nolo-cli 0.10.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-YAXYAUOK.js → _executeModel-MWAY74HA.js} +47 -44
- package/{action-TLI3V62L.js → action-RAXNQQKC.js} +9 -10
- package/{addContentAction-PLWJSCOZ.js → addContentAction-ZHI7TVV3.js} +8 -10
- package/{addDialogAgentAction-BJ6SB76X.js → addDialogAgentAction-JWXPKXNC.js} +7 -8
- package/{agentDeleteCommand-2VYX73U5.js → agentDeleteCommand-LXR5A5FV.js} +36 -26
- package/{agentEmailCommands-3GDZIX64.js → agentEmailCommands-DXRAP7BB.js} +63 -58
- package/{agentListCommands-UWVBT3LH.js → agentListCommands-ZFMS5ZLY.js} +132 -35
- package/{agentMachineCommands-WOKMUG2Y.js → agentMachineCommands-ZJLYVV52.js} +40 -29
- package/{agentPullCommand-O2MTUAFR.js → agentPullCommand-KRBRIFIY.js} +6 -6
- package/{agentRecordCommands-MVNZRH3U.js → agentRecordCommands-DFS626TB.js} +55 -50
- package/{agentRunCommand-K7THIJLA.js → agentRunCommand-GWBIE2TS.js} +60 -56
- package/{agentRunControl-K4VKNEHF.js → agentRunControl-IX4F5W2C.js} +3 -3
- package/{agentRuntimeLocal-WJIGU24U.js → agentRuntimeLocal-YNZSHMZC.js} +29 -14
- package/{agentSlice-LL5TKZEO.js → agentSlice-T2PXOEPQ.js} +9 -10
- package/{authCommand-TC2SW2CQ.js → authCommand-DMW336GT.js} +13 -13
- package/{authCommands-XPEHTKSM.js → authCommands-GH5T6RYV.js} +6 -6
- package/{chunk-5JGGZCZL.js → chunk-3HHTVM6G.js} +64 -5
- package/chunk-3QKO4EHV.js +112 -0
- package/{chunk-AUQ747NZ.js → chunk-43UD5ZP7.js} +76 -15
- package/{chunk-6SLCD4RB.js → chunk-4BTHUYMY.js} +596 -67
- package/{chunk-T7R3NGUU.js → chunk-4EH7AR52.js} +13 -13
- package/{chunk-C3RUNRHT.js → chunk-4GBNEA5B.js} +1 -1
- package/{chunk-4IJYA27C.js → chunk-4LG74DRG.js} +1 -1
- package/{chunk-2FTTDCD4.js → chunk-4ON5AV72.js} +2 -1
- package/{chunk-IWX4UW2E.js → chunk-524BDL33.js} +89 -8
- package/{chunk-EXXFGKF7.js → chunk-5ITRDSHY.js} +1400 -119
- package/{chunk-ISNCLGUZ.js → chunk-5NBHQD4D.js} +4 -3
- package/{chunk-7KNKFIRO.js → chunk-6LMFFG3K.js} +3 -3
- package/{chunk-PAKN26FP.js → chunk-6OVCRC72.js} +1 -1
- package/{chunk-CKOJQDKR.js → chunk-7JJCGV7N.js} +146 -3
- package/{chunk-KBKYAONQ.js → chunk-7MYHLZ3F.js} +2 -2
- package/{chunk-PIVFPOW6.js → chunk-AM53Q2SD.js} +175 -2541
- package/chunk-BYXBJQAS.js +0 -0
- package/{chunk-CL3IOKGK.js → chunk-DE5BA4O6.js} +20 -2
- package/{chunk-6KUOUWMP.js → chunk-DRMGJFGQ.js} +300 -89
- package/{chunk-QAALPJS7.js → chunk-EBH7G34M.js} +20 -7
- package/{chunk-HJGEVL7C.js → chunk-G3B356GF.js} +15 -17
- package/{chunk-OZMMKDBI.js → chunk-GDBCUWQ3.js} +26 -20
- package/{chunk-I5URP43I.js → chunk-GPZM7QH6.js} +9 -9
- package/chunk-IKXL2HZ3.js +70 -0
- package/{chunk-AS4PVWA4.js → chunk-IVAOVLM7.js} +1 -1
- package/{chunk-TNPIMII7.js → chunk-JUN3HFMN.js} +221 -81
- package/{chunk-HFASY3WO.js → chunk-JZDIW766.js} +1 -1
- package/{chunk-6JJWFVZ6.js → chunk-LHSJMY5V.js} +17 -17
- package/chunk-LTRXGFMS.js +83 -0
- package/{chunk-YIHFXH5Q.js → chunk-MEVCDATU.js} +3 -3
- package/{chunk-TILFE6LV.js → chunk-NCGFB7NN.js} +5 -3
- package/{chunk-BE2OOJ5P.js → chunk-NITP2JDG.js} +42 -11
- package/{chunk-YPRZSPF3.js → chunk-OCDEWRE2.js} +1 -1
- package/{chunk-VVX233PH.js → chunk-OHEKYYJF.js} +9 -9
- package/chunk-OOIN7HSO.js +146 -0
- package/{chunk-WPE4F4Z6.js → chunk-OPKKB25T.js} +1 -1
- package/{chunk-OR2XR25C.js → chunk-QCA3EPYK.js} +8 -8
- package/{chunk-SL35K7AH.js → chunk-QLUFR47U.js} +13 -83
- package/{chunk-CDTLMEB3.js → chunk-RNQ5BLR2.js} +1 -1
- package/{chunk-AVMKZHBC.js → chunk-RSEUHW6T.js} +3 -2
- package/{chunk-TYSCFY6S.js → chunk-RZ735TLX.js} +762 -167
- package/chunk-S3UTETIC.js +4885 -0
- package/chunk-S73OEOHH.js +2286 -0
- package/{chunk-JRKKFRAV.js → chunk-TSKWE74T.js} +58 -8
- package/{chunk-A67QFHAA.js → chunk-UG3WOFU6.js} +1 -1
- package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
- package/chunk-VC6OZXO5.js +298 -0
- package/{chunk-7U44LYTR.js → chunk-WPHL6ALY.js} +1 -1
- package/{chunk-4SIMLBEU.js → chunk-WTYKCU4W.js} +9 -9
- package/{chunk-NPVBXJY2.js → chunk-WWU275LU.js} +9 -9
- package/{chunk-ZQ2UM4KG.js → chunk-WZSRQNQG.js} +1 -292
- package/{chunk-DSZUWUYB.js → chunk-XHQWJUW4.js} +2 -2
- package/{chunk-GAKEBQD6.js → chunk-YDCZVUFP.js} +4 -0
- package/{chunk-2O4IZNTG.js → chunk-YTQLJYLB.js} +2 -2
- package/{chunk-3Y3HW5PX.js → chunk-ZPFRLGIZ.js} +1512 -935
- package/{chunk-5KLGBAAR.js → chunk-ZR4VHQ5D.js} +14 -13
- package/cliEnvHelpers-VYC2OPTB.js +30 -0
- package/{cliExecutor-DNE7TCC4.js → cliExecutor-K3F7DMRO.js} +2 -2
- package/{createAgentAutomationAction-CCE7CWGQ.js → createAgentAutomationAction-G32GKDGV.js} +22 -23
- package/{createDialogAction-QTRR4AT7.js → createDialogAction-TISANRZK.js} +25 -25
- package/{createPageAction-Y4KQOAJE.js → createPageAction-O7KOYNV4.js} +27 -27
- package/{dbSlice-WWNV2SGX.js → dbSlice-WDP2ZZHK.js} +7 -8
- package/{deleteFile-OW53A6BX.js → deleteFile-M7UNIUOO.js} +5 -5
- package/{dialogCommands-SMKIAC3Y.js → dialogCommands-6JPB3YQY.js} +33 -23
- package/{dialogSlice-PT7YBWNE.js → dialogSlice-PRHHYSP5.js} +21 -22
- package/{docCreateCommands-RFNA4HNM.js → docCreateCommands-75E6TZNN.js} +36 -25
- package/{docDeleteCommands-4YZ325M6.js → docDeleteCommands-EJHLN7LW.js} +37 -27
- package/{docReadCommands-RT6VAFFG.js → docReadCommands-RJYBC4FS.js} +36 -25
- package/{docStore-QUQZAFZF.js → docStore-H5VWKT5D.js} +22 -23
- package/{docUpdateCommands-EKKKNYPW.js → docUpdateCommands-MG4CNISV.js} +36 -25
- package/fetchMessages-KTNM7QAR.js +1 -1
- package/{getPricing-3E6UNPKL.js → getPricing-6TOZXPAU.js} +7 -3
- package/{handleSendMessageAction-5NSYAS53.js → handleSendMessageAction-QTUGICSZ.js} +22 -23
- package/index.js +77 -76
- package/{machineCommands-DOOSIUKG.js → machineCommands-MAV7M3TK.js} +67 -60
- package/{machineWsRunDispatch-PIOIQRBW.js → machineWsRunDispatch-ZOEGTKHC.js} +54 -49
- 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-GW7ZEI23.js → read-2MIMRBZ2.js} +5 -5
- package/{readDocTool-HUFU6OCT.js → readDocTool-QHVGQHUJ.js} +1 -1
- package/{readlineWorkspace-QEAOH5EP.js → readlineWorkspace-SWQKC7ZS.js} +1126 -678
- package/{removeDialogAgentAction-OHMCNSSD.js → removeDialogAgentAction-GTX5AN54.js} +11 -11
- package/{runAgentClientLoop-AIGLXC3R.js → runAgentClientLoop-P25HACXX.js} +42 -40
- package/{runtimeDoctorCommands-LRHLPDRC.js → runtimeDoctorCommands-QNF3J3UV.js} +6 -6
- package/{setDialogExtraReferencesAction-YJUM5BWQ.js → setDialogExtraReferencesAction-WFQ63KYO.js} +7 -8
- package/{setPrimaryDialogAgentAction-EBAREZDM.js → setPrimaryDialogAgentAction-P57FXTSU.js} +11 -11
- package/{settingSlice-UW4IUI5L.js → settingSlice-CK5YZGNI.js} +8 -9
- package/skillDiscovery-ZYHSX7VD.js +16 -0
- package/{spaceCommands-BKHSPR73.js → spaceCommands-6O5EFEM5.js} +41 -33
- package/{spaceSlice-TYNWE3OC.js → spaceSlice-4EXTYXS4.js} +25 -24
- package/{streamAgentChatTurn-HRMFFA7E.js → streamAgentChatTurn-Q3FJAHG2.js} +205 -107
- package/{tableCommands-O7O2LBEG.js → tableCommands-E4SQWDOX.js} +10 -10
- package/{tools-3JNDS3WH.js → tools-AHNQE4GP.js} +33 -31
- package/{tuiSummaryLlmCaller-RV3THLZF.js → tuiSummaryLlmCaller-TXLF4MEI.js} +8 -6
- package/{updateCommands-VOSPKXFF.js → updateCommands-XZDOOYFH.js} +13 -5
- package/{updateDialogTitleAction-OCETSKCP.js → updateDialogTitleAction-XZDVLKVX.js} +25 -25
- 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-DZ3XJVET.js → chunk-3QAF2LTL.js} +3 -3
- package/{chunk-X7W4TNB4.js → chunk-CMKUBIGW.js} +3 -3
- package/{chunk-4CQLVGRV.js → chunk-ID4G2MAR.js} +3 -3
- package/{chunk-5CS33IBL.js → chunk-PDL2AV3E.js} +3 -3
- package/{chunk-EHLHSX7R.js → chunk-TOILAPLH.js} +3 -3
- package/{chunk-UTLZINAP.js → chunk-TSUJOM6N.js} +10 -10
- package/{offlineMarxistsAgentCommand-BCPJITJL.js → offlineMarxistsAgentCommand-5OOWZLJI.js} +3 -3
|
@@ -3,198 +3,315 @@ 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
|
-
buildSkillDiscoveryContextBlock,
|
|
13
17
|
classifyCliAutoRoute,
|
|
18
|
+
clearCollapsedPasteStore,
|
|
19
|
+
countPhysicalLines,
|
|
20
|
+
createCollapsedPasteStore,
|
|
14
21
|
dimCliText,
|
|
22
|
+
displayWidth,
|
|
23
|
+
expandRangeToCollapsedPasteChips,
|
|
24
|
+
findCollapsedPasteSpanAt,
|
|
25
|
+
fitAnsiLine,
|
|
15
26
|
formatAssistantDisplay,
|
|
16
27
|
formatTokenCount,
|
|
17
28
|
getActiveBrightness,
|
|
18
29
|
getActiveDensity,
|
|
19
30
|
getActiveThemeName,
|
|
20
|
-
getCliLocale,
|
|
21
|
-
highlightMarkdown,
|
|
22
|
-
initCliLocale,
|
|
23
31
|
isBalanceExhaustedError,
|
|
24
32
|
isQuotaExhaustedError,
|
|
25
33
|
normalizeThinkingDisplayMode,
|
|
26
34
|
normalizeToolDisplayMode,
|
|
27
|
-
|
|
35
|
+
padOrTruncateToWidth,
|
|
36
|
+
releaseCollapsedPaste,
|
|
37
|
+
releaseCollapsedPasteReferences,
|
|
28
38
|
renderTokenStatus,
|
|
39
|
+
replaceCollapsedPastesWithReferences,
|
|
40
|
+
resolveAgentContextWindow,
|
|
41
|
+
resolveCliAutoFallbackTier,
|
|
29
42
|
resolveCliColorEnabled,
|
|
30
43
|
resolveSkillReference,
|
|
31
44
|
resolveTuiBrightness,
|
|
32
45
|
runAgentTurn,
|
|
33
46
|
setActiveBrightness,
|
|
34
47
|
setActiveDensity,
|
|
48
|
+
setActiveTerminalBaseHex,
|
|
35
49
|
setActiveThemeName,
|
|
36
|
-
|
|
50
|
+
shouldCollapsePaste,
|
|
51
|
+
stripAnsi,
|
|
37
52
|
surfaceBackgroundSequence,
|
|
38
|
-
|
|
53
|
+
takeDisplayWidth,
|
|
39
54
|
themeColorSequence,
|
|
40
|
-
themeText
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
themeText,
|
|
56
|
+
truncateAnsi,
|
|
57
|
+
visibleWidth,
|
|
58
|
+
wrapTextToLines,
|
|
59
|
+
wrapTranscriptLine
|
|
60
|
+
} from "./chunk-ZPFRLGIZ.js";
|
|
61
|
+
import "./chunk-3QAF2LTL.js";
|
|
62
|
+
import "./chunk-6HYVJV7B.js";
|
|
43
63
|
import {
|
|
44
64
|
listFavoriteAgentIdsAcrossServers,
|
|
45
65
|
listLocalCachedAgents,
|
|
46
66
|
listRemoteAgents,
|
|
47
67
|
listRemoteAgentsAcrossServers
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-DZ3XJVET.js";
|
|
51
|
-
import "./chunk-EXXFGKF7.js";
|
|
52
|
-
import "./chunk-EHLHSX7R.js";
|
|
68
|
+
} from "./chunk-DE5BA4O6.js";
|
|
69
|
+
import "./chunk-ID4G2MAR.js";
|
|
53
70
|
import {
|
|
54
71
|
listUserRecordsFromServers
|
|
55
|
-
} from "./chunk-
|
|
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";
|
|
81
|
+
import "./chunk-CMKUBIGW.js";
|
|
82
|
+
import "./chunk-JBTJAPUF.js";
|
|
56
83
|
import {
|
|
57
84
|
getReadableCliDb
|
|
58
85
|
} from "./chunk-W4NVOSFF.js";
|
|
59
86
|
import {
|
|
60
87
|
queryUserRecords,
|
|
61
88
|
readDbRecord
|
|
62
|
-
} from "./chunk-
|
|
63
|
-
import "./chunk-
|
|
89
|
+
} from "./chunk-QCA3EPYK.js";
|
|
90
|
+
import "./chunk-RNQ5BLR2.js";
|
|
64
91
|
import {
|
|
65
92
|
resolveCliAgentKeyInput
|
|
66
93
|
} from "./chunk-VHBWHNVT.js";
|
|
67
|
-
import "./chunk-
|
|
68
|
-
import "./chunk-
|
|
69
|
-
import "./chunk-X7W4TNB4.js";
|
|
94
|
+
import "./chunk-LTRXGFMS.js";
|
|
95
|
+
import "./chunk-UG3WOFU6.js";
|
|
70
96
|
import "./chunk-ATNTHIZI.js";
|
|
71
|
-
import "./chunk-6HYVJV7B.js";
|
|
72
|
-
import "./chunk-JBTJAPUF.js";
|
|
73
97
|
import "./chunk-JEXVIMYZ.js";
|
|
74
|
-
import
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
import "./chunk-
|
|
78
|
-
import
|
|
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";
|
|
79
107
|
import "./chunk-KQHGZWSV.js";
|
|
80
|
-
import "./chunk-
|
|
108
|
+
import "./chunk-IVAOVLM7.js";
|
|
81
109
|
import "./chunk-3LY4F7SV.js";
|
|
82
110
|
import "./chunk-VP4WJWKW.js";
|
|
83
111
|
import "./chunk-63W5N6P3.js";
|
|
84
|
-
import "./chunk-
|
|
85
|
-
import "./chunk-
|
|
86
|
-
import "./chunk-
|
|
112
|
+
import "./chunk-VF4K2QE6.js";
|
|
113
|
+
import "./chunk-MEVCDATU.js";
|
|
114
|
+
import "./chunk-G3B356GF.js";
|
|
115
|
+
import "./chunk-VC6OZXO5.js";
|
|
87
116
|
import "./chunk-OWOHNGCN.js";
|
|
88
|
-
import "./chunk-HNW7IJSK.js";
|
|
89
|
-
import "./chunk-XENYHRUE.js";
|
|
90
117
|
import {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
getModelContextWindow,
|
|
94
|
-
planCompression,
|
|
95
|
-
serializeMessageContent
|
|
96
|
-
} from "./chunk-PIVFPOW6.js";
|
|
118
|
+
extractReferenceKeysFromMessage
|
|
119
|
+
} from "./chunk-AM53Q2SD.js";
|
|
97
120
|
import {
|
|
98
121
|
buildBuiltinSummaryContent
|
|
99
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-V2J635L5.js";
|
|
100
123
|
import "./chunk-MRC4Q34M.js";
|
|
101
124
|
import "./chunk-MTU75CZ2.js";
|
|
102
125
|
import "./chunk-CWMSB67P.js";
|
|
103
|
-
import "./chunk-
|
|
104
|
-
import "./chunk-
|
|
126
|
+
import "./chunk-GPZM7QH6.js";
|
|
127
|
+
import "./chunk-6LMFFG3K.js";
|
|
105
128
|
import "./chunk-Z4NR32XR.js";
|
|
106
129
|
import "./chunk-M76ECQRD.js";
|
|
107
|
-
import "./chunk-SOTZ6RDN.js";
|
|
108
|
-
import "./chunk-5JGGZCZL.js";
|
|
109
|
-
import "./chunk-UAD2WT54.js";
|
|
110
|
-
import "./chunk-DCOA4QSN.js";
|
|
111
|
-
import {
|
|
112
|
-
runSelfUpdate
|
|
113
|
-
} from "./chunk-CKOJQDKR.js";
|
|
114
|
-
import {
|
|
115
|
-
saveProfileAgentSelection,
|
|
116
|
-
saveProfileLocale
|
|
117
|
-
} from "./chunk-ROWQEJRP.js";
|
|
118
|
-
import {
|
|
119
|
-
readPipeText,
|
|
120
|
-
spawnProcess
|
|
121
|
-
} from "./chunk-IDZTNRP2.js";
|
|
122
130
|
import {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
resolveServerUrl
|
|
127
|
-
} from "./chunk-ISNCLGUZ.js";
|
|
128
|
-
import {
|
|
129
|
-
DEFAULT_NOLO_SERVER_URL
|
|
130
|
-
} from "./chunk-OLZBQWZU.js";
|
|
131
|
+
buildSkillDiscoveryContextBlock
|
|
132
|
+
} from "./chunk-3QKO4EHV.js";
|
|
133
|
+
import "./chunk-WZSRQNQG.js";
|
|
131
134
|
import {
|
|
135
|
+
buildLocalWorkspaceOpenAiTools,
|
|
136
|
+
buildLocalWorkspaceToolset,
|
|
132
137
|
getProcessRegistry
|
|
133
|
-
} from "./chunk-
|
|
134
|
-
import "./chunk-5KLGBAAR.js";
|
|
138
|
+
} from "./chunk-DRMGJFGQ.js";
|
|
135
139
|
import "./chunk-ZNFJWEN4.js";
|
|
136
|
-
import "./chunk-
|
|
140
|
+
import "./chunk-ZR4VHQ5D.js";
|
|
141
|
+
import "./chunk-NCGFB7NN.js";
|
|
137
142
|
import {
|
|
138
143
|
readCommandActionGatePayload,
|
|
139
144
|
resolveAgentImageInputSupport
|
|
140
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-4BTHUYMY.js";
|
|
141
146
|
import "./chunk-OPZYGHUC.js";
|
|
142
|
-
import "./chunk-PAKN26FP.js";
|
|
143
|
-
import "./chunk-JRKKFRAV.js";
|
|
144
|
-
import "./chunk-AUQ747NZ.js";
|
|
145
147
|
import {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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";
|
|
150
166
|
import "./chunk-JZPBVBIY.js";
|
|
151
|
-
import "./chunk-
|
|
167
|
+
import "./chunk-BYXBJQAS.js";
|
|
168
|
+
import "./chunk-QLUFR47U.js";
|
|
169
|
+
import "./chunk-KKY4B2Q2.js";
|
|
152
170
|
import "./chunk-5MIDPSSK.js";
|
|
153
171
|
import {
|
|
154
172
|
extractCustomId
|
|
155
173
|
} from "./chunk-DFFIZ25G.js";
|
|
156
174
|
import "./chunk-3ASDTTEI.js";
|
|
157
|
-
import
|
|
158
|
-
compactWhitespace
|
|
159
|
-
} from "./chunk-DWLEOOGR.js";
|
|
175
|
+
import "./chunk-4ON5AV72.js";
|
|
160
176
|
import {
|
|
161
177
|
toErrorMessage
|
|
162
178
|
} from "./chunk-HNMXYYJR.js";
|
|
163
179
|
import "./chunk-H33743XH.js";
|
|
164
180
|
import "./chunk-LM6IYQ3F.js";
|
|
165
|
-
import "./chunk-
|
|
166
|
-
import "./chunk-
|
|
181
|
+
import "./chunk-SOTZ6RDN.js";
|
|
182
|
+
import "./chunk-HNW7IJSK.js";
|
|
183
|
+
import "./chunk-XENYHRUE.js";
|
|
184
|
+
import {
|
|
185
|
+
compactWhitespace
|
|
186
|
+
} from "./chunk-DWLEOOGR.js";
|
|
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";
|
|
167
202
|
import "./chunk-Y5GCAMGP.js";
|
|
168
|
-
import "./chunk-BE2OOJ5P.js";
|
|
169
|
-
import "./chunk-AZPCASRE.js";
|
|
170
|
-
import "./chunk-7U44LYTR.js";
|
|
171
203
|
import "./chunk-KX6YBIHG.js";
|
|
204
|
+
import "./chunk-3HHTVM6G.js";
|
|
205
|
+
import "./chunk-NITP2JDG.js";
|
|
206
|
+
import "./chunk-WPHL6ALY.js";
|
|
172
207
|
import "./chunk-O4BU24WZ.js";
|
|
173
208
|
import "./chunk-I42VC5KR.js";
|
|
174
209
|
import "./chunk-WWC7I6TA.js";
|
|
175
210
|
import {
|
|
176
211
|
asTrimmedLowercaseString
|
|
177
212
|
} from "./chunk-QSJ3HFEF.js";
|
|
178
|
-
import "./chunk-
|
|
179
|
-
import "./chunk-
|
|
213
|
+
import "./chunk-XHQWJUW4.js";
|
|
214
|
+
import "./chunk-TSUJOM6N.js";
|
|
180
215
|
import "./chunk-OOSFSFMA.js";
|
|
181
216
|
import "./chunk-GBRG75BQ.js";
|
|
182
|
-
import "./chunk-
|
|
183
|
-
import "./chunk-LCBAMY2M.js";
|
|
217
|
+
import "./chunk-KUG52IAP.js";
|
|
184
218
|
import "./chunk-3EUW3WEO.js";
|
|
185
219
|
import "./chunk-U6VC4MU4.js";
|
|
220
|
+
import {
|
|
221
|
+
parseUserIdFromAuthToken,
|
|
222
|
+
resolveAuthToken,
|
|
223
|
+
resolveServerCandidates,
|
|
224
|
+
resolveServerUrl
|
|
225
|
+
} from "./chunk-5NBHQD4D.js";
|
|
226
|
+
import {
|
|
227
|
+
DEFAULT_NOLO_SERVER_URL
|
|
228
|
+
} from "./chunk-OLZBQWZU.js";
|
|
229
|
+
import "./chunk-LCBAMY2M.js";
|
|
230
|
+
import "./chunk-4SN6J65J.js";
|
|
186
231
|
import "./chunk-CF7PE763.js";
|
|
187
232
|
import {
|
|
188
233
|
asOptionalTrimmedString
|
|
189
234
|
} from "./chunk-G3SUCT4W.js";
|
|
190
|
-
import "./chunk-KUG52IAP.js";
|
|
191
235
|
import "./chunk-4VNS5WPM.js";
|
|
192
236
|
|
|
193
237
|
// packages/cli/tui/readlineWorkspace.ts
|
|
194
238
|
import { createInterface } from "node:readline";
|
|
195
239
|
import { stdin as defaultInput, stdout as defaultOutput } from "node:process";
|
|
196
|
-
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";
|
|
197
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
|
+
}
|
|
198
315
|
|
|
199
316
|
// packages/cli/client/compactDialog.ts
|
|
200
317
|
import { ulid } from "ulid";
|
|
@@ -475,6 +592,12 @@ function renderDialogRow(args, colorEnabled = resolveCliColorEnabled()) {
|
|
|
475
592
|
function renderDialogOverflow(text, colorEnabled = resolveCliColorEnabled()) {
|
|
476
593
|
return themeText(` ${text}`, "chrome", colorEnabled);
|
|
477
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
|
+
}
|
|
478
601
|
function renderDialogCommand(text, colorEnabled = resolveCliColorEnabled()) {
|
|
479
602
|
return themeText(` ${text}`, "danger", colorEnabled);
|
|
480
603
|
}
|
|
@@ -573,7 +696,7 @@ function renderSelectDialog(args) {
|
|
|
573
696
|
];
|
|
574
697
|
const lines = [...titleLines, ""];
|
|
575
698
|
if (window.start > 0) {
|
|
576
|
-
lines.push(
|
|
699
|
+
lines.push(renderOverflowAbove(window.start));
|
|
577
700
|
}
|
|
578
701
|
for (let index = window.start; index < window.end; index += 1) {
|
|
579
702
|
const item = args.items[index];
|
|
@@ -586,7 +709,7 @@ function renderSelectDialog(args) {
|
|
|
586
709
|
);
|
|
587
710
|
}
|
|
588
711
|
if (window.end < total) {
|
|
589
|
-
lines.push("",
|
|
712
|
+
lines.push("", renderOverflowBelow(total - window.end));
|
|
590
713
|
}
|
|
591
714
|
return lines.join("\n");
|
|
592
715
|
}
|
|
@@ -815,7 +938,7 @@ async function runSelectDialog(args) {
|
|
|
815
938
|
// packages/cli/tui/confirmDialog.ts
|
|
816
939
|
var FALLBACK_TERMINAL_WIDTH = 80;
|
|
817
940
|
var WIDE_CHAR = /[ᄀ-ᅟ⺀-〾ぁ-㏿㐀-䶿一-鿿ꀀ-가-힣豈-︰--⦆¢-₩]/;
|
|
818
|
-
function
|
|
941
|
+
function displayWidth2(text) {
|
|
819
942
|
let width = 0;
|
|
820
943
|
for (const char of text) width += WIDE_CHAR.test(char) ? 2 : 1;
|
|
821
944
|
return width;
|
|
@@ -823,9 +946,9 @@ function displayWidth(text) {
|
|
|
823
946
|
function truncateCommand(command, maxWidth) {
|
|
824
947
|
const indent = 2;
|
|
825
948
|
const budget = Math.max(10, maxWidth - indent);
|
|
826
|
-
if (
|
|
949
|
+
if (displayWidth2(command) <= budget) return command;
|
|
827
950
|
const marker = ` ${t("dialogConfirmCommandTruncated")}`;
|
|
828
|
-
const keep = Math.max(1, budget -
|
|
951
|
+
const keep = Math.max(1, budget - displayWidth2(marker));
|
|
829
952
|
let kept = "";
|
|
830
953
|
let width = 0;
|
|
831
954
|
for (const char of command) {
|
|
@@ -855,9 +978,15 @@ async function runConfirmDialog(args) {
|
|
|
855
978
|
value: false
|
|
856
979
|
}
|
|
857
980
|
];
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
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
|
+
}
|
|
861
990
|
const terminalWidth = typeof output.columns === "number" && output.columns > 0 ? output.columns : FALLBACK_TERMINAL_WIDTH;
|
|
862
991
|
const titleLines = [
|
|
863
992
|
renderDialogTitle(`${titleText} ${t("dialogConfirmHint")}`)
|
|
@@ -1107,19 +1236,23 @@ function renderTabBar(questions, activeIndex, colorEnabled) {
|
|
|
1107
1236
|
}
|
|
1108
1237
|
return colorEnabled ? themeText(` ${label} `, "muted", colorEnabled) : ` ${label} `;
|
|
1109
1238
|
});
|
|
1110
|
-
const submitLabel = "
|
|
1239
|
+
const submitLabel = t("askChoiceSubmit");
|
|
1111
1240
|
return tabs.join(" ") + " " + (colorEnabled ? themeText(submitLabel, "chrome", colorEnabled) : submitLabel);
|
|
1112
1241
|
}
|
|
1113
|
-
function renderFooter(colorEnabled) {
|
|
1114
|
-
const hints =
|
|
1242
|
+
function renderFooter(multiSelect, colorEnabled) {
|
|
1243
|
+
const hints = multiSelect ? t("askChoiceFooterMulti") : t("askChoiceFooterSingle");
|
|
1115
1244
|
return colorEnabled ? themeText(` ${hints}`, "chrome", colorEnabled) : ` ${hints}`;
|
|
1116
1245
|
}
|
|
1246
|
+
function otherRowPrefix(index) {
|
|
1247
|
+
return ` [${index + 1}] ${t("askChoiceOtherLabel")}: `;
|
|
1248
|
+
}
|
|
1117
1249
|
function renderAskChoiceFrame(state) {
|
|
1118
1250
|
const colorEnabled = resolveCliColorEnabled();
|
|
1119
1251
|
const q = state.questions[state.activeIndex];
|
|
1120
1252
|
const qs = state.questionStates[state.activeIndex];
|
|
1121
1253
|
const lines = [];
|
|
1122
|
-
|
|
1254
|
+
let otherCursor = null;
|
|
1255
|
+
lines.push(renderDialogTitle(t("askChoiceTitle")));
|
|
1123
1256
|
lines.push("");
|
|
1124
1257
|
if (state.questions.length > 1) {
|
|
1125
1258
|
lines.push(renderTabBar(state.questions, state.activeIndex, colorEnabled));
|
|
@@ -1130,11 +1263,11 @@ function renderAskChoiceFrame(state) {
|
|
|
1130
1263
|
);
|
|
1131
1264
|
if (q.multiSelect) {
|
|
1132
1265
|
lines.push(
|
|
1133
|
-
colorEnabled ? themeText(
|
|
1266
|
+
colorEnabled ? themeText(` ${t("askChoiceHintMulti")}`, "muted", colorEnabled) : ` ${t("askChoiceHintMulti")}`
|
|
1134
1267
|
);
|
|
1135
1268
|
} else {
|
|
1136
1269
|
lines.push(
|
|
1137
|
-
colorEnabled ? themeText(
|
|
1270
|
+
colorEnabled ? themeText(` ${t("askChoiceHintSingle")}`, "muted", colorEnabled) : ` ${t("askChoiceHintSingle")}`
|
|
1138
1271
|
);
|
|
1139
1272
|
}
|
|
1140
1273
|
lines.push("");
|
|
@@ -1144,9 +1277,7 @@ function renderAskChoiceFrame(state) {
|
|
|
1144
1277
|
total: totalRows
|
|
1145
1278
|
});
|
|
1146
1279
|
if (window.start > 0) {
|
|
1147
|
-
lines.push(
|
|
1148
|
-
colorEnabled ? themeText(` \u2191 ${window.start} more`, "chrome", colorEnabled) : ` \u2191 ${window.start} more`
|
|
1149
|
-
);
|
|
1280
|
+
lines.push(renderOverflowAbove(window.start));
|
|
1150
1281
|
}
|
|
1151
1282
|
for (let i = window.start; i < window.end; i++) {
|
|
1152
1283
|
if (i < q.choices.length) {
|
|
@@ -1164,25 +1295,29 @@ function renderAskChoiceFrame(state) {
|
|
|
1164
1295
|
} else {
|
|
1165
1296
|
const focused = qs.cursorIndex === i;
|
|
1166
1297
|
const marker = focused ? DIALOG_CURSOR : " ";
|
|
1167
|
-
const
|
|
1168
|
-
const
|
|
1298
|
+
const plainPrefix = `${marker}${otherRowPrefix(i)}`;
|
|
1299
|
+
const plainRow = `${plainPrefix}${qs.otherText}`;
|
|
1169
1300
|
if (focused && colorEnabled) {
|
|
1170
1301
|
lines.push(
|
|
1171
|
-
`\x1B[1m${themeColorSequence("accent")}${
|
|
1302
|
+
`\x1B[1m${themeColorSequence("accent")}${plainRow}\x1B[0m`
|
|
1172
1303
|
);
|
|
1173
1304
|
} else {
|
|
1174
|
-
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
|
+
};
|
|
1175
1312
|
}
|
|
1176
1313
|
}
|
|
1177
1314
|
}
|
|
1178
1315
|
if (window.end < totalRows) {
|
|
1179
|
-
lines.push(
|
|
1180
|
-
colorEnabled ? themeText(` \u2193 ${totalRows - window.end} more`, "chrome", colorEnabled) : ` \u2193 ${totalRows - window.end} more`
|
|
1181
|
-
);
|
|
1316
|
+
lines.push(renderOverflowBelow(totalRows - window.end));
|
|
1182
1317
|
}
|
|
1183
1318
|
lines.push("");
|
|
1184
|
-
lines.push(renderFooter(colorEnabled));
|
|
1185
|
-
return lines.join("\n");
|
|
1319
|
+
lines.push(renderFooter(q.multiSelect, colorEnabled));
|
|
1320
|
+
return { text: lines.join("\n"), otherCursor };
|
|
1186
1321
|
}
|
|
1187
1322
|
async function runAskChoiceDialog(args) {
|
|
1188
1323
|
const { request } = args;
|
|
@@ -1195,9 +1330,6 @@ async function runAskChoiceDialog(args) {
|
|
|
1195
1330
|
if (normalized.questions.length === 0) {
|
|
1196
1331
|
return { kind: "cancelled" };
|
|
1197
1332
|
}
|
|
1198
|
-
const q0 = normalized.questions[0];
|
|
1199
|
-
if (normalized.questions.length === 1 && !q0.multiSelect && !q0.allowOther) {
|
|
1200
|
-
}
|
|
1201
1333
|
let state = createInitialAskChoiceState(normalized.questions);
|
|
1202
1334
|
const output = args.output ?? process.stdout;
|
|
1203
1335
|
const input = args.input ?? process.stdin;
|
|
@@ -1211,9 +1343,15 @@ async function runAskChoiceDialog(args) {
|
|
|
1211
1343
|
typeof args.bottomRow === "function" ? args.bottomRow() : args.bottomRow ?? 0
|
|
1212
1344
|
);
|
|
1213
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
|
+
};
|
|
1214
1352
|
const paint = () => {
|
|
1215
1353
|
const frame = renderAskChoiceFrame(state);
|
|
1216
|
-
const lines = frame.split("\n");
|
|
1354
|
+
const lines = frame.text.split("\n");
|
|
1217
1355
|
const lineCount = lines.length;
|
|
1218
1356
|
const canPosition = outputIsTty(output) && typeof output.write === "function";
|
|
1219
1357
|
if (bottomAnchored && canPosition) {
|
|
@@ -1230,22 +1368,37 @@ async function runAskChoiceDialog(args) {
|
|
|
1230
1368
|
}
|
|
1231
1369
|
lastBottomRow = anchorRow;
|
|
1232
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
|
+
}
|
|
1233
1378
|
return;
|
|
1234
1379
|
}
|
|
1235
1380
|
if (canPosition) {
|
|
1381
|
+
restoreUnanchoredCursor();
|
|
1236
1382
|
for (let i = 0; i < renderedLineCount; i++) {
|
|
1237
1383
|
output.write("\x1B[1A\x1B[2K");
|
|
1238
1384
|
}
|
|
1239
|
-
output.write(`${frame}
|
|
1385
|
+
output.write(`${frame.text}
|
|
1240
1386
|
`);
|
|
1241
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
|
+
}
|
|
1242
1394
|
return;
|
|
1243
1395
|
}
|
|
1244
1396
|
if (typeof output.write === "function") {
|
|
1245
|
-
output.write(`${frame}
|
|
1397
|
+
output.write(`${frame.text}
|
|
1246
1398
|
`);
|
|
1247
1399
|
}
|
|
1248
1400
|
renderedLineCount = lineCount;
|
|
1401
|
+
unanchoredCursorLift = 0;
|
|
1249
1402
|
};
|
|
1250
1403
|
const resizeTarget = output;
|
|
1251
1404
|
const onOutputResize = () => paint();
|
|
@@ -1273,6 +1426,9 @@ async function runAskChoiceDialog(args) {
|
|
|
1273
1426
|
continue;
|
|
1274
1427
|
}
|
|
1275
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;
|
|
1276
1432
|
if (isCancel(sequence)) {
|
|
1277
1433
|
action = { type: "CANCEL" };
|
|
1278
1434
|
} else if (sequence === CSI_TAB) {
|
|
@@ -1284,11 +1440,17 @@ async function runAskChoiceDialog(args) {
|
|
|
1284
1440
|
} else if (isArrowDown(sequence)) {
|
|
1285
1441
|
action = { type: "MOVE_CURSOR", delta: 1 };
|
|
1286
1442
|
} else if (sequence === CSI_SPACE) {
|
|
1287
|
-
|
|
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
|
+
}
|
|
1288
1453
|
} else if (isSubmit(sequence)) {
|
|
1289
|
-
const qs = state.questionStates[state.activeIndex];
|
|
1290
|
-
const q = state.questions[state.activeIndex];
|
|
1291
|
-
const isOtherRow = qs.cursorIndex >= q.choices.length;
|
|
1292
1454
|
if (qs.otherFocused) {
|
|
1293
1455
|
action = { type: "BLUR_OTHER" };
|
|
1294
1456
|
} else if (isOtherRow && !qs.otherFocused) {
|
|
@@ -1299,24 +1461,29 @@ async function runAskChoiceDialog(args) {
|
|
|
1299
1461
|
action = { type: "SELECT_AT_CURSOR" };
|
|
1300
1462
|
}
|
|
1301
1463
|
} else if (sequence === CSI_BACKSPACE || sequence === CSI_BACKSPACE_ALT) {
|
|
1302
|
-
const qs = state.questionStates[state.activeIndex];
|
|
1303
1464
|
if (qs.otherFocused && qs.otherText.length > 0) {
|
|
1465
|
+
const chars = Array.from(qs.otherText);
|
|
1304
1466
|
action = {
|
|
1305
1467
|
type: "SET_OTHER_TEXT",
|
|
1306
|
-
text:
|
|
1468
|
+
text: chars.slice(0, -1).join("")
|
|
1307
1469
|
};
|
|
1308
1470
|
}
|
|
1309
|
-
} else if (sequence.length
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
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
|
+
}
|
|
1316
1484
|
}
|
|
1317
1485
|
}
|
|
1318
1486
|
if (action) {
|
|
1319
|
-
const prev = state;
|
|
1320
1487
|
state = askChoiceReducer(state, action);
|
|
1321
1488
|
if (state.phase !== "active") break;
|
|
1322
1489
|
if (action.type === "BLUR_OTHER" && state.activeIndex >= state.questions.length - 1 && canSubmit(state)) {
|
|
@@ -1340,6 +1507,7 @@ async function runAskChoiceDialog(args) {
|
|
|
1340
1507
|
renderedLineCount
|
|
1341
1508
|
);
|
|
1342
1509
|
} else {
|
|
1510
|
+
restoreUnanchoredCursor();
|
|
1343
1511
|
for (let i = 0; i < renderedLineCount; i++) {
|
|
1344
1512
|
output.write("\x1B[1A\x1B[2K");
|
|
1345
1513
|
}
|
|
@@ -1353,13 +1521,13 @@ async function runAskChoiceDialog(args) {
|
|
|
1353
1521
|
}
|
|
1354
1522
|
if (result.answers.length === 1) {
|
|
1355
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);
|
|
1356
1527
|
return {
|
|
1357
1528
|
kind: "selected",
|
|
1358
1529
|
userMessage: a.userMessage,
|
|
1359
|
-
label:
|
|
1360
|
-
const q = normalized.questions[0];
|
|
1361
|
-
return q.choices.find((c) => c.id === id)?.label ?? "";
|
|
1362
|
-
}).join(", ") || a.otherText || ""
|
|
1530
|
+
label: labels.join(", ") || a.otherText || ""
|
|
1363
1531
|
};
|
|
1364
1532
|
}
|
|
1365
1533
|
return {
|
|
@@ -1417,8 +1585,13 @@ function createActivityIndicator(deps) {
|
|
|
1417
1585
|
let lastActivityAt = 0;
|
|
1418
1586
|
let frameIndex = 0;
|
|
1419
1587
|
let timer = null;
|
|
1588
|
+
let stopping = false;
|
|
1420
1589
|
const elapsedSecFrom = (startedAt) => startedAt > 0 ? Math.max(0, Math.floor((now() - startedAt) / 1e3)) : 0;
|
|
1421
1590
|
const tick = () => {
|
|
1591
|
+
if (stopping) {
|
|
1592
|
+
deps.onRepaint();
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1422
1595
|
frameIndex += 1;
|
|
1423
1596
|
if (explicitLabel === null && !fallbackActive && deps.isTurnActive() && lastActivityAt > 0 && now() - lastActivityAt >= fallbackDelayMs) {
|
|
1424
1597
|
fallbackActive = true;
|
|
@@ -1447,9 +1620,21 @@ function createActivityIndicator(deps) {
|
|
|
1447
1620
|
ensureTimer();
|
|
1448
1621
|
deps.onRepaint();
|
|
1449
1622
|
};
|
|
1623
|
+
const markStopping = () => {
|
|
1624
|
+
stopping = true;
|
|
1625
|
+
deps.onRepaint();
|
|
1626
|
+
};
|
|
1627
|
+
const isStopping = () => stopping;
|
|
1450
1628
|
const getView = () => {
|
|
1451
1629
|
if (!deps.isTurnActive()) return null;
|
|
1452
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
|
+
}
|
|
1453
1638
|
if (explicitLabel !== null) {
|
|
1454
1639
|
return {
|
|
1455
1640
|
frame,
|
|
@@ -1476,8 +1661,9 @@ function createActivityIndicator(deps) {
|
|
|
1476
1661
|
fallbackActive = false;
|
|
1477
1662
|
fallbackStartedAt = 0;
|
|
1478
1663
|
lastActivityAt = 0;
|
|
1664
|
+
stopping = false;
|
|
1479
1665
|
};
|
|
1480
|
-
return { report, getView, stop };
|
|
1666
|
+
return { report, getView, markStopping, isStopping, stop };
|
|
1481
1667
|
}
|
|
1482
1668
|
|
|
1483
1669
|
// packages/ai/agent/utils/sortUtils.ts
|
|
@@ -1528,12 +1714,12 @@ function sortAgentsFavoriteOwnedPublic(items) {
|
|
|
1528
1714
|
// packages/cli/tui/agentCatalog.ts
|
|
1529
1715
|
var DEFAULT_TUI_AGENT_KEY = "agent-pub-01NOLOAPPBLD000000019KCKT0";
|
|
1530
1716
|
function formatAgentSourceLabel(entry) {
|
|
1531
|
-
if (entry.kind === "platform" || entry.apiSource === "platform") return "
|
|
1717
|
+
if (entry.kind === "platform" || entry.apiSource === "platform") return t("agentSourcePlatform");
|
|
1532
1718
|
if (entry.apiSource === "cli") {
|
|
1533
|
-
return entry.cliProvider ?
|
|
1719
|
+
return entry.cliProvider ? `${t("agentSourceSubscription")}(${entry.cliProvider})` : t("agentSourceSubscription");
|
|
1534
1720
|
}
|
|
1535
|
-
if (entry.apiSource === "custom") return "
|
|
1536
|
-
return "
|
|
1721
|
+
if (entry.apiSource === "custom") return t("agentSourceApi");
|
|
1722
|
+
return t("agentSourcePlatform");
|
|
1537
1723
|
}
|
|
1538
1724
|
var PLATFORM_AGENTS = [
|
|
1539
1725
|
{
|
|
@@ -1717,13 +1903,25 @@ function findAgentCatalogEntry(entries, rawTarget) {
|
|
|
1717
1903
|
if (!target) return null;
|
|
1718
1904
|
if (/^\d+$/.test(target)) {
|
|
1719
1905
|
const entry = entries[Number(target) - 1];
|
|
1720
|
-
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;
|
|
1721
1912
|
}
|
|
1722
1913
|
const lower = target.toLowerCase();
|
|
1723
1914
|
const byName = entries.find(
|
|
1724
1915
|
(entry) => entry.name.toLowerCase() === lower || entry.key.toLowerCase() === lower || entry.key.toLowerCase().endsWith(`-${lower}`)
|
|
1725
1916
|
);
|
|
1726
|
-
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
|
+
}
|
|
1727
1925
|
if (target.startsWith("agent-") || target.startsWith("agent-pub-")) {
|
|
1728
1926
|
return { name: target, key: target };
|
|
1729
1927
|
}
|
|
@@ -1782,6 +1980,8 @@ async function runAgentPicker(args) {
|
|
|
1782
1980
|
kind: "selected",
|
|
1783
1981
|
name: selected.name,
|
|
1784
1982
|
key: selected.key,
|
|
1983
|
+
model: selected.model,
|
|
1984
|
+
apiSource: selected.apiSource ?? (selected.kind === "platform" ? "platform" : void 0),
|
|
1785
1985
|
entries
|
|
1786
1986
|
};
|
|
1787
1987
|
}
|
|
@@ -1791,7 +1991,11 @@ function resolveAgentSwitchTarget(rawTarget, catalogEntries = []) {
|
|
|
1791
1991
|
const aliasEntry = catalogEntries.find((entry) => entry.key === resolvedKey);
|
|
1792
1992
|
return {
|
|
1793
1993
|
name: aliasEntry?.name ?? asTrimmedLowercaseString(rawTarget),
|
|
1794
|
-
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
|
+
} : {}
|
|
1795
1999
|
};
|
|
1796
2000
|
}
|
|
1797
2001
|
return findAgentCatalogEntry(catalogEntries, rawTarget);
|
|
@@ -1804,10 +2008,10 @@ function formatDialogTimestamp(value, now = Date.now()) {
|
|
|
1804
2008
|
const time = typeof value === "number" ? value : Date.parse(value);
|
|
1805
2009
|
if (!Number.isFinite(time) || time <= 0) return "";
|
|
1806
2010
|
const deltaSeconds = Math.max(0, Math.floor((now - time) / 1e3));
|
|
1807
|
-
if (deltaSeconds < 60) return "
|
|
1808
|
-
if (deltaSeconds < 3600) return
|
|
1809
|
-
if (deltaSeconds < 86400) return
|
|
1810
|
-
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)));
|
|
1811
2015
|
const date = new Date(time);
|
|
1812
2016
|
const pad = (part) => String(part).padStart(2, "0");
|
|
1813
2017
|
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
@@ -1824,7 +2028,7 @@ function toDialogPickerItems(dialogs) {
|
|
|
1824
2028
|
}
|
|
1825
2029
|
function renderDialogList(dialogs) {
|
|
1826
2030
|
if (dialogs.length === 0) return t("noDialogsYet");
|
|
1827
|
-
const lines = ["
|
|
2031
|
+
const lines = [t("recentDialogs")];
|
|
1828
2032
|
for (const [index, dialog] of dialogs.entries()) {
|
|
1829
2033
|
const stamp = formatDialogTimestamp(dialog.updatedAt ?? dialog.createdAt);
|
|
1830
2034
|
lines.push(
|
|
@@ -1832,7 +2036,7 @@ function renderDialogList(dialogs) {
|
|
|
1832
2036
|
` id=${dialog.id}`
|
|
1833
2037
|
);
|
|
1834
2038
|
}
|
|
1835
|
-
lines.push("", "
|
|
2039
|
+
lines.push("", t("dialogListTip"));
|
|
1836
2040
|
return lines.join("\n");
|
|
1837
2041
|
}
|
|
1838
2042
|
async function fetchRecentDialogs(args) {
|
|
@@ -1913,7 +2117,7 @@ async function runDialogPicker(args) {
|
|
|
1913
2117
|
}
|
|
1914
2118
|
|
|
1915
2119
|
// packages/cli/tui/pasteImage.ts
|
|
1916
|
-
import { existsSync } from "node:fs";
|
|
2120
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1917
2121
|
import { readFile, stat } from "node:fs/promises";
|
|
1918
2122
|
import { homedir } from "node:os";
|
|
1919
2123
|
import { isAbsolute, resolve } from "node:path";
|
|
@@ -1968,7 +2172,7 @@ function detectImagePaths(line, cwd) {
|
|
|
1968
2172
|
if (!token.raw) continue;
|
|
1969
2173
|
const resolved = resolveImageSource(token.decoded, cwd);
|
|
1970
2174
|
if (!isImagePath(resolved)) continue;
|
|
1971
|
-
if (!
|
|
2175
|
+
if (!existsSync2(resolved)) continue;
|
|
1972
2176
|
out.push({ raw: token.raw, resolvedPath: resolved });
|
|
1973
2177
|
}
|
|
1974
2178
|
return out;
|
|
@@ -2151,302 +2355,48 @@ async function readImagePaths(paths, options = {}) {
|
|
|
2151
2355
|
}
|
|
2152
2356
|
|
|
2153
2357
|
// packages/cli/tui/gitStatus.ts
|
|
2154
|
-
import { execSync } from "node:child_process";
|
|
2155
|
-
function
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
return { branch, modified, untracked };
|
|
2182
|
-
} catch {
|
|
2183
|
-
return void 0;
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
|
-
// packages/cli/tui/tuiAnsi.ts
|
|
2188
|
-
var ANSI_ESCAPE_REGEX = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
2189
|
-
var OSC_HYPERLINK_REGEX = /\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)\x1b\]8;;(?:\x07|\x1b\\)|\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
|
|
2190
|
-
function stripAnsi(text) {
|
|
2191
|
-
return text.replace(OSC_HYPERLINK_REGEX, "").replace(ANSI_ESCAPE_REGEX, "");
|
|
2192
|
-
}
|
|
2193
|
-
var SGR_SEQUENCE_REGEX = /^\x1b\[[0-9;]*m/;
|
|
2194
|
-
var TRAILING_SGR_REGEX = /(?:\x1b\[[0-9;]*m)+$/;
|
|
2195
|
-
function applyTerminalOutputToText(existing, chunk) {
|
|
2196
|
-
if (!chunk) return existing;
|
|
2197
|
-
let text = existing;
|
|
2198
|
-
let index = 0;
|
|
2199
|
-
while (index < chunk.length) {
|
|
2200
|
-
if (chunk[index] === "\x1B") {
|
|
2201
|
-
const sgr = SGR_SEQUENCE_REGEX.exec(chunk.slice(index));
|
|
2202
|
-
if (sgr) {
|
|
2203
|
-
text += sgr[0];
|
|
2204
|
-
index += sgr[0].length;
|
|
2205
|
-
continue;
|
|
2206
|
-
}
|
|
2207
|
-
const osc = chunk.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
2208
|
-
if (osc) {
|
|
2209
|
-
index += osc[0].length;
|
|
2210
|
-
continue;
|
|
2211
|
-
}
|
|
2212
|
-
const csi = chunk.slice(index).match(/^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/);
|
|
2213
|
-
if (csi) {
|
|
2214
|
-
index += csi[0].length;
|
|
2215
|
-
continue;
|
|
2216
|
-
}
|
|
2217
|
-
index += 1;
|
|
2218
|
-
continue;
|
|
2219
|
-
}
|
|
2220
|
-
const ch = chunk[index];
|
|
2221
|
-
if (ch === "\r") {
|
|
2222
|
-
const lastNl = text.lastIndexOf("\n");
|
|
2223
|
-
text = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
|
|
2224
|
-
index += 1;
|
|
2225
|
-
continue;
|
|
2226
|
-
}
|
|
2227
|
-
if (ch === "\n") {
|
|
2228
|
-
text += "\n";
|
|
2229
|
-
index += 1;
|
|
2230
|
-
continue;
|
|
2231
|
-
}
|
|
2232
|
-
if (ch === "\b") {
|
|
2233
|
-
const trailing = TRAILING_SGR_REGEX.exec(text);
|
|
2234
|
-
const sgrTail = trailing ? trailing[0] : "";
|
|
2235
|
-
const head = sgrTail ? text.slice(0, -sgrTail.length) : text;
|
|
2236
|
-
if (head.length > 0 && head[head.length - 1] !== "\n") {
|
|
2237
|
-
text = head.slice(0, -1) + sgrTail;
|
|
2238
|
-
}
|
|
2239
|
-
index += 1;
|
|
2240
|
-
continue;
|
|
2241
|
-
}
|
|
2242
|
-
const code = ch.charCodeAt(0);
|
|
2243
|
-
if (code < 32 && ch !== " " || code === 127) {
|
|
2244
|
-
index += 1;
|
|
2245
|
-
continue;
|
|
2246
|
-
}
|
|
2247
|
-
text += ch;
|
|
2248
|
-
index += 1;
|
|
2249
|
-
}
|
|
2250
|
-
return text;
|
|
2251
|
-
}
|
|
2252
|
-
function displayWidth2(str) {
|
|
2253
|
-
let width = 0;
|
|
2254
|
-
for (const char of str) {
|
|
2255
|
-
const code = char.codePointAt(0) ?? 0;
|
|
2256
|
-
if (code < 32 || code === 127) continue;
|
|
2257
|
-
if (code >= 4352 && code <= 4447 || // 0x2768-0x2775 (ornamental brackets, incl. the ❯ prompt at U+276F)
|
|
2258
|
-
// render narrow in terminals; counting them wide drifts the cursor.
|
|
2259
|
-
code >= 9728 && code <= 10175 && !(code >= 10088 && code <= 10101) || // 0x2B00-0x2BFF (Misc Symbols and Arrows, incl. ⬢ U+2B22 used as the
|
|
2260
|
-
// status-line agent icon) render double-wide in common monospace fonts;
|
|
2261
|
-
// counting ⬢ as width 1 drifts the whole status line right of the icon.
|
|
2262
|
-
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 ‘ ’).
|
|
2263
|
-
// In CJK locale + CJK fonts these render double-wide like 全角 punctuation;
|
|
2264
|
-
// in English fonts they stay width 1. Follow the active locale so Chinese
|
|
2265
|
-
// replies align correctly without breaking English terminal output.
|
|
2266
|
-
getCliLocale() === "zh" && (code === 8220 || code === 8221 || code === 8216 || code === 8217)) {
|
|
2267
|
-
width += 2;
|
|
2268
|
-
} else {
|
|
2269
|
-
width += 1;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
return width;
|
|
2273
|
-
}
|
|
2274
|
-
function visibleWidth(str) {
|
|
2275
|
-
return displayWidth2(stripAnsi(str));
|
|
2276
|
-
}
|
|
2277
|
-
function truncateAnsi(text, maxWidth) {
|
|
2278
|
-
if (maxWidth <= 0) return "";
|
|
2279
|
-
if (visibleWidth(text) <= maxWidth) return text;
|
|
2280
|
-
let width = 0;
|
|
2281
|
-
let out = "";
|
|
2282
|
-
let i = 0;
|
|
2283
|
-
let sawAnsi = false;
|
|
2284
|
-
while (i < text.length) {
|
|
2285
|
-
if (text[i] === "\x1B" && text[i + 1] === "[") {
|
|
2286
|
-
sawAnsi = true;
|
|
2287
|
-
let j = i + 2;
|
|
2288
|
-
while (j < text.length) {
|
|
2289
|
-
const code = text.charCodeAt(j);
|
|
2290
|
-
j += 1;
|
|
2291
|
-
if (code >= 64 && code <= 126) break;
|
|
2292
|
-
}
|
|
2293
|
-
out += text.slice(i, j);
|
|
2294
|
-
i = j;
|
|
2295
|
-
continue;
|
|
2296
|
-
}
|
|
2297
|
-
const codePoint = text.codePointAt(i) ?? 0;
|
|
2298
|
-
const char = String.fromCodePoint(codePoint);
|
|
2299
|
-
const charWidth = displayWidth2(char);
|
|
2300
|
-
if (width + charWidth > maxWidth) break;
|
|
2301
|
-
out += char;
|
|
2302
|
-
width += charWidth;
|
|
2303
|
-
i += char.length;
|
|
2304
|
-
}
|
|
2305
|
-
return sawAnsi ? `${out}\x1B[0m` : out;
|
|
2306
|
-
}
|
|
2307
|
-
function fitAnsiLine(text, width, ellipsis = "\u2026") {
|
|
2308
|
-
if (width <= 0) return "";
|
|
2309
|
-
if (visibleWidth(text) <= width) return text;
|
|
2310
|
-
const ellipsisWidth = displayWidth2(ellipsis);
|
|
2311
|
-
if (width < ellipsisWidth) return truncateAnsi(text, width);
|
|
2312
|
-
if (width === ellipsisWidth) return truncateAnsi(ellipsis, width) || truncateAnsi(text, width);
|
|
2313
|
-
return `${truncateAnsi(text, width - ellipsisWidth)}${ellipsis}`;
|
|
2314
|
-
}
|
|
2315
|
-
function countPhysicalLines(text, columns) {
|
|
2316
|
-
const lines = text.split("\n");
|
|
2317
|
-
let total = 0;
|
|
2318
|
-
for (const line of lines) {
|
|
2319
|
-
const width = displayWidth2(line);
|
|
2320
|
-
total += Math.max(1, Math.ceil(width / columns));
|
|
2321
|
-
}
|
|
2322
|
-
return Math.max(total, 1);
|
|
2323
|
-
}
|
|
2324
|
-
function takeDisplayWidth(text, width) {
|
|
2325
|
-
let used = 0;
|
|
2326
|
-
let index = 0;
|
|
2327
|
-
for (const char of text) {
|
|
2328
|
-
const charWidth = displayWidth2(char);
|
|
2329
|
-
if (used + charWidth > width && used > 0) break;
|
|
2330
|
-
used += charWidth;
|
|
2331
|
-
index += char.length;
|
|
2332
|
-
}
|
|
2333
|
-
return { prefix: text.slice(0, index), rest: text.slice(index) };
|
|
2334
|
-
}
|
|
2335
|
-
function padOrTruncateToWidth(text, width) {
|
|
2336
|
-
const textWidth = visibleWidth(text);
|
|
2337
|
-
if (textWidth > width) {
|
|
2338
|
-
return truncateAnsi(text, width);
|
|
2339
|
-
}
|
|
2340
|
-
return `${text}${" ".repeat(width - textWidth)}`;
|
|
2341
|
-
}
|
|
2342
|
-
var SGR_RESET_REGEX = /^\x1b\[0?m$/;
|
|
2343
|
-
function tokenizeAnsiLine(line) {
|
|
2344
|
-
const tokens = [];
|
|
2345
|
-
let index = 0;
|
|
2346
|
-
while (index < line.length) {
|
|
2347
|
-
if (line[index] === "\x1B") {
|
|
2348
|
-
const osc = line.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
2349
|
-
if (osc) {
|
|
2350
|
-
tokens.push({ kind: "sgr", value: osc[0], width: 0 });
|
|
2351
|
-
index += osc[0].length;
|
|
2352
|
-
continue;
|
|
2353
|
-
}
|
|
2354
|
-
const sgr = SGR_SEQUENCE_REGEX.exec(line.slice(index));
|
|
2355
|
-
if (sgr) {
|
|
2356
|
-
tokens.push({ kind: "sgr", value: sgr[0], width: 0 });
|
|
2357
|
-
index += sgr[0].length;
|
|
2358
|
-
continue;
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
const codePoint = line.codePointAt(index) ?? 0;
|
|
2362
|
-
const value = String.fromCodePoint(codePoint);
|
|
2363
|
-
tokens.push({ kind: "char", value, width: displayWidth2(value) });
|
|
2364
|
-
index += value.length;
|
|
2365
|
-
}
|
|
2366
|
-
return tokens;
|
|
2367
|
-
}
|
|
2368
|
-
function wrapTranscriptLine(line, columns) {
|
|
2369
|
-
if (line === "") return [""];
|
|
2370
|
-
const tokens = tokenizeAnsiLine(line);
|
|
2371
|
-
const result = [];
|
|
2372
|
-
let activeStyles = [];
|
|
2373
|
-
const applyStyleToken = (value) => {
|
|
2374
|
-
if (SGR_RESET_REGEX.test(value)) {
|
|
2375
|
-
activeStyles = [];
|
|
2376
|
-
} else {
|
|
2377
|
-
activeStyles.push(value);
|
|
2378
|
-
}
|
|
2379
|
-
};
|
|
2380
|
-
let start = 0;
|
|
2381
|
-
while (start < tokens.length) {
|
|
2382
|
-
if (tokens.slice(start).every((token) => token.kind === "sgr")) {
|
|
2383
|
-
if (result.length > 0) break;
|
|
2384
|
-
}
|
|
2385
|
-
const openingStyles = [...activeStyles];
|
|
2386
|
-
let width = 0;
|
|
2387
|
-
let end = start;
|
|
2388
|
-
let lastBreak = -1;
|
|
2389
|
-
while (end < tokens.length) {
|
|
2390
|
-
const token = tokens[end];
|
|
2391
|
-
if (token.kind === "sgr") {
|
|
2392
|
-
end += 1;
|
|
2393
|
-
continue;
|
|
2394
|
-
}
|
|
2395
|
-
if (width + token.width > columns && width > 0) break;
|
|
2396
|
-
width += token.width;
|
|
2397
|
-
end += 1;
|
|
2398
|
-
if (token.value === " " || token.value === " ") {
|
|
2399
|
-
lastBreak = end;
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
let segmentEnd = end;
|
|
2403
|
-
if (end < tokens.length && lastBreak > start) {
|
|
2404
|
-
const overflowToken = tokens[end];
|
|
2405
|
-
if (overflowToken.kind === "char" && overflowToken.value !== " " && overflowToken.width === 1) {
|
|
2406
|
-
segmentEnd = lastBreak;
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
if (segmentEnd === start) segmentEnd = start + 1;
|
|
2410
|
-
let segment = "";
|
|
2411
|
-
let sawStyle = openingStyles.length > 0;
|
|
2412
|
-
for (let i = start; i < segmentEnd; i += 1) {
|
|
2413
|
-
const token = tokens[i];
|
|
2414
|
-
segment += token.value;
|
|
2415
|
-
if (token.kind === "sgr") {
|
|
2416
|
-
sawStyle = true;
|
|
2417
|
-
applyStyleToken(token.value);
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
const prefix = openingStyles.join("");
|
|
2421
|
-
const needsReset = (sawStyle || activeStyles.length > 0) && !segment.endsWith("\x1B[0m");
|
|
2422
|
-
result.push(`${prefix}${segment}${needsReset ? "\x1B[0m" : ""}`);
|
|
2423
|
-
start = segmentEnd;
|
|
2424
|
-
while (start < tokens.length) {
|
|
2425
|
-
const token = tokens[start];
|
|
2426
|
-
if (token.kind === "char" && token.value === " ") {
|
|
2427
|
-
start += 1;
|
|
2428
|
-
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 ?? ""));
|
|
2429
2385
|
}
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
}
|
|
2433
|
-
return result.length > 0 ? result : [""];
|
|
2386
|
+
);
|
|
2387
|
+
});
|
|
2434
2388
|
}
|
|
2435
|
-
function
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
const { prefix, rest } = takeDisplayWidth(remaining, columns);
|
|
2445
|
-
result.push(prefix);
|
|
2446
|
-
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;
|
|
2447
2398
|
}
|
|
2448
|
-
}
|
|
2449
|
-
return result;
|
|
2399
|
+
})();
|
|
2450
2400
|
}
|
|
2451
2401
|
|
|
2452
2402
|
// packages/cli/tui/sessionRender.ts
|
|
@@ -2463,12 +2413,12 @@ function formatElapsedSeconds(totalSeconds) {
|
|
|
2463
2413
|
const mins = minutes % 60;
|
|
2464
2414
|
return `${hours}h ${mins}m`;
|
|
2465
2415
|
}
|
|
2466
|
-
function renderComposerTokenChip(tokens, fallbackContextWindow) {
|
|
2416
|
+
function renderComposerTokenChip(tokens, fallbackContextWindow, estimatedContextTokens) {
|
|
2467
2417
|
const cw = tokens?.contextWindow ?? fallbackContextWindow;
|
|
2468
2418
|
if (!cw) {
|
|
2469
2419
|
return "context: \u2014";
|
|
2470
2420
|
}
|
|
2471
|
-
const used = tokens ? tokens.input + tokens.output : 0;
|
|
2421
|
+
const used = tokens ? tokens.input + tokens.output : Math.max(0, estimatedContextTokens ?? 0);
|
|
2472
2422
|
const pct = Math.min(100, used / cw * 100);
|
|
2473
2423
|
const pctText = pct > 0 && pct < 10 ? pct.toFixed(1) : Math.round(pct).toString();
|
|
2474
2424
|
return `context: ${pctText}% (${formatTokenCount(used)}/${formatTokenCount(cw)})`;
|
|
@@ -2490,7 +2440,17 @@ function renderStatusLine(state) {
|
|
|
2490
2440
|
const untrackedText = untracked > 0 ? ` ${themeText(`?${untracked}`, "muted", colorEnabled)}` : "";
|
|
2491
2441
|
parts.push(`${branchText}${modifiedText}${untrackedText}`);
|
|
2492
2442
|
}
|
|
2493
|
-
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
|
+
);
|
|
2494
2454
|
parts.push(tokenSegment);
|
|
2495
2455
|
const runningCount = getProcessRegistry().list().filter((p) => p.status === "running").length;
|
|
2496
2456
|
if (runningCount > 0) {
|
|
@@ -2572,7 +2532,7 @@ function renderWelcome(state, frame = 0, maxFrames = 0, columns) {
|
|
|
2572
2532
|
const isDark = brightness === "dark";
|
|
2573
2533
|
let sceneArt = colorEnabled ? buildColoredScene(isDark, frame, maxFrames) : buildPlainScene(isDark, frame, maxFrames);
|
|
2574
2534
|
if (typeof columns === "number" && columns > 0) {
|
|
2575
|
-
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);
|
|
2576
2536
|
if (columns < widestSceneCol) sceneArt = "";
|
|
2577
2537
|
}
|
|
2578
2538
|
const versionLine = colorEnabled ? `\x1B[1m${themeColorSequence("accent")}nolo\x1B[0m ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |") : `nolo ${state.cliVersion ?? ""} | server ${state.serverUrl}`.replace(" |", " |");
|
|
@@ -2622,19 +2582,19 @@ function renderContextPanel(state, colorEnabled = resolveCliColorEnabled()) {
|
|
|
2622
2582
|
];
|
|
2623
2583
|
let maxW = 0;
|
|
2624
2584
|
for (const l of labels) {
|
|
2625
|
-
const w =
|
|
2585
|
+
const w = displayWidth(l);
|
|
2626
2586
|
if (w > maxW) maxW = w;
|
|
2627
2587
|
}
|
|
2628
2588
|
const targetWidth = maxW >= 9 ? maxW + 1 : 9;
|
|
2629
2589
|
const padLabel = (raw) => {
|
|
2630
|
-
const w =
|
|
2590
|
+
const w = displayWidth(raw);
|
|
2631
2591
|
const padding = " ".repeat(Math.max(0, targetWidth - w));
|
|
2632
2592
|
return raw + padding;
|
|
2633
2593
|
};
|
|
2634
2594
|
const field = (rawLabel, value) => `${themeText(padLabel(rawLabel), "muted", colorEnabled)}${value}`;
|
|
2635
2595
|
const next = (command, description) => ` ${themeText(command, "accent", colorEnabled)}${themeText(description, "muted", colorEnabled)}`;
|
|
2636
2596
|
const titleText = t("contextTitle");
|
|
2637
|
-
const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(
|
|
2597
|
+
const heading = colorEnabled ? [renderDialogTitle(titleText, true)] : [titleText, "\u2500".repeat(displayWidth(titleText))];
|
|
2638
2598
|
return [
|
|
2639
2599
|
...heading,
|
|
2640
2600
|
field(labels[0], `${state.agentName} (${state.agentKey})`),
|
|
@@ -2679,14 +2639,21 @@ function renderKnownAgents(colorEnabled = resolveCliColorEnabled()) {
|
|
|
2679
2639
|
|
|
2680
2640
|
// packages/cli/tui/sessionInput.ts
|
|
2681
2641
|
var PASTE_TOKEN_PREFIX = "\0PASTE\0";
|
|
2682
|
-
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
2642
|
+
function applyTuiInputKey(buffer, sequence, key = {}, cursorPos, options) {
|
|
2683
2643
|
const seq = sequence ?? "";
|
|
2684
2644
|
const curPos = Math.max(0, Math.min(buffer.length, cursorPos ?? buffer.length));
|
|
2645
|
+
const pasteStore = options?.pasteStore;
|
|
2685
2646
|
if (seq.startsWith(PASTE_TOKEN_PREFIX)) {
|
|
2686
2647
|
const rawPayload = seq.slice(PASTE_TOKEN_PREFIX.length);
|
|
2687
2648
|
const normalized = rawPayload.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2688
|
-
const
|
|
2689
|
-
|
|
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 };
|
|
2690
2657
|
}
|
|
2691
2658
|
if (seq === "" || key.ctrl && key.name === "c") {
|
|
2692
2659
|
return { buffer, cursorPos: curPos, abort: true };
|
|
@@ -2695,16 +2662,25 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2695
2662
|
return { buffer, cursorPos: curPos, copyView: true };
|
|
2696
2663
|
}
|
|
2697
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") {
|
|
2698
|
-
const
|
|
2699
|
-
|
|
2665
|
+
const insertAt2 = snapCursorOutsidePasteChip(buffer, curPos);
|
|
2666
|
+
const nextBuf2 = buffer.slice(0, insertAt2) + "\n" + buffer.slice(insertAt2);
|
|
2667
|
+
return { buffer: nextBuf2, cursorPos: insertAt2 + 1 };
|
|
2700
2668
|
}
|
|
2701
2669
|
if (key.name === "enter" || key.name === "return" || seq === "\r") {
|
|
2702
2670
|
return { buffer: "", cursorPos: 0, submit: buffer };
|
|
2703
2671
|
}
|
|
2704
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
|
+
}
|
|
2705
2677
|
return { buffer, cursorPos: Math.max(0, curPos - 1) };
|
|
2706
2678
|
}
|
|
2707
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
|
+
}
|
|
2708
2684
|
return { buffer, cursorPos: Math.min(buffer.length, curPos + 1) };
|
|
2709
2685
|
}
|
|
2710
2686
|
if (isHomeSequence(seq, key)) {
|
|
@@ -2715,24 +2691,33 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2715
2691
|
}
|
|
2716
2692
|
if (isDeleteWordSequence(seq, key)) {
|
|
2717
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
|
+
}
|
|
2718
2700
|
const cutIdx = findWordStartLeft(buffer, curPos);
|
|
2719
|
-
|
|
2720
|
-
return { buffer: nextBuf2, cursorPos: cutIdx };
|
|
2701
|
+
return deleteBufferRange(buffer, cutIdx, curPos, pasteStore);
|
|
2721
2702
|
}
|
|
2722
2703
|
if (isKillToLineStartSequence(seq, key)) {
|
|
2723
2704
|
if (curPos === 0) return { buffer, cursorPos: curPos };
|
|
2724
2705
|
const lineStart = buffer.lastIndexOf("\n", curPos - 1) + 1;
|
|
2725
|
-
|
|
2726
|
-
return { buffer: nextBuf2, cursorPos: lineStart };
|
|
2706
|
+
return deleteBufferRange(buffer, lineStart, curPos, pasteStore);
|
|
2727
2707
|
}
|
|
2728
2708
|
if (isKillToLineEndSequence(seq, key)) {
|
|
2729
2709
|
const nlIdx = buffer.indexOf("\n", curPos);
|
|
2730
2710
|
const lineEnd = nlIdx === -1 ? buffer.length : nlIdx;
|
|
2731
|
-
|
|
2732
|
-
return { buffer: nextBuf2, cursorPos: curPos };
|
|
2711
|
+
return deleteBufferRange(buffer, curPos, lineEnd, pasteStore);
|
|
2733
2712
|
}
|
|
2734
2713
|
if (isBackspaceSequence(seq, key)) {
|
|
2735
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
|
+
}
|
|
2736
2721
|
const nextBuf2 = buffer.slice(0, curPos - 1) + buffer.slice(curPos);
|
|
2737
2722
|
return { buffer: nextBuf2, cursorPos: curPos - 1 };
|
|
2738
2723
|
}
|
|
@@ -2740,6 +2725,10 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2740
2725
|
}
|
|
2741
2726
|
if (isForwardDeleteSequence(seq, key)) {
|
|
2742
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
|
+
}
|
|
2743
2732
|
const nextBuf2 = buffer.slice(0, curPos) + buffer.slice(curPos + 1);
|
|
2744
2733
|
return { buffer: nextBuf2, cursorPos: curPos };
|
|
2745
2734
|
}
|
|
@@ -2756,8 +2745,14 @@ function applyTuiInputKey(buffer, sequence, key = {}, cursorPos) {
|
|
|
2756
2745
|
if (!seq || key.ctrl || key.meta || seq.startsWith("\x1B")) {
|
|
2757
2746
|
return { buffer, cursorPos: curPos };
|
|
2758
2747
|
}
|
|
2759
|
-
const
|
|
2760
|
-
|
|
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;
|
|
2761
2756
|
}
|
|
2762
2757
|
function isLeftArrowSequence(seq, key) {
|
|
2763
2758
|
if (key.name === "left") return true;
|
|
@@ -2781,13 +2776,44 @@ function isEndSequence(seq, key) {
|
|
|
2781
2776
|
if (seq === "" || seq === "\x1B[F" || seq === "\x1B[4~" || seq === "\x1B[8~" || seq === "\x1BOF") return true;
|
|
2782
2777
|
return false;
|
|
2783
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
|
+
}
|
|
2784
2800
|
var CJK_CHAR = /[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/;
|
|
2785
2801
|
function findWordStartLeft(buffer, curPos) {
|
|
2786
2802
|
let i = curPos;
|
|
2787
2803
|
while (i > 0 && /\s/.test(buffer[i - 1])) i--;
|
|
2788
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
|
+
}
|
|
2789
2811
|
if (CJK_CHAR.test(buffer[i - 1])) return i - 1;
|
|
2790
|
-
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
|
+
}
|
|
2791
2817
|
return i;
|
|
2792
2818
|
}
|
|
2793
2819
|
function isDeleteWordSequence(seq, key) {
|
|
@@ -2898,6 +2924,7 @@ function createInitialTuiState(env = process.env) {
|
|
|
2898
2924
|
) || void 0;
|
|
2899
2925
|
const dialogEnvValue = asOptionalTrimmedString(env.NOLO_DIALOG);
|
|
2900
2926
|
const explicitDialogKey = asOptionalTrimmedString(env.NOLO_DIALOG_KEY) ?? (dialogEnvValue?.startsWith("dialog-") ? dialogEnvValue : void 0);
|
|
2927
|
+
const autoRouteDefault = env.NOLO_AUTO_ROUTE !== "0";
|
|
2901
2928
|
return {
|
|
2902
2929
|
agentKey,
|
|
2903
2930
|
agentName,
|
|
@@ -2917,26 +2944,59 @@ function createInitialTuiState(env = process.env) {
|
|
|
2917
2944
|
attachedImages: [],
|
|
2918
2945
|
runtimeMode,
|
|
2919
2946
|
modeLabel: asOptionalTrimmedString(env.NOLO_CLI_STATUS_MODE) ?? runtimeMode,
|
|
2920
|
-
gitStatus:
|
|
2947
|
+
gitStatus: void 0,
|
|
2921
2948
|
thinkingDisplay: normalizeThinkingDisplayMode(
|
|
2922
2949
|
env.NOLO_CLI_THINKING ?? env.NOLO_THINKING,
|
|
2923
2950
|
"hide"
|
|
2924
2951
|
),
|
|
2925
2952
|
toolDisplay: normalizeToolDisplayMode(env.NOLO_CLI_TOOLS ?? env.NOLO_TOOLS, "compact"),
|
|
2926
|
-
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
|
|
2927
2965
|
};
|
|
2928
2966
|
}
|
|
2929
|
-
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
|
+
});
|
|
2930
2975
|
return {
|
|
2931
2976
|
nextState: {
|
|
2932
2977
|
...state,
|
|
2933
2978
|
agentName: target.name,
|
|
2934
2979
|
agentKey: target.key,
|
|
2935
|
-
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
|
|
2936
2988
|
},
|
|
2937
2989
|
output: `Switched to ${target.name}. ${state.dialogId ? `Dialog kept: ${state.dialogId}` : "Dialog kept: new"}`
|
|
2938
2990
|
};
|
|
2939
2991
|
}
|
|
2992
|
+
function formatAttachedSkillLine(skillRef) {
|
|
2993
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
2994
|
+
if (!colorEnabled) return `\u25CF Attached skill: ${skillRef}`;
|
|
2995
|
+
const bullet = themeText("\u25CF", "success", true);
|
|
2996
|
+
const label = themeText("Attached skill:", "muted", true);
|
|
2997
|
+
const name = themeText(skillRef, "chrome", true);
|
|
2998
|
+
return `${bullet} ${label} ${name}`;
|
|
2999
|
+
}
|
|
2940
3000
|
function handleTuiInput(input, state) {
|
|
2941
3001
|
const trimmed = input.trim();
|
|
2942
3002
|
if (!trimmed) {
|
|
@@ -2986,32 +3046,32 @@ function handleTuiInput(input, state) {
|
|
|
2986
3046
|
return {
|
|
2987
3047
|
nextState: state,
|
|
2988
3048
|
output: [
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3049
|
+
t("themeCurrent", getActiveThemeName(), brightness),
|
|
3050
|
+
t("themeUsage"),
|
|
3051
|
+
t("themeAvailable", available)
|
|
2992
3052
|
].join("\n")
|
|
2993
3053
|
};
|
|
2994
3054
|
}
|
|
2995
3055
|
if (sub === "light" || sub === "dark") {
|
|
2996
3056
|
setActiveBrightness(sub);
|
|
2997
|
-
return { nextState: state, output:
|
|
3057
|
+
return { nextState: state, output: t("themeBrightnessSwitched", sub) };
|
|
2998
3058
|
}
|
|
2999
3059
|
if (sub === "auto") {
|
|
3000
3060
|
setActiveBrightness(null);
|
|
3001
3061
|
return {
|
|
3002
3062
|
nextState: state,
|
|
3003
|
-
output:
|
|
3063
|
+
output: t("themeBrightnessAuto", resolveTuiBrightness())
|
|
3004
3064
|
};
|
|
3005
3065
|
}
|
|
3006
3066
|
if (setActiveThemeName(sub)) {
|
|
3007
3067
|
return {
|
|
3008
3068
|
nextState: state,
|
|
3009
|
-
output:
|
|
3069
|
+
output: t("themeSwitched", sub)
|
|
3010
3070
|
};
|
|
3011
3071
|
} else {
|
|
3012
3072
|
return {
|
|
3013
3073
|
nextState: state,
|
|
3014
|
-
output:
|
|
3074
|
+
output: t("themeUnknown", sub, available)
|
|
3015
3075
|
};
|
|
3016
3076
|
}
|
|
3017
3077
|
}
|
|
@@ -3021,20 +3081,19 @@ function handleTuiInput(input, state) {
|
|
|
3021
3081
|
if (!sub) {
|
|
3022
3082
|
return {
|
|
3023
3083
|
nextState: state,
|
|
3024
|
-
output:
|
|
3025
|
-
Usage: /density <cozy|spacious>`
|
|
3084
|
+
output: t("densityCurrent", getActiveDensity())
|
|
3026
3085
|
};
|
|
3027
3086
|
}
|
|
3028
3087
|
if (sub === "cozy" || sub === "spacious") {
|
|
3029
3088
|
setActiveDensity(sub);
|
|
3030
3089
|
return {
|
|
3031
3090
|
nextState: state,
|
|
3032
|
-
output:
|
|
3091
|
+
output: t("densitySwitched", sub)
|
|
3033
3092
|
};
|
|
3034
3093
|
} else {
|
|
3035
3094
|
return {
|
|
3036
3095
|
nextState: state,
|
|
3037
|
-
output:
|
|
3096
|
+
output: t("densityUnknown", sub)
|
|
3038
3097
|
};
|
|
3039
3098
|
}
|
|
3040
3099
|
}
|
|
@@ -3045,52 +3104,52 @@ Usage: /density <cozy|spacious>`
|
|
|
3045
3104
|
if (argText !== "auto" && argText !== "local" && argText !== "server") {
|
|
3046
3105
|
return {
|
|
3047
3106
|
nextState: state,
|
|
3048
|
-
output: "
|
|
3107
|
+
output: t("runtimeUsage")
|
|
3049
3108
|
};
|
|
3050
3109
|
}
|
|
3051
3110
|
return {
|
|
3052
3111
|
nextState: { ...state, runtimeMode: argText },
|
|
3053
|
-
output:
|
|
3112
|
+
output: t("runtimeSet", argText)
|
|
3054
3113
|
};
|
|
3055
3114
|
}
|
|
3056
3115
|
case "/tools": {
|
|
3057
3116
|
if (!argText) {
|
|
3058
3117
|
return {
|
|
3059
3118
|
nextState: state,
|
|
3060
|
-
output:
|
|
3119
|
+
output: t("toolsCurrent", state.toolDisplay)
|
|
3061
3120
|
};
|
|
3062
3121
|
}
|
|
3063
3122
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
3064
3123
|
if (!["hide", "compact", "verbose", "on", "off"].includes(normalizedArg)) {
|
|
3065
3124
|
return {
|
|
3066
3125
|
nextState: state,
|
|
3067
|
-
output: "
|
|
3126
|
+
output: t("toolsUsage")
|
|
3068
3127
|
};
|
|
3069
3128
|
}
|
|
3070
3129
|
const nextMode = normalizeToolDisplayMode(normalizedArg, state.toolDisplay);
|
|
3071
3130
|
return {
|
|
3072
3131
|
nextState: { ...state, toolDisplay: nextMode },
|
|
3073
|
-
output:
|
|
3132
|
+
output: t("toolsSet", nextMode)
|
|
3074
3133
|
};
|
|
3075
3134
|
}
|
|
3076
3135
|
case "/thinking": {
|
|
3077
3136
|
if (!argText) {
|
|
3078
3137
|
return {
|
|
3079
3138
|
nextState: state,
|
|
3080
|
-
output:
|
|
3139
|
+
output: t("thinkingCurrent", state.thinkingDisplay)
|
|
3081
3140
|
};
|
|
3082
3141
|
}
|
|
3083
3142
|
const normalizedArg = asTrimmedLowercaseString(argText);
|
|
3084
3143
|
if (!["hide", "marker", "show", "on", "off"].includes(normalizedArg)) {
|
|
3085
3144
|
return {
|
|
3086
3145
|
nextState: state,
|
|
3087
|
-
output: "
|
|
3146
|
+
output: t("thinkingUsage")
|
|
3088
3147
|
};
|
|
3089
3148
|
}
|
|
3090
3149
|
const nextMode = normalizeThinkingDisplayMode(normalizedArg, state.thinkingDisplay);
|
|
3091
3150
|
return {
|
|
3092
3151
|
nextState: { ...state, thinkingDisplay: nextMode },
|
|
3093
|
-
output:
|
|
3152
|
+
output: t("thinkingSet", nextMode)
|
|
3094
3153
|
};
|
|
3095
3154
|
}
|
|
3096
3155
|
case "/tasks":
|
|
@@ -3102,14 +3161,14 @@ Usage: /density <cozy|spacious>`
|
|
|
3102
3161
|
const stopped = all.filter((p) => p.status !== "running");
|
|
3103
3162
|
const lines = [];
|
|
3104
3163
|
if (running.length > 0) {
|
|
3105
|
-
lines.push(
|
|
3164
|
+
lines.push(t("tasksRunning", String(running.length)));
|
|
3106
3165
|
for (const p of running) {
|
|
3107
3166
|
const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
|
|
3108
3167
|
lines.push(` pid ${p.pid} ${p.label} running ${elapsed}`);
|
|
3109
3168
|
}
|
|
3110
3169
|
}
|
|
3111
3170
|
if (stopped.length > 0) {
|
|
3112
|
-
lines.push(
|
|
3171
|
+
lines.push(t("tasksStopped", String(stopped.length)));
|
|
3113
3172
|
for (const p of stopped) {
|
|
3114
3173
|
const elapsed = formatElapsedSeconds(Math.floor((Date.now() - p.startedAt) / 1e3));
|
|
3115
3174
|
const exitInfo = p.exitCode !== void 0 ? ` exit ${p.exitCode}` : "";
|
|
@@ -3117,38 +3176,38 @@ Usage: /density <cozy|spacious>`
|
|
|
3117
3176
|
}
|
|
3118
3177
|
}
|
|
3119
3178
|
if (all.length === 0) {
|
|
3120
|
-
lines.push("
|
|
3179
|
+
lines.push(t("tasksNone"));
|
|
3121
3180
|
}
|
|
3122
3181
|
return { nextState: state, output: lines.join("\n") };
|
|
3123
3182
|
}
|
|
3124
3183
|
case "/stop": {
|
|
3125
3184
|
const registry = getProcessRegistry();
|
|
3126
3185
|
if (!argText) {
|
|
3127
|
-
return { nextState: state, output: "
|
|
3186
|
+
return { nextState: state, output: t("stopUsage") };
|
|
3128
3187
|
}
|
|
3129
3188
|
if (argText === "all") {
|
|
3130
3189
|
const before = registry.list().filter((p) => p.status === "running").length;
|
|
3131
3190
|
registry.stopAll();
|
|
3132
|
-
return { nextState: state, output:
|
|
3191
|
+
return { nextState: state, output: t("stopAllDone", String(before)) };
|
|
3133
3192
|
}
|
|
3134
3193
|
if (/^\d+$/.test(argText)) {
|
|
3135
3194
|
const pid = parseInt(argText, 10);
|
|
3136
3195
|
const proc = registry.get(pid);
|
|
3137
3196
|
if (!proc || proc.status !== "running") {
|
|
3138
|
-
return { nextState: state, output:
|
|
3197
|
+
return { nextState: state, output: t("stopNoPid", String(pid)) };
|
|
3139
3198
|
}
|
|
3140
3199
|
registry.kill(pid);
|
|
3141
|
-
return { nextState: state, output:
|
|
3200
|
+
return { nextState: state, output: t("stopPidDone", String(pid), proc.label) };
|
|
3142
3201
|
}
|
|
3143
3202
|
const matches = registry.list().filter((p) => p.status === "running" && p.label === argText);
|
|
3144
3203
|
if (matches.length === 0) {
|
|
3145
|
-
return { nextState: state, output:
|
|
3204
|
+
return { nextState: state, output: t("stopNoLabel", argText) };
|
|
3146
3205
|
}
|
|
3147
3206
|
for (const p of matches) {
|
|
3148
3207
|
registry.kill(p.pid);
|
|
3149
3208
|
}
|
|
3150
3209
|
const stoppedNames = matches.map((p) => `pid ${p.pid} (${p.label})`).join(", ");
|
|
3151
|
-
return { nextState: state, output:
|
|
3210
|
+
return { nextState: state, output: t("stopLabelsDone", stoppedNames) };
|
|
3152
3211
|
}
|
|
3153
3212
|
case "/exit":
|
|
3154
3213
|
case "/quit":
|
|
@@ -3172,15 +3231,13 @@ Usage: /density <cozy|spacious>`
|
|
|
3172
3231
|
if (argText) {
|
|
3173
3232
|
return {
|
|
3174
3233
|
nextState: state,
|
|
3175
|
-
output:
|
|
3176
|
-
|
|
3177
|
-
${renderTuiHelp()}`
|
|
3234
|
+
output: t("unknownCommand", trimmed) + renderTuiHelp()
|
|
3178
3235
|
};
|
|
3179
3236
|
}
|
|
3180
3237
|
if (!state.dialogId) {
|
|
3181
3238
|
return {
|
|
3182
3239
|
nextState: state,
|
|
3183
|
-
output: "
|
|
3240
|
+
output: t("compactNothing")
|
|
3184
3241
|
};
|
|
3185
3242
|
}
|
|
3186
3243
|
return {
|
|
@@ -3207,15 +3264,14 @@ ${renderTuiHelp()}`
|
|
|
3207
3264
|
if (argText === "current" || argText === "show") {
|
|
3208
3265
|
return {
|
|
3209
3266
|
nextState: state,
|
|
3210
|
-
output:
|
|
3267
|
+
output: t("agentCurrent", state.agentName, state.agentKey)
|
|
3211
3268
|
};
|
|
3212
3269
|
}
|
|
3213
3270
|
const resolvedTarget = resolveAgentSwitchTarget(argText, resolveCatalogPlatformAgents());
|
|
3214
3271
|
if (!resolvedTarget) {
|
|
3215
3272
|
return {
|
|
3216
3273
|
nextState: state,
|
|
3217
|
-
output:
|
|
3218
|
-
Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
3274
|
+
output: t("agentUnknown", argText)
|
|
3219
3275
|
};
|
|
3220
3276
|
}
|
|
3221
3277
|
return applyAgentSwitch(state, resolvedTarget);
|
|
@@ -3269,6 +3325,16 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3269
3325
|
action: { type: "set-mouse", enabled: argText === "on" }
|
|
3270
3326
|
};
|
|
3271
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
|
+
}
|
|
3272
3338
|
case "/resume": {
|
|
3273
3339
|
if (!argText) {
|
|
3274
3340
|
return {
|
|
@@ -3298,7 +3364,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3298
3364
|
if (rest[0] === "attach") {
|
|
3299
3365
|
const docName = rest.slice(1).join(" ").trim();
|
|
3300
3366
|
if (!docName) {
|
|
3301
|
-
return { nextState: state, output: "
|
|
3367
|
+
return { nextState: state, output: t("docAttachUsage") };
|
|
3302
3368
|
}
|
|
3303
3369
|
const attachedDocs = state.attachedDocs.includes(docName) ? state.attachedDocs : [...state.attachedDocs, docName];
|
|
3304
3370
|
return {
|
|
@@ -3308,7 +3374,7 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3308
3374
|
}
|
|
3309
3375
|
return {
|
|
3310
3376
|
nextState: state,
|
|
3311
|
-
output: state.attachedDocs.length > 0 ?
|
|
3377
|
+
output: state.attachedDocs.length > 0 ? t("docList", state.attachedDocs.join(", ")) : t("docNone")
|
|
3312
3378
|
};
|
|
3313
3379
|
}
|
|
3314
3380
|
case "/skill": {
|
|
@@ -3316,49 +3382,48 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`
|
|
|
3316
3382
|
if (sub === "attach") {
|
|
3317
3383
|
const skillRef = rest.slice(1).join(" ").trim();
|
|
3318
3384
|
if (!skillRef) {
|
|
3319
|
-
return { nextState: state, output: "
|
|
3385
|
+
return { nextState: state, output: t("skillAttachUsage") };
|
|
3320
3386
|
}
|
|
3321
3387
|
const attachedSkills = state.attachedSkills.includes(skillRef) ? state.attachedSkills : [...state.attachedSkills, skillRef];
|
|
3322
3388
|
return {
|
|
3323
3389
|
nextState: { ...state, attachedSkills },
|
|
3324
|
-
output:
|
|
3390
|
+
output: formatAttachedSkillLine(skillRef)
|
|
3325
3391
|
};
|
|
3326
3392
|
}
|
|
3327
3393
|
if (sub === "detach") {
|
|
3328
3394
|
const skillRef = rest.slice(1).join(" ").trim();
|
|
3329
3395
|
if (!skillRef) {
|
|
3330
|
-
return { nextState: state, output: "
|
|
3396
|
+
return { nextState: state, output: t("skillDetachUsage") };
|
|
3331
3397
|
}
|
|
3332
3398
|
const attachedSkills = state.attachedSkills.filter((s) => s !== skillRef);
|
|
3333
3399
|
return {
|
|
3334
3400
|
nextState: { ...state, attachedSkills },
|
|
3335
|
-
output: state.attachedSkills.includes(skillRef) ?
|
|
3401
|
+
output: state.attachedSkills.includes(skillRef) ? t("skillDetached", skillRef) : t("skillNotAttached", skillRef)
|
|
3336
3402
|
};
|
|
3337
3403
|
}
|
|
3338
3404
|
if (sub === "clear") {
|
|
3339
3405
|
if (state.attachedSkills.length === 0) {
|
|
3340
|
-
return { nextState: state, output: "
|
|
3406
|
+
return { nextState: state, output: t("skillNone") };
|
|
3341
3407
|
}
|
|
3342
3408
|
return {
|
|
3343
3409
|
nextState: { ...state, attachedSkills: [] },
|
|
3344
|
-
output:
|
|
3410
|
+
output: t("skillCleared", String(state.attachedSkills.length))
|
|
3345
3411
|
};
|
|
3346
3412
|
}
|
|
3347
3413
|
return {
|
|
3348
3414
|
nextState: state,
|
|
3349
|
-
output: state.attachedSkills.length > 0 ?
|
|
3350
|
-
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")
|
|
3351
3416
|
};
|
|
3352
3417
|
}
|
|
3353
3418
|
case "/customize":
|
|
3354
3419
|
return {
|
|
3355
3420
|
nextState: state,
|
|
3356
|
-
output: "
|
|
3421
|
+
output: t("customizeHint")
|
|
3357
3422
|
};
|
|
3358
3423
|
case "/login":
|
|
3359
3424
|
return {
|
|
3360
3425
|
nextState: state,
|
|
3361
|
-
output: "
|
|
3426
|
+
output: t("loginHint")
|
|
3362
3427
|
};
|
|
3363
3428
|
case "/profile":
|
|
3364
3429
|
return {
|
|
@@ -3374,16 +3439,12 @@ Usage: /skill attach <ref> | /skill detach <ref> | /skill clear` : "No skills at
|
|
|
3374
3439
|
case "/version":
|
|
3375
3440
|
return {
|
|
3376
3441
|
nextState: state,
|
|
3377
|
-
output:
|
|
3378
|
-
Update this install with: nolo update
|
|
3379
|
-
If repo-local output differs, publish/install the latest npm package first.`
|
|
3442
|
+
output: t("versionInfo", state.cliVersion || t("versionUnknown"))
|
|
3380
3443
|
};
|
|
3381
3444
|
default:
|
|
3382
3445
|
return {
|
|
3383
3446
|
nextState: state,
|
|
3384
|
-
output:
|
|
3385
|
-
|
|
3386
|
-
${renderTuiHelp()}`
|
|
3447
|
+
output: t("unknownCommand", command) + renderTuiHelp()
|
|
3387
3448
|
};
|
|
3388
3449
|
}
|
|
3389
3450
|
}
|
|
@@ -3401,19 +3462,23 @@ function brightnessFromRgb(r, g, b) {
|
|
|
3401
3462
|
const luma = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
3402
3463
|
return luma >= 0.5 ? "light" : "dark";
|
|
3403
3464
|
}
|
|
3404
|
-
function
|
|
3465
|
+
function parseOsc11Background(reply) {
|
|
3405
3466
|
const match = reply.match(OSC11_REPLY_RE);
|
|
3406
3467
|
if (!match) return null;
|
|
3407
|
-
|
|
3468
|
+
const channels = [
|
|
3408
3469
|
componentToByte(match[1]),
|
|
3409
3470
|
componentToByte(match[2]),
|
|
3410
3471
|
componentToByte(match[3])
|
|
3411
|
-
|
|
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
|
+
};
|
|
3412
3477
|
}
|
|
3413
3478
|
function isTerminalDevice(stream) {
|
|
3414
3479
|
return stream instanceof ReadStream;
|
|
3415
3480
|
}
|
|
3416
|
-
async function
|
|
3481
|
+
async function detectTerminalBackground(args = {}) {
|
|
3417
3482
|
const stdin = args.stdin ?? process.stdin;
|
|
3418
3483
|
const stdout = args.stdout ?? process.stdout;
|
|
3419
3484
|
const timeoutMs = args.timeoutMs ?? 100;
|
|
@@ -3440,7 +3505,7 @@ async function detectTerminalBrightness(args = {}) {
|
|
|
3440
3505
|
};
|
|
3441
3506
|
const onData = (chunk) => {
|
|
3442
3507
|
buffer += chunk.toString("latin1");
|
|
3443
|
-
const parsed =
|
|
3508
|
+
const parsed = parseOsc11Background(buffer);
|
|
3444
3509
|
if (parsed) finish(parsed);
|
|
3445
3510
|
else if (buffer.length > 256) finish(null);
|
|
3446
3511
|
};
|
|
@@ -3734,6 +3799,7 @@ function createChatQueueTuiBinding(runTurn) {
|
|
|
3734
3799
|
|
|
3735
3800
|
// packages/cli/tui/tuiHistory.ts
|
|
3736
3801
|
var MAX_TUI_HISTORY_TURNS = 500;
|
|
3802
|
+
var turnLineCache = /* @__PURE__ */ new WeakMap();
|
|
3737
3803
|
function createTurnHistory() {
|
|
3738
3804
|
return {
|
|
3739
3805
|
turns: [],
|
|
@@ -3775,45 +3841,81 @@ function applyOutputChunkToCurrentTurn(history, chunk) {
|
|
|
3775
3841
|
history.currentContent = next;
|
|
3776
3842
|
return true;
|
|
3777
3843
|
}
|
|
3778
|
-
function
|
|
3779
|
-
const
|
|
3780
|
-
const
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
const
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
const anchorPrefix = colorEnabled ? `${themeColorSequence("chrome")}\u25C8\x1B[39m ` : "\u25C8 ";
|
|
3792
|
-
return `${anchorPrefix}${line}`;
|
|
3793
|
-
}
|
|
3794
|
-
return line.startsWith("[nolo]") && colorEnabled ? themeText(line, "chrome", true) : line;
|
|
3795
|
-
});
|
|
3796
|
-
return styledLines.join("\n");
|
|
3797
|
-
};
|
|
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) {
|
|
3798
3857
|
const lines = [];
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
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));
|
|
3802
3878
|
}
|
|
3803
|
-
lines.push(styleTurn(role, content));
|
|
3804
|
-
};
|
|
3805
|
-
for (const turn of history.turns) {
|
|
3806
|
-
pushTurn(turn.role, turn.content);
|
|
3807
|
-
}
|
|
3808
|
-
if (history.currentRole !== null && history.currentContent) {
|
|
3809
|
-
pushTurn(history.currentRole, history.currentContent);
|
|
3810
3879
|
}
|
|
3880
|
+
return lines;
|
|
3881
|
+
}
|
|
3882
|
+
function buildHistoryLines(history, contentWidth) {
|
|
3883
|
+
const colorEnabled = resolveCliColorEnabled();
|
|
3884
|
+
const density = getActiveDensity();
|
|
3811
3885
|
const wrapped = [];
|
|
3812
|
-
for (
|
|
3813
|
-
|
|
3814
|
-
|
|
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);
|
|
3815
3903
|
}
|
|
3816
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
|
+
}
|
|
3817
3919
|
return wrapped;
|
|
3818
3920
|
}
|
|
3819
3921
|
function renderHistory(output, history, inputLines) {
|
|
@@ -3911,6 +4013,38 @@ function applyScrollAction(history, action, output, inputLines) {
|
|
|
3911
4013
|
}
|
|
3912
4014
|
|
|
3913
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
|
+
}
|
|
3914
4048
|
function createNoopFixedInput() {
|
|
3915
4049
|
return {
|
|
3916
4050
|
active: false,
|
|
@@ -3933,6 +4067,8 @@ function createNoopFixedInput() {
|
|
|
3933
4067
|
getInputLines: () => 1,
|
|
3934
4068
|
isPaused: () => false,
|
|
3935
4069
|
setMouseEnabled() {
|
|
4070
|
+
},
|
|
4071
|
+
setAltScreenEnabled() {
|
|
3936
4072
|
}
|
|
3937
4073
|
};
|
|
3938
4074
|
}
|
|
@@ -3976,7 +4112,7 @@ function createFixedInput(output, config) {
|
|
|
3976
4112
|
sections.push(fitAnsiLine(line.replace(/\r?\n/g, " "), cols));
|
|
3977
4113
|
}
|
|
3978
4114
|
const promptRaw = t("promptLabel");
|
|
3979
|
-
const promptWidth =
|
|
4115
|
+
const promptWidth = displayWidth(promptRaw);
|
|
3980
4116
|
const prompt = colorEnabled ? `${themeColorSequence("accent")}${promptRaw}\x1B[39m` : promptRaw;
|
|
3981
4117
|
const contentWidth = Math.max(1, cols - promptWidth);
|
|
3982
4118
|
const logicalLines = buffer.length === 0 ? [""] : buffer.split("\n");
|
|
@@ -4004,13 +4140,15 @@ function createFixedInput(output, config) {
|
|
|
4004
4140
|
for (let j = 0; j < rows.length; j += 1) {
|
|
4005
4141
|
const rowPrefix = j === 0 ? prefix : " ".repeat(promptWidth);
|
|
4006
4142
|
const rowText = rows[j] ?? "";
|
|
4007
|
-
sections.push(
|
|
4143
|
+
sections.push(
|
|
4144
|
+
`${rowPrefix}${styleCollapsedPastePlaceholders(rowText, colorEnabled)}`
|
|
4145
|
+
);
|
|
4008
4146
|
const rowLen = rowText.length;
|
|
4009
4147
|
if (!cursorFound) {
|
|
4010
4148
|
if (targetPos <= charOffset + rowLen || j === rows.length - 1 && i === logicalLines.length - 1) {
|
|
4011
4149
|
const subOffset = Math.max(0, Math.min(rowLen, targetPos - charOffset));
|
|
4012
4150
|
const subStr = rowText.slice(0, subOffset);
|
|
4013
|
-
cursorCol = promptWidth +
|
|
4151
|
+
cursorCol = promptWidth + displayWidth(subStr);
|
|
4014
4152
|
cursorRow = inputRows;
|
|
4015
4153
|
cursorFound = true;
|
|
4016
4154
|
}
|
|
@@ -4027,10 +4165,15 @@ function createFixedInput(output, config) {
|
|
|
4027
4165
|
};
|
|
4028
4166
|
const repaintAt = (buffer, cursorPos) => {
|
|
4029
4167
|
const { text, lines, cursorCol, cursorRow } = renderInputArea(buffer, cursorPos);
|
|
4168
|
+
let linesChanged = false;
|
|
4030
4169
|
if (lines !== inputLines) {
|
|
4031
4170
|
inputLines = lines;
|
|
4171
|
+
linesChanged = true;
|
|
4032
4172
|
}
|
|
4033
4173
|
setScrollRegion(inputLines);
|
|
4174
|
+
if (linesChanged) {
|
|
4175
|
+
config.onInputLinesChange?.(inputLines);
|
|
4176
|
+
}
|
|
4034
4177
|
const startRow = getRows() - inputLines + 1;
|
|
4035
4178
|
write(`\x1B[${startRow};1H`);
|
|
4036
4179
|
write("\x1B[J");
|
|
@@ -4078,8 +4221,7 @@ function createFixedInput(output, config) {
|
|
|
4078
4221
|
disable() {
|
|
4079
4222
|
disableMouse();
|
|
4080
4223
|
resetScrollRegion();
|
|
4081
|
-
|
|
4082
|
-
write(`\x1B[${rows};1H\x1B[2K\x1B[${Math.max(1, rows - 1)};1H`);
|
|
4224
|
+
leaveAltScreen(output);
|
|
4083
4225
|
},
|
|
4084
4226
|
getInputLines: () => inputLines,
|
|
4085
4227
|
isPaused: () => paused,
|
|
@@ -4090,6 +4232,13 @@ function createFixedInput(output, config) {
|
|
|
4090
4232
|
} else {
|
|
4091
4233
|
write("\x1B[?1000l\x1B[?1006l");
|
|
4092
4234
|
}
|
|
4235
|
+
},
|
|
4236
|
+
setAltScreenEnabled(enabled) {
|
|
4237
|
+
if (enabled) {
|
|
4238
|
+
enterAltScreen(output);
|
|
4239
|
+
} else {
|
|
4240
|
+
leaveAltScreen(output);
|
|
4241
|
+
}
|
|
4093
4242
|
}
|
|
4094
4243
|
};
|
|
4095
4244
|
}
|
|
@@ -4139,9 +4288,27 @@ function isIncompleteTail(input, start) {
|
|
|
4139
4288
|
}
|
|
4140
4289
|
return false;
|
|
4141
4290
|
}
|
|
4142
|
-
var PASTE_START = "\x1B[
|
|
4143
|
-
var PASTE_END = "\x1B[
|
|
4144
|
-
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) {
|
|
4145
4312
|
const tokens = [];
|
|
4146
4313
|
for (let index = 0; index < input.length; ) {
|
|
4147
4314
|
if (isIncompleteTail(input, index)) {
|
|
@@ -4149,15 +4316,17 @@ function splitRawInputWithTail(input) {
|
|
|
4149
4316
|
}
|
|
4150
4317
|
if (input.startsWith(PASTE_START, index)) {
|
|
4151
4318
|
const contentStart = index + PASTE_START.length;
|
|
4152
|
-
const endPos = input
|
|
4319
|
+
const endPos = findBracketedPasteEnd(input, contentStart);
|
|
4153
4320
|
if (endPos !== -1) {
|
|
4154
4321
|
const payload = input.slice(contentStart, endPos);
|
|
4155
4322
|
tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
|
|
4156
4323
|
index = endPos + PASTE_END.length;
|
|
4157
|
-
} else {
|
|
4324
|
+
} else if (options?.forceCompleteOpenPaste) {
|
|
4158
4325
|
const payload = input.slice(contentStart);
|
|
4159
4326
|
tokens.push(`${PASTE_TOKEN_PREFIX}${payload}`);
|
|
4160
4327
|
index = input.length;
|
|
4328
|
+
} else {
|
|
4329
|
+
return { tokens, tail: input.slice(index) };
|
|
4161
4330
|
}
|
|
4162
4331
|
continue;
|
|
4163
4332
|
}
|
|
@@ -4182,63 +4351,121 @@ function splitRawInputWithTail(input) {
|
|
|
4182
4351
|
index += csi.length;
|
|
4183
4352
|
continue;
|
|
4184
4353
|
}
|
|
4185
|
-
const
|
|
4186
|
-
|
|
4187
|
-
const
|
|
4188
|
-
|
|
4189
|
-
|
|
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;
|
|
4190
4367
|
}
|
|
4191
4368
|
return { tokens, tail: "" };
|
|
4192
4369
|
}
|
|
4193
4370
|
function splitRawInput(input) {
|
|
4194
|
-
const { tokens, tail } = splitRawInputWithTail(input
|
|
4371
|
+
const { tokens, tail } = splitRawInputWithTail(input, {
|
|
4372
|
+
forceCompleteOpenPaste: true
|
|
4373
|
+
});
|
|
4195
4374
|
if (!tail) return tokens;
|
|
4196
|
-
|
|
4197
|
-
for (let index = 0; index < tail.length; ) {
|
|
4198
|
-
const codePoint = tail.codePointAt(index);
|
|
4199
|
-
if (codePoint === void 0) break;
|
|
4200
|
-
const value = String.fromCodePoint(codePoint);
|
|
4201
|
-
tailTokens.push(value);
|
|
4202
|
-
index += value.length;
|
|
4203
|
-
}
|
|
4204
|
-
return [...tokens, ...tailTokens];
|
|
4375
|
+
return [...tokens, ...emitPlainRunAsTokens(tail)];
|
|
4205
4376
|
}
|
|
4206
4377
|
function createRawInputDecoder(onToken, options) {
|
|
4207
4378
|
const decoder = new TextDecoder("utf-8", { fatal: false, ignoreBOM: true });
|
|
4208
4379
|
let pendingBuffer = "";
|
|
4209
4380
|
let timer = null;
|
|
4210
4381
|
const timeoutMs = options?.escTimeoutMs ?? 15;
|
|
4382
|
+
const unmarkedPasteDebounceMs = options?.unmarkedPasteDebounceMs ?? 40;
|
|
4211
4383
|
const clearTimer = () => {
|
|
4212
4384
|
if (timer !== null) {
|
|
4213
4385
|
clearTimeout(timer);
|
|
4214
4386
|
timer = null;
|
|
4215
4387
|
}
|
|
4216
4388
|
};
|
|
4217
|
-
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 = () => {
|
|
4218
4399
|
clearTimer();
|
|
4219
|
-
if (pendingBuffer.length
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
}
|
|
4400
|
+
if (pendingBuffer.length === 0) return;
|
|
4401
|
+
const text = pendingBuffer;
|
|
4402
|
+
pendingBuffer = "";
|
|
4403
|
+
for (const token of emitPlainRunAsTokens(text)) {
|
|
4404
|
+
onToken(token);
|
|
4225
4405
|
}
|
|
4226
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
|
+
};
|
|
4227
4425
|
const decodeFn = (chunk) => {
|
|
4228
4426
|
clearTimer();
|
|
4229
4427
|
const bytes = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
4230
4428
|
const text = decoder.decode(bytes, { stream: true });
|
|
4231
4429
|
pendingBuffer += text;
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
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;
|
|
4236
4454
|
}
|
|
4237
|
-
if (pendingBuffer.
|
|
4238
|
-
|
|
4455
|
+
if (!pendingBuffer.includes("\n") && !pendingBuffer.includes("\r")) {
|
|
4456
|
+
emitCodePoints(pendingBuffer);
|
|
4457
|
+
pendingBuffer = "";
|
|
4458
|
+
return;
|
|
4459
|
+
}
|
|
4460
|
+
timer = setTimeout(flushPlainPending, unmarkedPasteDebounceMs);
|
|
4461
|
+
};
|
|
4462
|
+
decodeFn.flush = () => {
|
|
4463
|
+
if (pendingBuffer.startsWith(PASTE_START) || pendingBuffer.includes("\x1B")) {
|
|
4464
|
+
flushEscPending(true);
|
|
4465
|
+
return;
|
|
4239
4466
|
}
|
|
4467
|
+
flushPlainPending();
|
|
4240
4468
|
};
|
|
4241
|
-
decodeFn.flush = flush;
|
|
4242
4469
|
decodeFn.destroy = () => {
|
|
4243
4470
|
clearTimer();
|
|
4244
4471
|
pendingBuffer = "";
|
|
@@ -4248,12 +4475,66 @@ function createRawInputDecoder(onToken, options) {
|
|
|
4248
4475
|
|
|
4249
4476
|
// packages/cli/tui/readlineWorkspace.ts
|
|
4250
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
|
+
}
|
|
4251
4532
|
function readAgentsMdBlock(cwd) {
|
|
4252
4533
|
for (const name of ["AGENTS.md", "CLAUDE.md"]) {
|
|
4253
|
-
const filePath =
|
|
4254
|
-
if (
|
|
4534
|
+
const filePath = join2(cwd, name);
|
|
4535
|
+
if (existsSync3(filePath)) {
|
|
4255
4536
|
try {
|
|
4256
|
-
let content =
|
|
4537
|
+
let content = readFileSync2(filePath, "utf8").trim();
|
|
4257
4538
|
if (!content) continue;
|
|
4258
4539
|
if (Buffer.byteLength(content, "utf8") > AGENTS_MD_MAX_BYTES) {
|
|
4259
4540
|
content = Buffer.from(content, "utf8").subarray(0, AGENTS_MD_MAX_BYTES).toString("utf8") + "\n\n<!-- AGENTS.md truncated -->";
|
|
@@ -4277,10 +4558,14 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4277
4558
|
effectiveAgentName = cachedRoute.agentName;
|
|
4278
4559
|
} else if (!continueId && env.NOLO_AUTO_ROUTE !== "0" && state.agentKey === DEFAULT_TUI_AGENT_KEY) {
|
|
4279
4560
|
const authToken = env.AUTH_TOKEN ?? env.AUTH ?? env.BENCHMARK_AUTH_TOKEN ?? "";
|
|
4280
|
-
const route = await classifyCliAutoRoute(message, {
|
|
4561
|
+
const route = authToken ? await classifyCliAutoRoute(message, {
|
|
4281
4562
|
serverUrl: state.serverUrl,
|
|
4282
4563
|
authToken
|
|
4283
|
-
})
|
|
4564
|
+
}) : {
|
|
4565
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS[resolveCliAutoFallbackTier(message)],
|
|
4566
|
+
tier: resolveCliAutoFallbackTier(message),
|
|
4567
|
+
classified: false
|
|
4568
|
+
};
|
|
4284
4569
|
effectiveAgentKey = route.agentKey;
|
|
4285
4570
|
effectiveAgentName = `auto\u2192${route.tier}`;
|
|
4286
4571
|
if (effectiveAgentKey !== state.agentKey) {
|
|
@@ -4368,6 +4653,18 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4368
4653
|
if (skillDiscoveryBlock) {
|
|
4369
4654
|
extraContextBlocks.push(skillDiscoveryBlock);
|
|
4370
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
|
+
}
|
|
4371
4668
|
const result = await agentRunner({
|
|
4372
4669
|
agentName: effectiveAgentName,
|
|
4373
4670
|
agentKey: effectiveAgentKey,
|
|
@@ -4388,9 +4685,17 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4388
4685
|
...options.confirmDestructiveAction ? { confirmDestructiveAction: options.confirmDestructiveAction } : {},
|
|
4389
4686
|
...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {},
|
|
4390
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
|
+
} : {},
|
|
4391
4696
|
...options.activityReporter ? { activityReporter: options.activityReporter } : {},
|
|
4392
4697
|
...skillAllowedTools !== void 0 ? { allowedToolNames: skillAllowedTools } : {},
|
|
4393
|
-
...
|
|
4698
|
+
...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
|
|
4394
4699
|
});
|
|
4395
4700
|
if (!continueId && result.dialogId && effectiveAgentKey !== state.agentKey) {
|
|
4396
4701
|
autoRouteByDialog.set(result.dialogId, {
|
|
@@ -4398,19 +4703,32 @@ async function runAgentChat(scriptDir, state, message, env, output, agentRunner
|
|
|
4398
4703
|
agentName: effectiveAgentName
|
|
4399
4704
|
});
|
|
4400
4705
|
}
|
|
4401
|
-
return
|
|
4706
|
+
return {
|
|
4707
|
+
...result,
|
|
4708
|
+
contextWindow: resolveAgentContextWindow({
|
|
4709
|
+
agentKey: effectiveAgentKey,
|
|
4710
|
+
agentName: effectiveAgentName,
|
|
4711
|
+
autoRouteDefault: env.NOLO_AUTO_ROUTE !== "0"
|
|
4712
|
+
})
|
|
4713
|
+
};
|
|
4402
4714
|
}
|
|
4403
4715
|
function waitForActionGate(rl, input, output, gate, spawnRunner) {
|
|
4404
4716
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
4405
4717
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
4406
|
-
|
|
4407
|
-
|
|
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}
|
|
4408
4725
|
`);
|
|
4409
|
-
if (
|
|
4726
|
+
if (body) output.write(`[nolo] ${body}
|
|
4410
4727
|
`);
|
|
4411
4728
|
output.write(` ${displayCommand}
|
|
4412
4729
|
`);
|
|
4413
|
-
output.write(
|
|
4730
|
+
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
4731
|
+
`);
|
|
4414
4732
|
return new Promise((resolve2) => {
|
|
4415
4733
|
let settled = false;
|
|
4416
4734
|
const finish = (result) => {
|
|
@@ -4500,17 +4818,28 @@ function isInteractiveInput(input) {
|
|
|
4500
4818
|
function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
4501
4819
|
const commandPayload = gate.kind === "handoff" ? readCommandActionGatePayload(gate.payload) : null;
|
|
4502
4820
|
const displayCommand = commandPayload?.displayCommand ?? commandPayload?.command.join(" ") ?? gate.title;
|
|
4503
|
-
|
|
4504
|
-
|
|
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")}
|
|
4505
4826
|
`);
|
|
4506
|
-
|
|
4827
|
+
output.write(`[nolo] ${title}
|
|
4828
|
+
`);
|
|
4829
|
+
if (body) output.write(`[nolo] ${body}
|
|
4507
4830
|
`);
|
|
4508
4831
|
output.write(` ${displayCommand}
|
|
4509
4832
|
`);
|
|
4510
|
-
output.write(
|
|
4833
|
+
output.write(`[nolo] ${t("actionGateEnterHint")}
|
|
4834
|
+
`);
|
|
4511
4835
|
return new Promise((resolve2) => {
|
|
4512
4836
|
const rawInput = input;
|
|
4837
|
+
let settled = false;
|
|
4838
|
+
let commandRunning = false;
|
|
4513
4839
|
const finish = (result) => {
|
|
4840
|
+
if (settled) return;
|
|
4841
|
+
settled = true;
|
|
4842
|
+
hooks?.registerToken?.(null);
|
|
4514
4843
|
input.off("data", onData);
|
|
4515
4844
|
resolve2(result);
|
|
4516
4845
|
};
|
|
@@ -4528,13 +4857,9 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
4528
4857
|
actionGateResult: { gateId: gate.id, status: "failed", output: message }
|
|
4529
4858
|
}
|
|
4530
4859
|
});
|
|
4531
|
-
const
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
cancel("interrupted");
|
|
4535
|
-
return;
|
|
4536
|
-
}
|
|
4537
|
-
if (!text.includes("\r") && !text.includes("\n")) return;
|
|
4860
|
+
const runCommand = async () => {
|
|
4861
|
+
if (settled || commandRunning) return;
|
|
4862
|
+
commandRunning = true;
|
|
4538
4863
|
if (!commandPayload) {
|
|
4539
4864
|
fail("unsupported gate payload");
|
|
4540
4865
|
return;
|
|
@@ -4572,7 +4897,25 @@ function waitForRawActionGate(input, output, gate, spawnRunner, hooks) {
|
|
|
4572
4897
|
}
|
|
4573
4898
|
});
|
|
4574
4899
|
};
|
|
4575
|
-
|
|
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
|
+
}
|
|
4576
4919
|
});
|
|
4577
4920
|
}
|
|
4578
4921
|
async function startTuiWorkspace(options) {
|
|
@@ -4584,22 +4927,33 @@ async function startTuiWorkspace(options) {
|
|
|
4584
4927
|
const spawnRunner = options.spawnRunner ?? spawnProcess;
|
|
4585
4928
|
const selfUpdater = options.selfUpdater ?? ((target) => runSelfUpdate({ output: target }));
|
|
4586
4929
|
if (output.isTTY) {
|
|
4587
|
-
output
|
|
4930
|
+
enterAltScreen(output);
|
|
4931
|
+
installAltScreenRestoreHandlers(output);
|
|
4932
|
+
output.write("\x1B[2J\x1B[H");
|
|
4588
4933
|
}
|
|
4589
|
-
const detected = await
|
|
4934
|
+
const detected = await detectTerminalBackground({
|
|
4590
4935
|
stdin: input,
|
|
4591
4936
|
stdout: output
|
|
4592
4937
|
});
|
|
4593
|
-
if (detected)
|
|
4938
|
+
if (detected) {
|
|
4939
|
+
setActiveBrightness(detected.brightness);
|
|
4940
|
+
setActiveTerminalBaseHex(detected.hex);
|
|
4941
|
+
}
|
|
4594
4942
|
const bannerColumns = output.columns;
|
|
4595
4943
|
output.write(renderWelcome(state, 0, 0, bannerColumns));
|
|
4596
4944
|
let fixedInput = createNoopFixedInput();
|
|
4597
4945
|
let buffer = "";
|
|
4598
4946
|
let cursorPos = 0;
|
|
4947
|
+
const pasteStore = createCollapsedPasteStore();
|
|
4599
4948
|
let activeTurnAbort = null;
|
|
4949
|
+
let forcedStop = false;
|
|
4950
|
+
let forcedStopEpoch = 0;
|
|
4951
|
+
let turnEpoch = 0;
|
|
4952
|
+
let activeTurnEpoch = 0;
|
|
4600
4953
|
const activityIndicator = createActivityIndicator({
|
|
4601
4954
|
isTurnActive: () => activeTurnAbort !== null,
|
|
4602
4955
|
fallbackLabel: () => `${state.agentName} -> working`,
|
|
4956
|
+
stoppingLabel: () => t("turnStopping"),
|
|
4603
4957
|
onRepaint: () => {
|
|
4604
4958
|
if (fixedInput.active && !fixedInput.isPaused()) {
|
|
4605
4959
|
output.write("\x1B[?2026h\x1B[?25l");
|
|
@@ -4629,8 +4983,10 @@ async function startTuiWorkspace(options) {
|
|
|
4629
4983
|
},
|
|
4630
4984
|
output
|
|
4631
4985
|
});
|
|
4986
|
+
const RENDER_THROTTLE_MS = 33;
|
|
4632
4987
|
let renderScheduled = false;
|
|
4633
4988
|
let renderTimer = null;
|
|
4989
|
+
let sessionEnded = false;
|
|
4634
4990
|
const flushPendingRender = () => {
|
|
4635
4991
|
if (renderTimer !== null) {
|
|
4636
4992
|
clearTimeout(renderTimer);
|
|
@@ -4657,11 +5013,26 @@ async function startTuiWorkspace(options) {
|
|
|
4657
5013
|
renderScheduled = false;
|
|
4658
5014
|
renderTimer = null;
|
|
4659
5015
|
paintSyncedFrame();
|
|
4660
|
-
},
|
|
5016
|
+
}, RENDER_THROTTLE_MS);
|
|
4661
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;
|
|
4662
5027
|
const renderHistoryToOutput = () => {
|
|
4663
5028
|
if (fixedInput.isPaused()) return;
|
|
4664
|
-
|
|
5029
|
+
if (syncingLayout) return;
|
|
5030
|
+
syncingLayout = true;
|
|
5031
|
+
try {
|
|
5032
|
+
renderHistory(output, history, fixedInput.getInputLines());
|
|
5033
|
+
} finally {
|
|
5034
|
+
syncingLayout = false;
|
|
5035
|
+
}
|
|
4665
5036
|
};
|
|
4666
5037
|
const readLatestAssistantReply = () => {
|
|
4667
5038
|
const lastReply = [...history.turns].reverse().find((turn) => turn.role === "assistant")?.content;
|
|
@@ -4699,7 +5070,11 @@ ${t("copyViewHint")}
|
|
|
4699
5070
|
return true;
|
|
4700
5071
|
};
|
|
4701
5072
|
let modalOwnsKeyboard = false;
|
|
5073
|
+
let rawActionGateTokenHandler = null;
|
|
4702
5074
|
const runOneAgentTurn = async (message, imageUrls, actionGateHandler, confirmDestructiveAction) => {
|
|
5075
|
+
forcedStop = false;
|
|
5076
|
+
turnEpoch += 1;
|
|
5077
|
+
const myEpoch = turnEpoch;
|
|
4703
5078
|
history.followBottom = true;
|
|
4704
5079
|
startTurn(history, "user");
|
|
4705
5080
|
appendToCurrentTurn(history, message);
|
|
@@ -4729,6 +5104,7 @@ ${t("copyViewHint")}
|
|
|
4729
5104
|
} : void 0;
|
|
4730
5105
|
try {
|
|
4731
5106
|
activeTurnAbort = new AbortController();
|
|
5107
|
+
activeTurnEpoch = myEpoch;
|
|
4732
5108
|
const runResult = await runAgentChat(
|
|
4733
5109
|
options.scriptDir,
|
|
4734
5110
|
state,
|
|
@@ -4742,10 +5118,27 @@ ${t("copyViewHint")}
|
|
|
4742
5118
|
...confirmDestructiveAction ? { confirmDestructiveAction } : {},
|
|
4743
5119
|
...requestUserChoice ? { requestUserChoice } : {},
|
|
4744
5120
|
abortSignal: activeTurnAbort.signal,
|
|
5121
|
+
pastedTextStore: pasteStore,
|
|
4745
5122
|
explicitAgentSwitch,
|
|
4746
5123
|
activityReporter
|
|
4747
5124
|
}
|
|
4748
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
|
+
}
|
|
4749
5142
|
const wasAborted = activeTurnAbort.signal.aborted;
|
|
4750
5143
|
activeTurnAbort = null;
|
|
4751
5144
|
explicitAgentSwitch = false;
|
|
@@ -4756,9 +5149,13 @@ ${t("copyViewHint")}
|
|
|
4756
5149
|
if (fixedInput.active) fixedInput.repaint(buffer);
|
|
4757
5150
|
}
|
|
4758
5151
|
if (wasAborted) {
|
|
4759
|
-
|
|
5152
|
+
if (runResult.pendingToolName) {
|
|
5153
|
+
emitCommandOutput(t("turnStoppedToolPending", runResult.pendingToolName));
|
|
5154
|
+
} else {
|
|
5155
|
+
emitCommandOutput(t("turnStopped"));
|
|
5156
|
+
}
|
|
4760
5157
|
}
|
|
4761
|
-
if (runResult.dialogId || runResult.turnTokens) {
|
|
5158
|
+
if (runResult.dialogId || runResult.turnTokens || runResult.contextWindow) {
|
|
4762
5159
|
const nextDialogKey = runResult.dialogId ? runResult.dialogId === state.dialogId && state.dialogKey ? state.dialogKey : state.dialogOwnerId ? `dialog-${state.dialogOwnerId}-${runResult.dialogId}` : void 0 : state.dialogKey;
|
|
4763
5160
|
state = {
|
|
4764
5161
|
...state,
|
|
@@ -4767,7 +5164,8 @@ ${t("copyViewHint")}
|
|
|
4767
5164
|
dialogKey: nextDialogKey,
|
|
4768
5165
|
dialogLabel: runResult.dialogId
|
|
4769
5166
|
} : {},
|
|
4770
|
-
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {}
|
|
5167
|
+
...runResult.turnTokens ? { turnTokens: runResult.turnTokens } : {},
|
|
5168
|
+
...runResult.contextWindow ? { contextWindow: runResult.contextWindow } : {}
|
|
4771
5169
|
};
|
|
4772
5170
|
}
|
|
4773
5171
|
if (!wasAborted && runResult.exitCode !== 0) {
|
|
@@ -4834,6 +5232,7 @@ ${t("copyViewHint")}
|
|
|
4834
5232
|
}
|
|
4835
5233
|
if (result.action?.type === "exit") return true;
|
|
4836
5234
|
if (result.action?.type === "clear") {
|
|
5235
|
+
clearCollapsedPasteStore(pasteStore);
|
|
4837
5236
|
history.turns.length = 0;
|
|
4838
5237
|
history.currentRole = null;
|
|
4839
5238
|
history.currentContent = "";
|
|
@@ -4904,7 +5303,19 @@ ${t("copyViewHint")}
|
|
|
4904
5303
|
...state,
|
|
4905
5304
|
agentName: pickResult.name,
|
|
4906
5305
|
agentKey: pickResult.key,
|
|
4907
|
-
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 } : {}
|
|
4908
5319
|
};
|
|
4909
5320
|
if (state.dialogId) autoRouteByDialog.delete(state.dialogId);
|
|
4910
5321
|
explicitAgentSwitch = true;
|
|
@@ -4936,6 +5347,16 @@ ${t("copyViewHint")}
|
|
|
4936
5347
|
if (result.action?.type === "set-mouse") {
|
|
4937
5348
|
fixedInput.setMouseEnabled(result.action.enabled);
|
|
4938
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
|
+
}
|
|
4939
5360
|
if (result.action?.type === "copy-view") {
|
|
4940
5361
|
const opened = await openCopyView();
|
|
4941
5362
|
if (!opened) emitCommandOutput(t("copyNothing"));
|
|
@@ -4979,14 +5400,7 @@ ${t("copyViewHint")}
|
|
|
4979
5400
|
dialog: pickResult.dialog,
|
|
4980
5401
|
env: options.env ?? process.env
|
|
4981
5402
|
});
|
|
4982
|
-
const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS)
|
|
4983
|
-
(turn) => turn.role === "assistant" ? {
|
|
4984
|
-
...turn,
|
|
4985
|
-
content: formatAssistantDisplay(
|
|
4986
|
-
turn.content
|
|
4987
|
-
)
|
|
4988
|
-
} : turn
|
|
4989
|
-
);
|
|
5403
|
+
const restored = loadedTurns.slice(-MAX_TUI_HISTORY_TURNS);
|
|
4990
5404
|
history.turns.length = 0;
|
|
4991
5405
|
history.turns.push(...restored);
|
|
4992
5406
|
history.currentRole = null;
|
|
@@ -5000,6 +5414,7 @@ ${t("copyViewHint")}
|
|
|
5000
5414
|
dialogLabel: pickResult.dialog.id,
|
|
5001
5415
|
turnTokens: void 0
|
|
5002
5416
|
};
|
|
5417
|
+
clearCollapsedPasteStore(pasteStore);
|
|
5003
5418
|
emitCommandOutput(
|
|
5004
5419
|
`${t("resumedDialogPrefix")}: ${pickResult.dialog.title} (${pickResult.dialog.id})`
|
|
5005
5420
|
);
|
|
@@ -5123,6 +5538,7 @@ ${err.message}` : ""}`
|
|
|
5123
5538
|
output.write("\x1B[?2004h");
|
|
5124
5539
|
let busy = false;
|
|
5125
5540
|
let done = false;
|
|
5541
|
+
let resolveDone = null;
|
|
5126
5542
|
let cursorPos2 = 0;
|
|
5127
5543
|
fixedInput = createFixedInput(output, {
|
|
5128
5544
|
getStatusLine: () => {
|
|
@@ -5159,6 +5575,9 @@ ${err.message}` : ""}`
|
|
|
5159
5575
|
const oneLine = text.replace(/\r?\n/g, " \u23CE ");
|
|
5160
5576
|
return dimCliText(` \u2937 ${i + 1}. ${oneLine}`, colorEnabled);
|
|
5161
5577
|
});
|
|
5578
|
+
},
|
|
5579
|
+
onInputLinesChange: () => {
|
|
5580
|
+
renderHistoryToOutput();
|
|
5162
5581
|
}
|
|
5163
5582
|
});
|
|
5164
5583
|
fixedInput.init();
|
|
@@ -5181,6 +5600,9 @@ ${err.message}` : ""}`
|
|
|
5181
5600
|
const finish = () => {
|
|
5182
5601
|
if (done) return;
|
|
5183
5602
|
done = true;
|
|
5603
|
+
sessionEnded = true;
|
|
5604
|
+
resolveDone?.();
|
|
5605
|
+
clearCollapsedPasteStore(pasteStore);
|
|
5184
5606
|
resizeTarget.off?.("resize", onResize);
|
|
5185
5607
|
input.off("data", onData);
|
|
5186
5608
|
onData.destroy();
|
|
@@ -5198,7 +5620,10 @@ ${err.message}` : ""}`
|
|
|
5198
5620
|
}
|
|
5199
5621
|
return;
|
|
5200
5622
|
}
|
|
5201
|
-
if (modalOwnsKeyboard)
|
|
5623
|
+
if (modalOwnsKeyboard) {
|
|
5624
|
+
rawActionGateTokenHandler?.(sequence);
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5202
5627
|
const busyLock = busy;
|
|
5203
5628
|
const scrollAction = parseScrollAction(sequence);
|
|
5204
5629
|
if (scrollAction) {
|
|
@@ -5208,19 +5633,33 @@ ${err.message}` : ""}`
|
|
|
5208
5633
|
return;
|
|
5209
5634
|
}
|
|
5210
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
|
+
}
|
|
5211
5650
|
const stopBinding = chatQueueBinding;
|
|
5212
5651
|
if (stopBinding && stopBinding.queueLength() > 0) {
|
|
5213
5652
|
stopBinding.preemptForStop();
|
|
5214
5653
|
}
|
|
5654
|
+
activityIndicator.markStopping();
|
|
5215
5655
|
activeTurnAbort.abort();
|
|
5216
5656
|
return;
|
|
5217
5657
|
}
|
|
5218
|
-
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos2
|
|
5658
|
+
const result = applyTuiInputKey(buffer, sequence, {}, cursorPos2, {
|
|
5659
|
+
pasteStore
|
|
5660
|
+
});
|
|
5219
5661
|
if (result.copyView) {
|
|
5220
|
-
if (busyLock) return;
|
|
5221
|
-
busy = true;
|
|
5222
5662
|
const opened = await openCopyView();
|
|
5223
|
-
busy = false;
|
|
5224
5663
|
if (!opened) {
|
|
5225
5664
|
history.followBottom = true;
|
|
5226
5665
|
startTurn(history, "assistant");
|
|
@@ -5236,14 +5675,19 @@ ${err.message}` : ""}`
|
|
|
5236
5675
|
return;
|
|
5237
5676
|
}
|
|
5238
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("!");
|
|
5239
5684
|
if (busyLock) {
|
|
5240
|
-
const
|
|
5241
|
-
const trimmedText = submittedText2.trim();
|
|
5685
|
+
const trimmedText = submittedText.trim();
|
|
5242
5686
|
const busySlashCommand = trimmedText.split(/\s+/)[0]?.toLowerCase();
|
|
5243
5687
|
const isBusyLocalSlash = busySlashCommand === "/context" || busySlashCommand === "/ctx" || busySlashCommand === "/switch";
|
|
5244
5688
|
if (isBusyLocalSlash) {
|
|
5245
5689
|
const beforeAgentKey = state.agentKey;
|
|
5246
|
-
const res = handleTuiInput(
|
|
5690
|
+
const res = handleTuiInput(submittedText, state);
|
|
5247
5691
|
if (res.action) {
|
|
5248
5692
|
output.write(
|
|
5249
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"
|
|
@@ -5261,6 +5705,7 @@ ${hint}` : hint;
|
|
|
5261
5705
|
`);
|
|
5262
5706
|
}
|
|
5263
5707
|
}
|
|
5708
|
+
releaseCollapsedPasteReferences(submittedText, pasteStore);
|
|
5264
5709
|
buffer = "";
|
|
5265
5710
|
cursorPos2 = 0;
|
|
5266
5711
|
if (fixedInput.active) fixedInput.repaint(buffer, cursorPos2);
|
|
@@ -5272,7 +5717,10 @@ ${hint}` : hint;
|
|
|
5272
5717
|
try {
|
|
5273
5718
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5274
5719
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5275
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5720
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5721
|
+
registerToken: (handler) => {
|
|
5722
|
+
rawActionGateTokenHandler = handler;
|
|
5723
|
+
}
|
|
5276
5724
|
});
|
|
5277
5725
|
} finally {
|
|
5278
5726
|
modalOwnsKeyboard = false;
|
|
@@ -5295,7 +5743,7 @@ ${hint}` : hint;
|
|
|
5295
5743
|
}
|
|
5296
5744
|
);
|
|
5297
5745
|
const decision = binding.resolveSubmit({
|
|
5298
|
-
text:
|
|
5746
|
+
text: submittedText,
|
|
5299
5747
|
isRunning: true
|
|
5300
5748
|
});
|
|
5301
5749
|
if (decision.kind === "queue-text") {
|
|
@@ -5304,7 +5752,7 @@ ${hint}` : hint;
|
|
|
5304
5752
|
cursorPos2 = 0;
|
|
5305
5753
|
fixedInput.repaint(buffer, cursorPos2);
|
|
5306
5754
|
} else if (decision.kind === "queue-blocked") {
|
|
5307
|
-
} else if (decision.kind === "noop" && !
|
|
5755
|
+
} else if (decision.kind === "noop" && !submittedText.trim() && binding.queueLength() > 0) {
|
|
5308
5756
|
if (binding.preemptForDrain()) {
|
|
5309
5757
|
if (activeTurnAbort) {
|
|
5310
5758
|
activeTurnAbort.abort();
|
|
@@ -5313,13 +5761,16 @@ ${hint}` : hint;
|
|
|
5313
5761
|
}
|
|
5314
5762
|
return;
|
|
5315
5763
|
}
|
|
5316
|
-
if (!
|
|
5764
|
+
if (!submittedText.trim() && chatQueueBinding && chatQueueBinding.queueLength() > 0) {
|
|
5317
5765
|
const actionGateHandler = async (gate) => {
|
|
5318
5766
|
modalOwnsKeyboard = true;
|
|
5319
5767
|
try {
|
|
5320
5768
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5321
5769
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5322
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5770
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5771
|
+
registerToken: (handler) => {
|
|
5772
|
+
rawActionGateTokenHandler = handler;
|
|
5773
|
+
}
|
|
5323
5774
|
});
|
|
5324
5775
|
} finally {
|
|
5325
5776
|
modalOwnsKeyboard = false;
|
|
@@ -5364,17 +5815,13 @@ ${err.message}` : ""}`
|
|
|
5364
5815
|
} finally {
|
|
5365
5816
|
busy = false;
|
|
5366
5817
|
}
|
|
5367
|
-
|
|
5368
|
-
if (drainEnv.NOLO_CLI_GIT_STATUS !== "0") {
|
|
5369
|
-
state = { ...state, gitStatus: detectGitStatus(state.cwd) };
|
|
5370
|
-
}
|
|
5818
|
+
refreshGitStatus();
|
|
5371
5819
|
flushPendingRender();
|
|
5372
5820
|
fixedInput.exitOutputMode(buffer, cursorPos2);
|
|
5373
5821
|
return;
|
|
5374
5822
|
}
|
|
5375
5823
|
}
|
|
5376
|
-
busy =
|
|
5377
|
-
const submittedText = result.submit;
|
|
5824
|
+
busy = startsChatTurn;
|
|
5378
5825
|
buffer = "";
|
|
5379
5826
|
cursorPos2 = 0;
|
|
5380
5827
|
fixedInput.enterOutputMode(submittedText);
|
|
@@ -5387,7 +5834,10 @@ ${err.message}` : ""}`
|
|
|
5387
5834
|
try {
|
|
5388
5835
|
return await waitForRawActionGate(input, output, gate, spawnRunner, {
|
|
5389
5836
|
beforeSubprocess: () => fixedInput.pause(),
|
|
5390
|
-
afterSubprocess: () => fixedInput.resumeFromSubprocess()
|
|
5837
|
+
afterSubprocess: () => fixedInput.resumeFromSubprocess(),
|
|
5838
|
+
registerToken: (handler) => {
|
|
5839
|
+
rawActionGateTokenHandler = handler;
|
|
5840
|
+
}
|
|
5391
5841
|
});
|
|
5392
5842
|
} finally {
|
|
5393
5843
|
modalOwnsKeyboard = false;
|
|
@@ -5417,10 +5867,7 @@ ${err.message}` : ""}`
|
|
|
5417
5867
|
finish();
|
|
5418
5868
|
return;
|
|
5419
5869
|
}
|
|
5420
|
-
|
|
5421
|
-
if (refreshEnv.NOLO_CLI_GIT_STATUS !== "0") {
|
|
5422
|
-
state = { ...state, gitStatus: detectGitStatus(state.cwd) };
|
|
5423
|
-
}
|
|
5870
|
+
refreshGitStatus();
|
|
5424
5871
|
flushPendingRender();
|
|
5425
5872
|
fixedInput.exitOutputMode(buffer, cursorPos2);
|
|
5426
5873
|
return;
|
|
@@ -5435,13 +5882,10 @@ ${err.message}` : ""}`
|
|
|
5435
5882
|
try {
|
|
5436
5883
|
input.on("data", onData);
|
|
5437
5884
|
fixedInput.repaint(buffer, cursorPos2);
|
|
5885
|
+
refreshGitStatus();
|
|
5438
5886
|
await new Promise((resolve2) => {
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
clearInterval(check);
|
|
5442
|
-
resolve2();
|
|
5443
|
-
}
|
|
5444
|
-
}, 10);
|
|
5887
|
+
resolveDone = resolve2;
|
|
5888
|
+
if (done) resolve2();
|
|
5445
5889
|
});
|
|
5446
5890
|
} finally {
|
|
5447
5891
|
finish();
|
|
@@ -5496,9 +5940,13 @@ export {
|
|
|
5496
5940
|
createNoopFixedInput,
|
|
5497
5941
|
createRawInputDecoder,
|
|
5498
5942
|
createTurnHistory,
|
|
5499
|
-
|
|
5943
|
+
displayWidth,
|
|
5944
|
+
enterAltScreen,
|
|
5500
5945
|
finalizeCurrentTurn,
|
|
5501
5946
|
fitAnsiLine,
|
|
5947
|
+
installAltScreenRestoreHandlers,
|
|
5948
|
+
isAltScreenOn,
|
|
5949
|
+
leaveAltScreen,
|
|
5502
5950
|
padOrTruncateToWidth,
|
|
5503
5951
|
parseScrollAction,
|
|
5504
5952
|
renderHistory,
|