nolo-cli 0.8.0-alpha.21 → 0.8.0-alpha.23
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-42U3VOVZ.js → _executeModel-YXTTYRXS.js} +44 -43
- package/{action-TLI3V62L.js → action-QM2ONPYZ.js} +9 -9
- package/{addContentAction-57RSIIMR.js → addContentAction-UXY3GM53.js} +8 -8
- package/{addDialogAgentAction-G3VWEA6E.js → addDialogAgentAction-MUBYOG65.js} +10 -10
- package/{agentDeleteCommand-5DD2IM3J.js → agentDeleteCommand-4NO7Y6UI.js} +28 -27
- package/{agentEmailCommands-6FACJBU4.js → agentEmailCommands-NPP5TGZV.js} +60 -58
- package/{agentListCommands-I6KZYCIG.js → agentListCommands-IP5BNB5W.js} +32 -30
- package/{agentMachineCommands-VKLIGMZA.js → agentMachineCommands-24NFTIKY.js} +27 -26
- package/{agentPullCommand-O2MTUAFR.js → agentPullCommand-N6UWRTVL.js} +3 -3
- package/{agentRecordCommands-7TZICYDT.js → agentRecordCommands-7AWSR46F.js} +51 -49
- package/{agentRunCommand-L4OM23KV.js → agentRunCommand-P46WCJ6P.js} +55 -52
- package/{agentRunControl-K4VKNEHF.js → agentRunControl-S3G62M6C.js} +3 -3
- package/{agentRuntimeLocal-ZYEIPTY4.js → agentRuntimeLocal-V5UV7S4R.js} +14 -12
- package/{agentSlice-BX7GXSNO.js → agentSlice-3CVAZZOP.js} +9 -9
- package/{authCommand-EB5JSOX5.js → authCommand-B6P2XYLN.js} +11 -11
- package/{authCommands-XPEHTKSM.js → authCommands-4YKA4GTU.js} +7 -7
- package/{chunk-AS4PVWA4.js → chunk-2CVZSC5L.js} +1 -1
- package/{chunk-VUW5FBDB.js → chunk-4VA3UQRF.js} +9 -9
- package/{chunk-2JCXITPK.js → chunk-5NYGMN4O.js} +15 -15
- package/{chunk-AGFH73SK.js → chunk-6KRA6AWI.js} +1 -1
- package/{chunk-P3PKED2I.js → chunk-6OHYC4BY.js} +9 -12
- package/{chunk-5KLGBAAR.js → chunk-6UUD2WES.js} +1 -1
- package/{chunk-ENOG22KJ.js → chunk-A4MYG3TR.js} +18 -20
- package/{chunk-2FTTDCD4.js → chunk-AMJ7LA5D.js} +1 -1
- package/chunk-AOKWJZ5N.js +4884 -0
- package/{chunk-JRKKFRAV.js → chunk-AWY2AFHN.js} +9 -5
- package/{chunk-RL776AGR.js → chunk-BB2PII22.js} +1 -1
- package/{chunk-I6XMPTMR.js → chunk-BFDWXLFF.js} +2 -2
- package/{chunk-VVX233PH.js → chunk-BT37DVDA.js} +9 -9
- package/chunk-BYXBJQAS.js +0 -0
- package/{chunk-C3RUNRHT.js → chunk-D55DXHXL.js} +1 -1
- package/{chunk-7DAJ4AI4.js → chunk-DSNLHTP3.js} +2 -2
- package/{chunk-SDJDLO5W.js → chunk-EUN3SYY7.js} +5 -5
- package/{chunk-FSO5B7GH.js → chunk-HAC6GPRE.js} +2 -2
- package/{chunk-CKOJQDKR.js → chunk-JEMATI63.js} +1 -1
- package/{chunk-7U44LYTR.js → chunk-JTINRTBT.js} +1 -1
- package/{chunk-YPRZSPF3.js → chunk-KLOCUWKZ.js} +1 -1
- package/{chunk-4O3CARJ4.js → chunk-KTHLAJEY.js} +1 -1
- package/{chunk-URUUZLPA.js → chunk-L3KWEH3V.js} +8 -8
- package/{chunk-O2ZNTTET.js → chunk-LBUTKV7S.js} +21 -12
- package/{chunk-GU3PEVGZ.js → chunk-LFFATN2M.js} +2632 -1578
- package/{chunk-UB6SN4NJ.js → chunk-LJCH34R2.js} +6 -6
- package/{chunk-5EFXE3O7.js → chunk-LTH6AVG7.js} +3 -3
- package/{chunk-7GNGZRLZ.js → chunk-LW6FJFCT.js} +45 -67
- package/{chunk-7KCUSYT2.js → chunk-MIQOUMSN.js} +7 -7
- package/{chunk-FVYY6MCS.js → chunk-O7VS7JLJ.js} +17 -17
- package/{chunk-RCSJFQPB.js → chunk-P7GAHW32.js} +361 -90
- package/{chunk-AL2KDGR2.js → chunk-PTT6KSYQ.js} +134 -84
- package/{chunk-4IJYA27C.js → chunk-PXZAAB4L.js} +4 -4
- package/{chunk-4XENYTF5.js → chunk-Q2WC4KGQ.js} +3 -3
- package/{chunk-4QEWT7KD.js → chunk-RBB43B5W.js} +367 -85
- package/chunk-RBCENBG7.js +36 -0
- package/{chunk-IWX4UW2E.js → chunk-RBCNBU2A.js} +88 -8
- package/{chunk-25LCXTML.js → chunk-RQPZX6KP.js} +2 -2
- package/{chunk-6KHNO3SK.js → chunk-RYMUT5JO.js} +23 -23
- package/{chunk-VX3SXJ3N.js → chunk-UBSKX3LP.js} +6 -6
- package/{chunk-4ZDM73SD.js → chunk-V2J635L5.js} +1 -1
- package/{chunk-DSZUWUYB.js → chunk-VBKJTOAW.js} +1 -1
- package/{chunk-XBUBEFNX.js → chunk-WESWWEVA.js} +1 -1
- package/{chunk-2ECQG4YX.js → chunk-ZAUDEKML.js} +253 -159
- package/{chunk-N54XAP77.js → chunk-ZJS64PZJ.js} +1 -1
- package/{createAgentAutomationAction-RJF3N2QY.js → createAgentAutomationAction-DYQOGAVE.js} +25 -24
- package/{createDialogAction-DRSPS6CE.js → createDialogAction-ETB3KQQE.js} +25 -24
- package/{createPageAction-6B2WMNO3.js → createPageAction-UF2RHA63.js} +25 -24
- package/{dbSlice-Q3TM2FJV.js → dbSlice-R5EJKZBW.js} +7 -7
- package/{deleteFile-OW53A6BX.js → deleteFile-WPWVZE4B.js} +5 -5
- package/{dialogCommands-4IX4XIZE.js → dialogCommands-LYYC7XHF.js} +23 -22
- package/{dialogSlice-3M7KX2TX.js → dialogSlice-IFBZ4IT2.js} +24 -23
- package/{docCreateCommands-SIL3NPGT.js → docCreateCommands-I66OI374.js} +22 -21
- package/{docDeleteCommands-7IOMLUS4.js → docDeleteCommands-OVRBCHMF.js} +23 -22
- package/{docReadCommands-FNFXUA5L.js → docReadCommands-YLWUMEH7.js} +22 -21
- package/{docStore-SV7E34D4.js → docStore-65WO7U36.js} +24 -23
- package/{docUpdateCommands-X2HNDVUC.js → docUpdateCommands-NSICS4IN.js} +22 -21
- package/fetchMessages-KTNM7QAR.js +1 -1
- package/{getPricing-3E6UNPKL.js → getPricing-7PUT44ZS.js} +7 -3
- package/{handleSendMessageAction-JYETO5RZ.js → handleSendMessageAction-T76HEDOP.js} +29 -28
- package/index.js +74 -74
- package/{localDialogRead-2VRI24F4.js → localDialogRead-YSKFFRTT.js} +1 -1
- package/{machineCommands-RIO3RP5Q.js → machineCommands-4HQY6UVZ.js} +57 -55
- package/{machineWsRunDispatch-W7UYLGB5.js → machineWsRunDispatch-7YW2M4FS.js} +49 -47
- package/{memoryCommands-O4MIPIWQ.js → memoryCommands-HG4WKTU7.js} +2 -2
- package/{models-4OPOOLFS.js → models-MFXNI3TF.js} +2 -2
- package/package.json +1 -1
- package/{read-GW7ZEI23.js → read-5ZMY7FKP.js} +5 -5
- package/{readDocTool-HUFU6OCT.js → readDocTool-2NXDK32S.js} +1 -1
- package/{readlineWorkspace-27JR7WPW.js → readlineWorkspace-FLQWOAUR.js} +759 -604
- package/{removeDialogAgentAction-CXKR4NJI.js → removeDialogAgentAction-KOLQ2R5W.js} +13 -12
- package/{runAgentClientLoop-HZFAPJHS.js → runAgentClientLoop-IUV2TR3X.js} +43 -42
- package/{runtimeDoctorCommands-LRHLPDRC.js → runtimeDoctorCommands-UWR5UDSM.js} +5 -5
- package/{setDialogExtraReferencesAction-6RKUSXHX.js → setDialogExtraReferencesAction-OMTEO7X6.js} +10 -10
- package/{setPrimaryDialogAgentAction-T3UTBEFG.js → setPrimaryDialogAgentAction-DOCIS6V4.js} +13 -12
- package/{settingSlice-IVKXJXMG.js → settingSlice-UWZJYDOA.js} +8 -8
- package/{spaceCommands-E7VOF4LO.js → spaceCommands-BDDAT4VU.js} +29 -28
- package/{spaceSlice-TSVROA5U.js → spaceSlice-HH633ZA4.js} +23 -22
- package/{streamAgentChatTurn-3C5RQZJF.js → streamAgentChatTurn-UBZOVFKV.js} +95 -72
- package/{tableCommands-O7O2LBEG.js → tableCommands-M3DJUETS.js} +10 -10
- package/{toolApiClient-QI3YBNWB.js → toolApiClient-C7P7YSE4.js} +2 -2
- package/{tools-EQDEKR6N.js → tools-OQZ34KCU.js} +31 -30
- package/{tuiSummaryLlmCaller-RV3THLZF.js → tuiSummaryLlmCaller-42AEL3LL.js} +8 -6
- package/{updateCommands-VOSPKXFF.js → updateCommands-TC5SX42Y.js} +3 -3
- package/{updateDialogTitleAction-3XV7VWSZ.js → updateDialogTitleAction-A3OOMSDO.js} +27 -26
- package/chunk-BBYVOSU2.js +0 -792
- package/chunk-DCOA4QSN.js +0 -105
- package/{chunk-DZ3XJVET.js → chunk-3QAF2LTL.js} +3 -3
- package/{chunk-EHLHSX7R.js → chunk-5MMZUWSG.js} +3 -3
- package/{chunk-ISNCLGUZ.js → chunk-AVMJVOQY.js} +3 -3
- package/{chunk-UTLZINAP.js → chunk-DVRHHFEA.js} +10 -10
- package/{chunk-4CQLVGRV.js → chunk-ID4G2MAR.js} +3 -3
- package/{chunk-5MIDPSSK.js → chunk-JK7VW2FN.js} +3 -3
- package/{chunk-TILFE6LV.js → chunk-YOCHZD7D.js} +3 -3
- package/{db-HCJ5PRB5.js → db-6QED3ZVO.js} +3 -3
- package/{understanding-3CUQQ6SV.js → understanding-ZOESBLF3.js} +3 -3
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveMachineId
|
|
3
3
|
} from "./chunk-6HYVJV7B.js";
|
|
4
|
-
import {
|
|
5
|
-
createRunActivityTracker,
|
|
6
|
-
finalizeRunRecord,
|
|
7
|
-
spawnLocalBackgroundRun
|
|
8
|
-
} from "./chunk-2FTTDCD4.js";
|
|
9
4
|
import {
|
|
10
5
|
buildLocalRunEnv,
|
|
11
6
|
isFullstackCodingAgentRef,
|
|
@@ -14,22 +9,25 @@ import {
|
|
|
14
9
|
resolveRawAgentInput,
|
|
15
10
|
resolveServerUrl,
|
|
16
11
|
writeUsage
|
|
17
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-3QAF2LTL.js";
|
|
18
13
|
import {
|
|
19
14
|
createCliCallAgentToolExecutor,
|
|
20
15
|
createCliLocalRuntimeAdapter,
|
|
21
16
|
isBuiltinNoloAgentRef
|
|
22
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-P7GAHW32.js";
|
|
18
|
+
import {
|
|
19
|
+
CliProviderQuotaError
|
|
20
|
+
} from "./chunk-CMKUBIGW.js";
|
|
23
21
|
import {
|
|
24
22
|
getReadableCliDb
|
|
25
23
|
} from "./chunk-W4NVOSFF.js";
|
|
26
24
|
import {
|
|
27
25
|
readDbRecord,
|
|
28
26
|
resolveAgentRecordFromHybridStore
|
|
29
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-EUN3SYY7.js";
|
|
30
28
|
import {
|
|
31
29
|
normalizeAgentHandle
|
|
32
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ZJS64PZJ.js";
|
|
33
31
|
import {
|
|
34
32
|
NOLO_PROJECT_MANAGER_AGENT_KEY,
|
|
35
33
|
isLocalCliAgentKey
|
|
@@ -38,20 +36,25 @@ import {
|
|
|
38
36
|
applyModelLayerOverride,
|
|
39
37
|
buildModelLayerOverride
|
|
40
38
|
} from "./chunk-LTRXGFMS.js";
|
|
41
|
-
import {
|
|
42
|
-
CliProviderQuotaError
|
|
43
|
-
} from "./chunk-CMKUBIGW.js";
|
|
44
39
|
import {
|
|
45
40
|
isGatewayHttpStatus
|
|
46
41
|
} from "./chunk-GAKEBQD6.js";
|
|
47
42
|
import {
|
|
48
43
|
buildMemorySubjectsForAgent,
|
|
49
44
|
resolveAgentMemoryPolicy
|
|
50
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-A4MYG3TR.js";
|
|
51
46
|
import {
|
|
52
47
|
parseExternalSkillMarkdown,
|
|
53
48
|
parseSkillDocProtocol
|
|
54
49
|
} from "./chunk-VC6OZXO5.js";
|
|
50
|
+
import {
|
|
51
|
+
DEFAULT_CONTEXT_WINDOW,
|
|
52
|
+
getModelContextWindow,
|
|
53
|
+
parseUiAskChoiceContent
|
|
54
|
+
} from "./chunk-ZAUDEKML.js";
|
|
55
|
+
import {
|
|
56
|
+
parsePositiveFiniteNumberOrFallback
|
|
57
|
+
} from "./chunk-Y5GCAMGP.js";
|
|
55
58
|
import {
|
|
56
59
|
touchMemoryItemsInDb
|
|
57
60
|
} from "./chunk-HNW7IJSK.js";
|
|
@@ -59,17 +62,10 @@ import {
|
|
|
59
62
|
chooseMemoryOwners,
|
|
60
63
|
loadMemoryCandidatesFromDb
|
|
61
64
|
} from "./chunk-XENYHRUE.js";
|
|
62
|
-
import {
|
|
63
|
-
getModelContextWindow,
|
|
64
|
-
parseUiAskChoiceContent
|
|
65
|
-
} from "./chunk-2ECQG4YX.js";
|
|
66
65
|
import {
|
|
67
66
|
readPipeText,
|
|
68
67
|
spawnProcess
|
|
69
68
|
} from "./chunk-IDZTNRP2.js";
|
|
70
|
-
import {
|
|
71
|
-
resolveAuthToken
|
|
72
|
-
} from "./chunk-ISNCLGUZ.js";
|
|
73
69
|
import {
|
|
74
70
|
buildSkillDiscoveryContextBlock
|
|
75
71
|
} from "./chunk-AFON4QUU.js";
|
|
@@ -80,28 +76,39 @@ import {
|
|
|
80
76
|
import {
|
|
81
77
|
buildPlatformChatCompletionRequest,
|
|
82
78
|
parsePlatformChatCompletionData
|
|
83
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-6UUD2WES.js";
|
|
84
80
|
import {
|
|
85
81
|
resolveAgentRuntimeConfigFromRecord
|
|
86
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-YOCHZD7D.js";
|
|
87
83
|
import {
|
|
88
84
|
LOCAL_AGENT_CONFIG_MISSING_CODE,
|
|
89
85
|
LOCAL_TURN_ABORTED_CODE,
|
|
90
86
|
readActionGate,
|
|
91
87
|
readCommandActionGatePayload
|
|
92
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-RBB43B5W.js";
|
|
93
89
|
import {
|
|
94
90
|
resolvePlatformChatCompletionsEndpoint
|
|
95
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-AWY2AFHN.js";
|
|
96
92
|
import {
|
|
97
93
|
clipCompactText
|
|
98
94
|
} from "./chunk-5MMAK75Q.js";
|
|
99
95
|
import {
|
|
100
96
|
findModelConfig
|
|
101
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-AOKWJZ5N.js";
|
|
98
|
+
import {
|
|
99
|
+
asTrimmedLowercaseString
|
|
100
|
+
} from "./chunk-QSJ3HFEF.js";
|
|
102
101
|
import {
|
|
103
102
|
compactWhitespace
|
|
104
103
|
} from "./chunk-DWLEOOGR.js";
|
|
104
|
+
import {
|
|
105
|
+
createRunActivityTracker,
|
|
106
|
+
finalizeRunRecord,
|
|
107
|
+
spawnLocalBackgroundRun
|
|
108
|
+
} from "./chunk-AMJ7LA5D.js";
|
|
109
|
+
import {
|
|
110
|
+
resolveAuthToken
|
|
111
|
+
} from "./chunk-AVMJVOQY.js";
|
|
105
112
|
import {
|
|
106
113
|
toErrorMessage
|
|
107
114
|
} from "./chunk-HNMXYYJR.js";
|
|
@@ -109,28 +116,251 @@ import {
|
|
|
109
116
|
getDefaultCliLocalRuntimeDb
|
|
110
117
|
} from "./chunk-H33743XH.js";
|
|
111
118
|
import {
|
|
112
|
-
|
|
113
|
-
} from "./chunk-Y5GCAMGP.js";
|
|
114
|
-
import {
|
|
115
|
-
asTrimmedLowercaseString
|
|
116
|
-
} from "./chunk-QSJ3HFEF.js";
|
|
117
|
-
import {
|
|
119
|
+
BUILTIN_NOLO_AGENT_KEY,
|
|
118
120
|
PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
|
|
119
121
|
PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
|
|
120
122
|
PUBLIC_GLM_52_AGENT_KEY,
|
|
121
123
|
PUBLIC_KIMI_K26_IMAGE_AGENT_KEY
|
|
122
|
-
} from "./chunk-
|
|
123
|
-
import {
|
|
124
|
-
isLoopbackUrl
|
|
125
|
-
} from "./chunk-4SN6J65J.js";
|
|
124
|
+
} from "./chunk-VBKJTOAW.js";
|
|
126
125
|
import {
|
|
127
126
|
asTrimmedString
|
|
128
127
|
} from "./chunk-3EUW3WEO.js";
|
|
128
|
+
import {
|
|
129
|
+
isLoopbackUrl
|
|
130
|
+
} from "./chunk-4SN6J65J.js";
|
|
129
131
|
import {
|
|
130
132
|
asOptionalTrimmedString
|
|
131
133
|
} from "./chunk-G3SUCT4W.js";
|
|
132
134
|
|
|
135
|
+
// packages/agent-runtime/quickChatIntentCore.ts
|
|
136
|
+
var INTENT_MODEL = "deepseek-v4-flash";
|
|
137
|
+
var INTENT_PROVIDER = "deepseek";
|
|
138
|
+
var QUICK_CHAT_INTENT_TIMEOUT_MS = 4e3;
|
|
139
|
+
var SHORT_GREETING_MAX_LENGTH = 20;
|
|
140
|
+
var SHORT_GREETING_PATTERN = /^(?:hi|hello|hey|hiya|yo|sup|howdy|嗨|哈喽|哈囉|你好|您好|在吗|在嘛|喂|早上好|中午好|下午好|晚上好|拜拜|再见|谢谢|thanks|thx|ok|好的|收到|了解)[!.。,、~~]?$/iu;
|
|
141
|
+
function isShortGreeting(text) {
|
|
142
|
+
const trimmed = text.trim();
|
|
143
|
+
if (!trimmed) return false;
|
|
144
|
+
if (trimmed.length > SHORT_GREETING_MAX_LENGTH) return false;
|
|
145
|
+
return SHORT_GREETING_PATTERN.test(trimmed);
|
|
146
|
+
}
|
|
147
|
+
var COMPLEXITY_SIMPLE_MAX_LENGTH = 80;
|
|
148
|
+
var COMPLEXITY_MEDIUM_MAX_LENGTH = 500;
|
|
149
|
+
var COMPLEXITY_KEYWORDS = /为什么|如何|分析|对比|比较|设计|架构|实现|原理|推导|评价|区别|关系|影响|优化|重构/;
|
|
150
|
+
var COMPLEXITY_CODE_BLOCK = /```[\s\S]*```/;
|
|
151
|
+
function estimateComplexity(text) {
|
|
152
|
+
const trimmed = text.trim();
|
|
153
|
+
const len = trimmed.length;
|
|
154
|
+
if (len > COMPLEXITY_MEDIUM_MAX_LENGTH) return "complex";
|
|
155
|
+
if (COMPLEXITY_CODE_BLOCK.test(trimmed)) return "complex";
|
|
156
|
+
if (len > COMPLEXITY_SIMPLE_MAX_LENGTH) return "medium";
|
|
157
|
+
if (COMPLEXITY_KEYWORDS.test(trimmed)) return "medium";
|
|
158
|
+
return "simple";
|
|
159
|
+
}
|
|
160
|
+
var TIER_DESCRIPTIONS = {
|
|
161
|
+
flash: "\u5FEB\u901F\u7B80\u5355\uFF1A\u95EE\u5019\u3001\u95F2\u804A\u3001\u5FEB\u901F\u95EE\u7B54\u3001\u7FFB\u8BD1\u3001\u77ED\u6587",
|
|
162
|
+
balanced: "\u5E73\u8861\u63A8\u7406\uFF1A\u5206\u6790\u3001\u4E2D\u7B49\u957F\u5EA6\u5199\u4F5C\u3001\u4EE3\u7801\u3001\u63A8\u7406",
|
|
163
|
+
quality: "\u9AD8\u8D28\u91CF\u6DF1\u5EA6\uFF1A\u590D\u6742\u63A8\u7406\u3001\u957F\u6587\u3001\u67B6\u6784\u8BBE\u8BA1\u3001\u6DF1\u5EA6\u5206\u6790"
|
|
164
|
+
};
|
|
165
|
+
function buildQuickChatIntentSystemPrompt(tierAgents) {
|
|
166
|
+
const agentList = tierAgents.map((t2) => ` - "${t2.agentKey}"\uFF1A${t2.description}`).join("\n");
|
|
167
|
+
return `\u4F60\u662F\u4E00\u4E2A\u610F\u56FE\u8DEF\u7531\u5668\u3002\u6839\u636E\u7528\u6237\u6D88\u606F\uFF0C\u5224\u65AD\u5E94\u8BE5\u4EA4\u7ED9\u54EA\u4E2A agent \u5904\u7406\u3002
|
|
168
|
+
|
|
169
|
+
\u53EF\u9009 agent \u5217\u8868\uFF08agentKey \u4E0E\u63CF\u8FF0\uFF09\uFF1A
|
|
170
|
+
${agentList}
|
|
171
|
+
|
|
172
|
+
\u5224\u65AD\u539F\u5219\uFF08\u9ED8\u8BA4\u504F\u5411\u901A\u7528\u6863\u4F4D\uFF1B\u4E13\u804C agent \u5728\u660E\u786E\u5339\u914D\u65F6\u4F7F\u7528\uFF1B**\u7F16\u7801/\u672C\u5730\u4ED3\u5E93\u4EFB\u52A1\u8D70\u901A\u7528\u6863 + needsWorkspace=true**\uFF09\uFF1A
|
|
173
|
+
- \u9ED8\u8BA4\u60C5\u51B5\u4E0B\uFF0C**\u9664\u975E\u7528\u6237\u660E\u786E\u8868\u8FBE\u8981\u5EFA\u5E94\u7528/\u5EFA Agent/\u63D0\u4EA4\u53CD\u9988/\u591A Agent \u7F16\u6392**\uFF0C\u5426\u5219\u9009\u901A\u7528\u6863\u4F4D\uFF08flash/balanced/quality\uFF09\uFF1A
|
|
174
|
+
- \u7B80\u5355\u95EE\u5019\u3001\u95F2\u804A\u3001\u5FEB\u901F\u95EE\u7B54\u3001\u7FFB\u8BD1\u3001\u77ED\u6587 \u2192 \u9009 flash \u6863
|
|
175
|
+
- \u9700\u8981\u63A8\u7406\u3001\u5206\u6790\u3001\u4E2D\u7B49\u957F\u5EA6\u5199\u4F5C\u3001\u666E\u901A\u4EE3\u7801\u89E3\u91CA/\u67B6\u6784\u95EE\u7B54 \u2192 \u9009 balanced \u6863
|
|
176
|
+
- \u590D\u6742\u63A8\u7406\u3001\u957F\u6587\u3001\u67B6\u6784\u8BBE\u8BA1\u3001\u6DF1\u5EA6\u5206\u6790 \u2192 \u9009 quality \u6863
|
|
177
|
+
- **\u660E\u786E\u7F16\u7801\u4EFB\u52A1\uFF08\u5B9E\u73B0\u529F\u80FD\u3001\u4FEE bug\u3001refactor\u3001\u5199/\u8865\u6D4B\u8BD5\u3001\u8DD1 build/tests/ci\uFF09\u6216\u67E5\u770B\u672C\u673A\u4ED3\u5E93/\u4EE3\u7801\u72B6\u6001\uFF08git/\u5206\u652F/commit/\u672C\u5730\u4E0E\u8FDC\u7A0B\u5DEE\u8DDD/\u672A\u63D0\u4EA4\u6539\u52A8\u7B49\uFF09** \u2192 \u9009 balanced \u6216 quality \u6863\uFF08\u6309\u590D\u6742\u5EA6\uFF1B**\u4E0D\u8981\u9009 flash**\uFF09\uFF0C\u4E14 needsWorkspace=true
|
|
178
|
+
- \u4E13\u804C agent \u8DEF\u7531\u89C4\u5219\uFF08\u6709\u660E\u786E\u5339\u914D\u65F6\u4F7F\u7528\uFF09\uFF1A
|
|
179
|
+
- \u8981\u63D0\u4EA4/\u8BB0\u5F55 bug\u3001\u4F53\u9A8C\u95EE\u9898\u3001\u6570\u636E\u5F02\u5E38\u3001\u4EA7\u54C1\u5EFA\u8BAE\uFF0C\u6216\u53E3\u8BED\u5982\u300C\u60F3\u53CD\u9988\u4E00\u4E9B\u95EE\u9898\u300D\u300C\u53CD\u9988\u4E00\u4E0B\u300D\u2192 \u9009\u610F\u89C1\u53CD\u9988\u4E13\u804C agent
|
|
180
|
+
- \u8981\u65B0\u5EFA\u6216\u5B9A\u5236 AI/Agent/\u667A\u80FD\u4F53\u52A9\u624B\uFF08\u542B\u914D\u7F6E\u5DE5\u5177\u3001\u77E5\u8BC6\u3001\u786E\u8BA4\u521B\u5EFA\uFF09\u2192 \u9009\u521B\u5EFA Agent \u4E13\u804C agent
|
|
181
|
+
- \u8981\u505A/\u6539/\u53D1\u5E03\u7F51\u7AD9\u3001\u7F51\u9875\u3001\u5C0F\u5E94\u7528\u3001\u9884\u7EA6\u9875\u3001\u535A\u5BA2\u3001\u770B\u677F \u2192 \u9009\u5E94\u7528\u6784\u5EFA\u4E13\u804C agent
|
|
182
|
+
- \u8981\u6D3E\u591A\u4E2A agent\u3001\u591A agent \u5E76\u884C\u3001\u62C6\u6210\u4EFB\u52A1\u540E\u53F0\u6267\u884C\u3001\u591A\u4E2A agent review\u3001\u8BA9\u4E0D\u540C agent \u8BA8\u8BBA/\u4F1A\u5546 \u2192 \u9009\u591A Agent \u7F16\u6392\u4E13\u804C agent\uFF08\u663E\u5F0F multi-agent \u4F18\u5148\uFF09
|
|
183
|
+
- **\u62FF\u4E0D\u51C6\u65F6**\uFF1A\u7EAF\u95F2\u804A\u9009 flash\uFF1B**\u82E5\u6CBE\u8FB9\u672C\u5730\u4ED3\u5E93/\u5F53\u524D\u4EE3\u7801\u72B6\u6001\uFF0C\u9009 balanced/quality + needsWorkspace=true**\u3002
|
|
184
|
+
|
|
185
|
+
\u540C\u65F6\u5224\u65AD\u672C\u8F6E\u662F\u5426\u9700\u8981\u6CE8\u5165\u300C\u5DE5\u4F5C\u533A\u53EA\u8BFB\u5DE5\u5177\u300D\uFF08listFiles/globFiles/searchFiles/readFile/execShell \u7B49\uFF09\uFF1A
|
|
186
|
+
- needsWorkspace=true \u7684\u573A\u666F\uFF1A\u7528\u6237\u8981\u8BFB/\u6539/\u5206\u6790\u6587\u4EF6\u6216\u4EE3\u7801\u3001\u63D0\u5230\u4E86\u6587\u4EF6\u8DEF\u5F84/\u6269\u5C55\u540D\uFF08.md/.csv/.ts \u7B49\uFF09\u3001\u63D0\u5230\u5DE5\u4F5C\u533A/\u4EE3\u7801\u5E93/\u4ED3\u5E93/\u76EE\u5F55/git/\u5206\u652F\u3001\u8981\u770B\u5F53\u524D\u4EE3\u7801\u6216\u4ED3\u5E93\u72B6\u6001\u3001\u672C\u5730\u641C\u7D22/\u67E5\u770B\u4EE3\u7801\u3002
|
|
187
|
+
- needsWorkspace=false \u7684\u573A\u666F\uFF1A\u901A\u7528\u77E5\u8BC6\u95EE\u7B54\uFF08\u5982\u300C\u5E7F\u4E1C\u7ECF\u6D4E\u6570\u636E\u300D\u300C\u5199\u4E00\u9996\u8BD7\u300D\uFF09\u3001\u7EAF\u95F2\u804A\u95EE\u5019\u3001\u7FFB\u8BD1\u3001\u4E0D\u6D89\u53CA\u672C\u5730\u6587\u4EF6/\u4ED3\u5E93\u3002
|
|
188
|
+
- \u6F0F\u5224\uFF08\u7528\u6237\u8981\u6587\u4EF6\u800C\u6CA1\u5E26\u5DE5\u5177\uFF09\u6BD4\u8BEF\u5224\uFF08\u767D\u641C\u51E0\u8F6E\uFF09\u4EE3\u4EF7\u66F4\u9AD8\uFF0C\u5B81\u53EF\u504F\u5BBD\u5224 true\u3002
|
|
189
|
+
|
|
190
|
+
\u5728\u7ED9\u51FA agentKey \u4E4B\u524D\uFF0C\u5148\u5728\u5FC3\u91CC\u533A\u5206\u5019\u9009\u6863\u4F4D\u7684\u8FB9\u754C\u518D\u7ED9\u7F6E\u4FE1\u5EA6\uFF1Abalanced \u4E0E quality \u7684\u8FB9\u754C\u5728\u4E8E\u590D\u6742\u5EA6/\u7BC7\u5E45/\u662F\u5426\u9700\u8981\u6DF1\u5EA6\u5206\u6790\uFF0C\u62FF\u4E0D\u51C6\u5C31\u7ED9\u4F4E confidence\u3002
|
|
191
|
+
|
|
192
|
+
\u540C\u65F6\u5224\u65AD\u672C\u8F6E\u6D88\u606F\u662F\u5426\u9700\u8981\u6302\u8F7D\u5BF9\u8C61\u64CD\u4F5C\u6280\u80FD\uFF08skills \u6570\u7EC4\uFF0C\u672A\u547D\u4E2D\u7ED9 []\uFF09\uFF1A
|
|
193
|
+
- \u7528\u6237\u8981\u65B0\u5EFA/\u6574\u7406/\u5F55\u5165/\u6279\u91CF\u5904\u7406\u8868\u683C\u6570\u636E\uFF08\u5EFA\u8868\u3001\u52A0\u884C\u3001\u6539\u5217\u3001\u6309\u6761\u4EF6\u6574\u7406\u6570\u636E\uFF09\u2192 skills \u542B "table"
|
|
194
|
+
- \u7528\u6237\u8981\u5199/\u6DA6\u8272/\u6539\u5199/\u7EED\u5199/\u6392\u7248\u4E00\u7BC7\u6587\u6863\u6216\u6587\u7AE0 \u2192 skills \u542B "doc"
|
|
195
|
+
- \u7528\u6237\u8981\u5199/\u6539/\u5B9E\u73B0/\u4FEE bug/refactor/\u8865\u6D4B\u8BD5/\u5BA1\u67E5\u5E76\u4FEE\u6539\u4EE3\u7801 \u2192 skills \u542B "code"\uFF08\u4EC5\u95EE\u901A\u7528\u77E5\u8BC6\u3001\u7EAF\u95F2\u804A\u3001\u53EA\u67E5\u770B git/\u4ED3\u5E93\u72B6\u6001\u800C\u4E0D\u4FEE\u6539\u4EE3\u7801\u65F6\u4E0D\u6302 "code"\uFF09
|
|
196
|
+
- \u666E\u901A\u95EE\u7B54/\u7EAF\u95F2\u804A/\u5EFA\u5E94\u7528 \u2192 skills \u4E3A []
|
|
197
|
+
|
|
198
|
+
\u53EA\u8F93\u51FA JSON\uFF0C\u4E0D\u8981\u8F93\u51FA\u5176\u4ED6\u5185\u5BB9\uFF1A
|
|
199
|
+
{"confidence": <0\u52301\u4E4B\u95F4\u7684\u5C0F\u6570\uFF0C\u8868\u793A\u4F60\u5BF9\u8FD9\u4E2A\u5206\u7C7B\u5224\u65AD\u7684\u628A\u63E1\u7A0B\u5EA6>, "agentKey": "<\u4ECE\u5217\u8868\u4E2D\u9009\u62E9\u7684 agentKey>", "needsWorkspace": <true \u6216 false>, "skills": <\u5B57\u7B26\u4E32\u6570\u7EC4\uFF0C\u5143\u7D20\u53EA\u80FD\u662F "table" | "doc" | "code"\uFF0C\u672A\u547D\u4E2D\u7ED9 []>}`;
|
|
200
|
+
}
|
|
201
|
+
function parseQuickChatIntentResult(content, tierAgents) {
|
|
202
|
+
try {
|
|
203
|
+
const parsed = JSON.parse(content.trim());
|
|
204
|
+
if (typeof parsed !== "object" || parsed === null || !("agentKey" in parsed)) return null;
|
|
205
|
+
const key = parsed.agentKey;
|
|
206
|
+
if (typeof key !== "string") return null;
|
|
207
|
+
if (!tierAgents.some((t2) => t2.agentKey === key)) return null;
|
|
208
|
+
const rawNeedsWorkspace = parsed.needsWorkspace;
|
|
209
|
+
const needsWorkspace = rawNeedsWorkspace === true;
|
|
210
|
+
const rawConfidence = parsed.confidence;
|
|
211
|
+
const confidence = typeof rawConfidence === "number" && Number.isFinite(rawConfidence) && rawConfidence >= 0 && rawConfidence <= 1 ? rawConfidence : void 0;
|
|
212
|
+
const rawSkills = parsed.skills;
|
|
213
|
+
let skills;
|
|
214
|
+
if (Array.isArray(rawSkills)) {
|
|
215
|
+
const filtered = [...new Set(rawSkills)].filter(
|
|
216
|
+
(s) => s === "table" || s === "doc" || s === "code"
|
|
217
|
+
);
|
|
218
|
+
if (filtered.length > 0) skills = filtered;
|
|
219
|
+
}
|
|
220
|
+
return { agentKey: key, needsWorkspace, confidence, skills };
|
|
221
|
+
} catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// packages/cli/client/autoModelRouter.ts
|
|
227
|
+
var CLI_AUTO_TIER_AGENT_KEYS = {
|
|
228
|
+
flash: PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
|
|
229
|
+
balanced: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
|
|
230
|
+
quality: PUBLIC_GLM_52_AGENT_KEY
|
|
231
|
+
};
|
|
232
|
+
var CLI_AUTO_TIER_MODELS = {
|
|
233
|
+
flash: "deepseek-v4-flash",
|
|
234
|
+
balanced: "deepseek-v4-pro",
|
|
235
|
+
quality: "glm-5.2"
|
|
236
|
+
};
|
|
237
|
+
var CLI_IMAGE_AGENT_KEY = PUBLIC_KIMI_K26_IMAGE_AGENT_KEY;
|
|
238
|
+
var CLI_IMAGE_AGENT_MODEL = "kimi-k2.6";
|
|
239
|
+
var CLI_AUTO_TIER_AGENT_KEY_TABLE = {
|
|
240
|
+
[CLI_AUTO_TIER_AGENT_KEYS.flash]: true,
|
|
241
|
+
[CLI_AUTO_TIER_AGENT_KEYS.balanced]: true,
|
|
242
|
+
[CLI_AUTO_TIER_AGENT_KEYS.quality]: true
|
|
243
|
+
};
|
|
244
|
+
function resolveCliAutoAgentModel(agentKey) {
|
|
245
|
+
if (agentKey === CLI_AUTO_TIER_AGENT_KEYS.flash) return CLI_AUTO_TIER_MODELS.flash;
|
|
246
|
+
if (agentKey === CLI_AUTO_TIER_AGENT_KEYS.balanced) {
|
|
247
|
+
return CLI_AUTO_TIER_MODELS.balanced;
|
|
248
|
+
}
|
|
249
|
+
if (agentKey === CLI_AUTO_TIER_AGENT_KEYS.quality) {
|
|
250
|
+
return CLI_AUTO_TIER_MODELS.quality;
|
|
251
|
+
}
|
|
252
|
+
if (agentKey === CLI_IMAGE_AGENT_KEY) return CLI_IMAGE_AGENT_MODEL;
|
|
253
|
+
return void 0;
|
|
254
|
+
}
|
|
255
|
+
var buildRouteOptions = () => ["flash", "balanced", "quality"].map((tier) => ({
|
|
256
|
+
tier,
|
|
257
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS[tier],
|
|
258
|
+
description: TIER_DESCRIPTIONS[tier]
|
|
259
|
+
}));
|
|
260
|
+
var tierForAgentKey = (agentKey) => {
|
|
261
|
+
for (const tier of ["flash", "balanced", "quality"]) {
|
|
262
|
+
if (CLI_AUTO_TIER_AGENT_KEYS[tier] === agentKey) return tier;
|
|
263
|
+
}
|
|
264
|
+
return null;
|
|
265
|
+
};
|
|
266
|
+
function resolveCliAutoFallbackTier(text) {
|
|
267
|
+
switch (estimateComplexity(text)) {
|
|
268
|
+
case "complex":
|
|
269
|
+
return "quality";
|
|
270
|
+
case "medium":
|
|
271
|
+
return "balanced";
|
|
272
|
+
case "simple":
|
|
273
|
+
default:
|
|
274
|
+
return "flash";
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
async function classifyCliAutoRoute(text, options) {
|
|
278
|
+
const timeoutMs = options.timeoutMs ?? QUICK_CHAT_INTENT_TIMEOUT_MS;
|
|
279
|
+
const fallbackTier = resolveCliAutoFallbackTier(text);
|
|
280
|
+
const fallback = () => ({
|
|
281
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS[fallbackTier],
|
|
282
|
+
tier: fallbackTier,
|
|
283
|
+
classified: false
|
|
284
|
+
});
|
|
285
|
+
if (!text.trim()) return fallback();
|
|
286
|
+
if (isShortGreeting(text)) {
|
|
287
|
+
return {
|
|
288
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS.flash,
|
|
289
|
+
tier: "flash",
|
|
290
|
+
classified: true
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (!options.authToken) return fallback();
|
|
294
|
+
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
295
|
+
const controller = new AbortController();
|
|
296
|
+
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
|
|
297
|
+
try {
|
|
298
|
+
const routeOptions = buildRouteOptions();
|
|
299
|
+
const messages = [
|
|
300
|
+
{ role: "system", content: buildQuickChatIntentSystemPrompt(routeOptions) },
|
|
301
|
+
{ role: "user", content: text }
|
|
302
|
+
];
|
|
303
|
+
const { url, init } = buildPlatformChatCompletionRequest({
|
|
304
|
+
providerConfig: {
|
|
305
|
+
serverUrl: options.serverUrl,
|
|
306
|
+
authToken: options.authToken,
|
|
307
|
+
agentKey: CLI_AUTO_TIER_AGENT_KEYS.flash,
|
|
308
|
+
model: INTENT_MODEL,
|
|
309
|
+
provider: INTENT_PROVIDER,
|
|
310
|
+
endpoint: resolvePlatformChatCompletionsEndpoint(INTENT_PROVIDER) ?? "",
|
|
311
|
+
requestOptions: {}
|
|
312
|
+
},
|
|
313
|
+
messages,
|
|
314
|
+
stream: false
|
|
315
|
+
});
|
|
316
|
+
const response = await fetchImpl(url, {
|
|
317
|
+
...init,
|
|
318
|
+
signal: controller.signal
|
|
319
|
+
});
|
|
320
|
+
if (!response.ok) return fallback();
|
|
321
|
+
const data = parsePlatformChatCompletionData(await response.text());
|
|
322
|
+
const content = data?.choices?.[0]?.message?.content;
|
|
323
|
+
if (typeof content !== "string" || !content.trim()) return fallback();
|
|
324
|
+
const parsed = parseQuickChatIntentResult(content, routeOptions);
|
|
325
|
+
if (!parsed) return fallback();
|
|
326
|
+
const tier = tierForAgentKey(parsed.agentKey) ?? fallbackTier;
|
|
327
|
+
return {
|
|
328
|
+
agentKey: parsed.agentKey,
|
|
329
|
+
tier,
|
|
330
|
+
classified: true,
|
|
331
|
+
confidence: parsed.confidence,
|
|
332
|
+
needsWorkspace: parsed.needsWorkspace,
|
|
333
|
+
skills: parsed.skills
|
|
334
|
+
};
|
|
335
|
+
} catch {
|
|
336
|
+
return fallback();
|
|
337
|
+
} finally {
|
|
338
|
+
clearTimeout(timeoutHandle);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
133
342
|
// packages/cli/client/tokenUsage.ts
|
|
343
|
+
var isUsableModelId = (model) => {
|
|
344
|
+
const raw = model?.trim();
|
|
345
|
+
return Boolean(raw) && raw !== "-" && raw !== "auto";
|
|
346
|
+
};
|
|
347
|
+
function resolveAgentContextWindow(opts) {
|
|
348
|
+
if (isUsableModelId(opts.model)) {
|
|
349
|
+
return getModelContextWindow(opts.model);
|
|
350
|
+
}
|
|
351
|
+
const agentKey = opts.agentKey?.trim();
|
|
352
|
+
if (agentKey) {
|
|
353
|
+
const tierModel = resolveCliAutoAgentModel(agentKey);
|
|
354
|
+
if (tierModel) return getModelContextWindow(tierModel);
|
|
355
|
+
if (opts.autoRouteDefault !== false && agentKey === BUILTIN_NOLO_AGENT_KEY) {
|
|
356
|
+
return getModelContextWindow(CLI_AUTO_TIER_MODELS.flash);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (opts.agentName?.trim()) {
|
|
360
|
+
return getModelContextWindow(opts.agentName);
|
|
361
|
+
}
|
|
362
|
+
return DEFAULT_CONTEXT_WINDOW;
|
|
363
|
+
}
|
|
134
364
|
var PROVIDER_LOOKUP_ORDER = [
|
|
135
365
|
"openrouter",
|
|
136
366
|
"fireworks",
|
|
@@ -242,1151 +472,39 @@ function dimCliText(text, enabled = resolveCliColorEnabled()) {
|
|
|
242
472
|
return styleCliText(text, "dim", enabled);
|
|
243
473
|
}
|
|
244
474
|
|
|
245
|
-
// packages/cli/tui/
|
|
246
|
-
var
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
success: { hex: "3F8F5C", ansiFallback: "\x1B[32m" },
|
|
254
|
-
// moss green
|
|
255
|
-
warning: { hex: "9A6A1F", ansiFallback: "\x1B[33m" },
|
|
256
|
-
// deeper amber — B57F2E still read as yellow/washed on white (H2 headers like ## Plan floated); 9A6A1F raises contrast
|
|
257
|
-
info: { hex: "4A9FD4", ansiFallback: "\x1B[36m" },
|
|
258
|
-
// sky blue
|
|
259
|
-
danger: { hex: "C45C4A", ansiFallback: "\x1B[31m" },
|
|
260
|
-
// reddish
|
|
261
|
-
muted: { hex: "5E6A78", ansiFallback: "\x1B[90m" }
|
|
262
|
-
// denser slate — 687584 read too blue in dense prose (inline code/tool labels); 5E6A78 pulls blue down while staying darker than the old value
|
|
263
|
-
},
|
|
264
|
-
dark: {
|
|
265
|
-
accent: { hex: "89B4FA", ansiFallback: "\x1B[34m" },
|
|
266
|
-
// blue
|
|
267
|
-
chrome: { hex: "6C7086", ansiFallback: "\x1B[90m" },
|
|
268
|
-
success: { hex: "A6E3A1", ansiFallback: "\x1B[32m" },
|
|
269
|
-
warning: { hex: "F9E2AF", ansiFallback: "\x1B[33m" },
|
|
270
|
-
info: { hex: "94E2D5", ansiFallback: "\x1B[36m" },
|
|
271
|
-
danger: { hex: "F38BA8", ansiFallback: "\x1B[31m" },
|
|
272
|
-
muted: { hex: "9AA3B8", ansiFallback: "\x1B[90m" }
|
|
273
|
-
// dimmed from A6ADC8 so secondary text sits a step below body text
|
|
274
|
-
}
|
|
275
|
-
},
|
|
276
|
-
catppuccin: {
|
|
277
|
-
light: {
|
|
278
|
-
accent: { hex: "0969DA", ansiFallback: "\x1B[34m" },
|
|
279
|
-
chrome: { hex: "57606A", ansiFallback: "\x1B[90m" },
|
|
280
|
-
success: { hex: "116329", ansiFallback: "\x1B[32m" },
|
|
281
|
-
warning: { hex: "9A6700", ansiFallback: "\x1B[33m" },
|
|
282
|
-
info: { hex: "0969DA", ansiFallback: "\x1B[36m" },
|
|
283
|
-
danger: { hex: "CF222E", ansiFallback: "\x1B[31m" },
|
|
284
|
-
muted: { hex: "6E7781", ansiFallback: "\x1B[90m" }
|
|
285
|
-
},
|
|
286
|
-
dark: {
|
|
287
|
-
accent: { hex: "58A6FF", ansiFallback: "\x1B[34m" },
|
|
288
|
-
// GitHub sky blue
|
|
289
|
-
chrome: { hex: "6E7681", ansiFallback: "\x1B[90m" },
|
|
290
|
-
success: { hex: "3FB950", ansiFallback: "\x1B[32m" },
|
|
291
|
-
warning: { hex: "D29922", ansiFallback: "\x1B[33m" },
|
|
292
|
-
info: { hex: "58A6FF", ansiFallback: "\x1B[36m" },
|
|
293
|
-
danger: { hex: "FF7B72", ansiFallback: "\x1B[31m" },
|
|
294
|
-
muted: { hex: "B1BAC4", ansiFallback: "\x1B[90m" }
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
wave: {
|
|
298
|
-
light: {
|
|
299
|
-
accent: { hex: "4D699B", ansiFallback: "\x1B[34m" },
|
|
300
|
-
// ink blue
|
|
301
|
-
chrome: { hex: "9E9B8E", ansiFallback: "\x1B[90m" },
|
|
302
|
-
success: { hex: "6F894E", ansiFallback: "\x1B[32m" },
|
|
303
|
-
warning: { hex: "836F4A", ansiFallback: "\x1B[33m" },
|
|
304
|
-
info: { hex: "4D699B", ansiFallback: "\x1B[36m" },
|
|
305
|
-
danger: { hex: "C84053", ansiFallback: "\x1B[31m" },
|
|
306
|
-
muted: { hex: "716E61", ansiFallback: "\x1B[90m" }
|
|
307
|
-
},
|
|
308
|
-
dark: {
|
|
309
|
-
accent: { hex: "7E9CD8", ansiFallback: "\x1B[34m" },
|
|
310
|
-
// crystalBlue
|
|
311
|
-
chrome: { hex: "727169", ansiFallback: "\x1B[90m" },
|
|
312
|
-
success: { hex: "98BB6C", ansiFallback: "\x1B[32m" },
|
|
313
|
-
warning: { hex: "E6C384", ansiFallback: "\x1B[33m" },
|
|
314
|
-
info: { hex: "7FB4CA", ansiFallback: "\x1B[36m" },
|
|
315
|
-
danger: { hex: "E82424", ansiFallback: "\x1B[31m" },
|
|
316
|
-
muted: { hex: "938AA9", ansiFallback: "\x1B[90m" }
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
iris: {
|
|
320
|
-
light: {
|
|
321
|
-
accent: { hex: "5E6AD2", ansiFallback: "\x1B[34m" },
|
|
322
|
-
chrome: { hex: "9E9AB5", ansiFallback: "\x1B[90m" },
|
|
323
|
-
success: { hex: "16A34A", ansiFallback: "\x1B[32m" },
|
|
324
|
-
warning: { hex: "D97706", ansiFallback: "\x1B[33m" },
|
|
325
|
-
info: { hex: "5E6AD2", ansiFallback: "\x1B[36m" },
|
|
326
|
-
danger: { hex: "E5484D", ansiFallback: "\x1B[31m" },
|
|
327
|
-
muted: { hex: "6E6A8A", ansiFallback: "\x1B[90m" }
|
|
328
|
-
},
|
|
329
|
-
dark: {
|
|
330
|
-
accent: { hex: "8B9CF4", ansiFallback: "\x1B[34m" },
|
|
331
|
-
chrome: { hex: "5A5772", ansiFallback: "\x1B[90m" },
|
|
332
|
-
success: { hex: "26BD6C", ansiFallback: "\x1B[32m" },
|
|
333
|
-
warning: { hex: "F5A623", ansiFallback: "\x1B[33m" },
|
|
334
|
-
info: { hex: "8B9CF4", ansiFallback: "\x1B[36m" },
|
|
335
|
-
danger: { hex: "EC5B6E", ansiFallback: "\x1B[31m" },
|
|
336
|
-
muted: { hex: "938AA9", ansiFallback: "\x1B[90m" }
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
rose: {
|
|
340
|
-
light: {
|
|
341
|
-
accent: { hex: "D14D72", ansiFallback: "\x1B[35m" },
|
|
342
|
-
chrome: { hex: "9893A5", ansiFallback: "\x1B[90m" },
|
|
343
|
-
success: { hex: "56949F", ansiFallback: "\x1B[32m" },
|
|
344
|
-
warning: { hex: "EA9D34", ansiFallback: "\x1B[33m" },
|
|
345
|
-
info: { hex: "286983", ansiFallback: "\x1B[36m" },
|
|
346
|
-
danger: { hex: "B4637A", ansiFallback: "\x1B[31m" },
|
|
347
|
-
muted: { hex: "797593", ansiFallback: "\x1B[90m" }
|
|
348
|
-
},
|
|
349
|
-
dark: {
|
|
350
|
-
accent: { hex: "EB6F92", ansiFallback: "\x1B[35m" },
|
|
351
|
-
chrome: { hex: "6E6A86", ansiFallback: "\x1B[90m" },
|
|
352
|
-
success: { hex: "9CCFD8", ansiFallback: "\x1B[32m" },
|
|
353
|
-
warning: { hex: "F6C177", ansiFallback: "\x1B[33m" },
|
|
354
|
-
info: { hex: "C4A7E7", ansiFallback: "\x1B[36m" },
|
|
355
|
-
danger: { hex: "EB6F92", ansiFallback: "\x1B[31m" },
|
|
356
|
-
muted: { hex: "908CAA", ansiFallback: "\x1B[90m" }
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
mono: {
|
|
360
|
-
light: {
|
|
361
|
-
accent: { hex: "FF9500", ansiFallback: "\x1B[33m" },
|
|
362
|
-
chrome: { hex: "9DA6AF", ansiFallback: "\x1B[90m" },
|
|
363
|
-
success: { hex: "16A34A", ansiFallback: "\x1B[32m" },
|
|
364
|
-
warning: { hex: "D97706", ansiFallback: "\x1B[33m" },
|
|
365
|
-
info: { hex: "2563EB", ansiFallback: "\x1B[34m" },
|
|
366
|
-
danger: { hex: "DC2626", ansiFallback: "\x1B[31m" },
|
|
367
|
-
muted: { hex: "7B8793", ansiFallback: "\x1B[90m" }
|
|
368
|
-
},
|
|
369
|
-
dark: {
|
|
370
|
-
accent: { hex: "FFBF66", ansiFallback: "\x1B[33m" },
|
|
371
|
-
chrome: { hex: "7B8793", ansiFallback: "\x1B[90m" },
|
|
372
|
-
success: { hex: "4DE800", ansiFallback: "\x1B[32m" },
|
|
373
|
-
warning: { hex: "FCD34D", ansiFallback: "\x1B[33m" },
|
|
374
|
-
info: { hex: "60A5FA", ansiFallback: "\x1B[34m" },
|
|
375
|
-
danger: { hex: "F87171", ansiFallback: "\x1B[31m" },
|
|
376
|
-
muted: { hex: "C1C7CD", ansiFallback: "\x1B[90m" }
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
var activeThemeName = "catppuccin";
|
|
381
|
-
function getActiveThemeName() {
|
|
382
|
-
return activeThemeName;
|
|
383
|
-
}
|
|
384
|
-
function setActiveThemeName(name) {
|
|
385
|
-
if (THEME_PALETTES[name]) {
|
|
386
|
-
activeThemeName = name;
|
|
387
|
-
return true;
|
|
388
|
-
}
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
var activeBrightness = null;
|
|
392
|
-
function getActiveBrightness() {
|
|
393
|
-
return activeBrightness;
|
|
394
|
-
}
|
|
395
|
-
function setActiveBrightness(brightness) {
|
|
396
|
-
activeBrightness = brightness;
|
|
397
|
-
}
|
|
398
|
-
var activeDensity = "spacious";
|
|
399
|
-
function getActiveDensity() {
|
|
400
|
-
return activeDensity;
|
|
401
|
-
}
|
|
402
|
-
function setActiveDensity(density) {
|
|
403
|
-
activeDensity = density;
|
|
404
|
-
}
|
|
405
|
-
function supportsTruecolor(env = process.env) {
|
|
406
|
-
return /truecolor|24bit/i.test(env.COLORTERM ?? "");
|
|
475
|
+
// packages/cli/tui/i18n.ts
|
|
476
|
+
var ZH_PATTERNS = /^zh/i;
|
|
477
|
+
function parseCliLocale(raw) {
|
|
478
|
+
const normalized = raw?.trim().toLowerCase();
|
|
479
|
+
if (!normalized) return null;
|
|
480
|
+
if (ZH_PATTERNS.test(normalized)) return "zh";
|
|
481
|
+
if (normalized === "en" || normalized.startsWith("en")) return "en";
|
|
482
|
+
return null;
|
|
407
483
|
}
|
|
408
|
-
function
|
|
409
|
-
const explicit = (env.
|
|
410
|
-
if (explicit
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (!Number.isNaN(bg) && bg >= 0 && bg <= 6) return "dark";
|
|
418
|
-
if (!Number.isNaN(bg) && bg >= 7 && bg <= 15) return "light";
|
|
484
|
+
function detectLocaleFromEnv(env) {
|
|
485
|
+
const explicit = parseCliLocale(env.NOLO_LANG);
|
|
486
|
+
if (explicit) return explicit;
|
|
487
|
+
const candidates = [env.LC_ALL, env.LC_CTYPE, env.LANG].filter(Boolean);
|
|
488
|
+
for (const candidate of candidates) {
|
|
489
|
+
if (ZH_PATTERNS.test(candidate)) return "zh";
|
|
490
|
+
if (candidate && !candidate.startsWith("C.") && !candidate.startsWith("POSIX")) {
|
|
491
|
+
return "en";
|
|
492
|
+
}
|
|
419
493
|
}
|
|
420
|
-
return
|
|
421
|
-
}
|
|
422
|
-
function hexToSgr(hex) {
|
|
423
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
424
|
-
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
425
|
-
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
426
|
-
return `\x1B[38;2;${r};${g};${b}m`;
|
|
427
|
-
}
|
|
428
|
-
var SURFACE_HEX = {
|
|
429
|
-
trail: { light: "E4E8EC", dark: "313244" },
|
|
430
|
-
catppuccin: { light: "E8ECF0", dark: "161B22" },
|
|
431
|
-
wave: { light: "E5E1D6", dark: "2A2A37" },
|
|
432
|
-
iris: { light: "E9E8F2", dark: "2A2740" },
|
|
433
|
-
rose: { light: "F2EAE4", dark: "26233A" },
|
|
434
|
-
mono: { light: "E8EAED", dark: "2A2A2A" }
|
|
435
|
-
};
|
|
436
|
-
var TERMINAL_BASE = {
|
|
437
|
-
dark: "1E1E2E",
|
|
438
|
-
light: "FFFFFF"
|
|
439
|
-
};
|
|
440
|
-
function readHexChannels(hex) {
|
|
441
|
-
if (!/^[0-9A-F]{6}$/.test(hex)) return null;
|
|
442
|
-
return [
|
|
443
|
-
Number.parseInt(hex.slice(0, 2), 16),
|
|
444
|
-
Number.parseInt(hex.slice(2, 4), 16),
|
|
445
|
-
Number.parseInt(hex.slice(4, 6), 16)
|
|
446
|
-
];
|
|
447
|
-
}
|
|
448
|
-
function hexToBgSgr(hex) {
|
|
449
|
-
const channels = readHexChannels(hex.replace(/^#/, "").toUpperCase());
|
|
450
|
-
if (!channels) return "";
|
|
451
|
-
const [r, g, b] = channels;
|
|
452
|
-
return `\x1B[48;2;${r};${g};${b}m`;
|
|
494
|
+
return null;
|
|
453
495
|
}
|
|
454
|
-
function
|
|
455
|
-
|
|
456
|
-
const normFg = fg.replace(/^#/, "").toUpperCase();
|
|
457
|
-
const normBase = base.replace(/^#/, "").toUpperCase();
|
|
458
|
-
if (w === 0) return normBase;
|
|
459
|
-
if (w === 1) return normFg;
|
|
460
|
-
if (!readHexChannels(normFg) || !readHexChannels(normBase)) return normBase;
|
|
461
|
-
const fgR = Number.parseInt(normFg.slice(0, 2), 16);
|
|
462
|
-
const fgG = Number.parseInt(normFg.slice(2, 4), 16);
|
|
463
|
-
const fgB = Number.parseInt(normFg.slice(4, 6), 16);
|
|
464
|
-
const baseR = Number.parseInt(normBase.slice(0, 2), 16);
|
|
465
|
-
const baseG = Number.parseInt(normBase.slice(2, 4), 16);
|
|
466
|
-
const baseB = Number.parseInt(normBase.slice(4, 6), 16);
|
|
467
|
-
const r = Math.round(baseR + (fgR - baseR) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
468
|
-
const g = Math.round(baseG + (fgG - baseG) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
469
|
-
const b = Math.round(baseB + (fgB - baseB) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
470
|
-
return `${r}${g}${b}`;
|
|
496
|
+
function detectLocale(env) {
|
|
497
|
+
return detectLocaleFromEnv(env) ?? "zh";
|
|
471
498
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
const successHex = palette[brightness].success.hex;
|
|
476
|
-
const dangerHex = palette[brightness].danger.hex;
|
|
477
|
-
const weight = brightness === "dark" ? 0.14 : 0.1;
|
|
478
|
-
const baseHex = TERMINAL_BASE[brightness];
|
|
479
|
-
const addedBgHex = blendHex(successHex, baseHex, weight);
|
|
480
|
-
const removedBgHex = blendHex(dangerHex, baseHex, weight);
|
|
481
|
-
return {
|
|
482
|
-
added: {
|
|
483
|
-
fg: hexToSgr(successHex),
|
|
484
|
-
bg: hexToBgSgr(addedBgHex)
|
|
485
|
-
},
|
|
486
|
-
removed: {
|
|
487
|
-
fg: hexToSgr(dangerHex),
|
|
488
|
-
bg: hexToBgSgr(removedBgHex)
|
|
489
|
-
}
|
|
490
|
-
};
|
|
499
|
+
var currentLocale = detectLocale(process.env);
|
|
500
|
+
function getCliLocale() {
|
|
501
|
+
return currentLocale;
|
|
491
502
|
}
|
|
492
|
-
function
|
|
493
|
-
|
|
494
|
-
return hexToBgSgr((SURFACE_HEX[activeThemeName] ?? SURFACE_HEX.trail)[brightness]);
|
|
503
|
+
function setCliLocale(locale) {
|
|
504
|
+
currentLocale = locale;
|
|
495
505
|
}
|
|
496
|
-
function
|
|
497
|
-
|
|
498
|
-
const entry = palette[brightness][token];
|
|
499
|
-
return supportsTruecolor(env) ? hexToSgr(entry.hex) : entry.ansiFallback;
|
|
500
|
-
}
|
|
501
|
-
function themeText(text, token, colorEnabled = resolveCliColorEnabled(), env = process.env) {
|
|
502
|
-
if (!colorEnabled) return text;
|
|
503
|
-
return `${themeColorSequence(token, env)}${text}\x1B[39m`;
|
|
504
|
-
}
|
|
505
|
-
function renderDiffCodeBlock(code, env = process.env) {
|
|
506
|
-
const border = themeText("\u2502", "chrome", true, env);
|
|
507
|
-
const addedColor = themeColorSequence("success", env);
|
|
508
|
-
const deletedColor = themeColorSequence("danger", env);
|
|
509
|
-
const hunkColor = themeColorSequence("info", env);
|
|
510
|
-
const contextColor = themeColorSequence("chrome", env);
|
|
511
|
-
const reset = "\x1B[0m";
|
|
512
|
-
const lines = code.split("\n").map((line) => {
|
|
513
|
-
let color = contextColor;
|
|
514
|
-
if (line.startsWith("@@")) {
|
|
515
|
-
color = hunkColor;
|
|
516
|
-
} else if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
517
|
-
color = addedColor;
|
|
518
|
-
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
519
|
-
color = deletedColor;
|
|
520
|
-
}
|
|
521
|
-
return ` ${border} ${color}${line}${reset}`;
|
|
522
|
-
});
|
|
523
|
-
return ` ${themeText("\u250C\u2500\u2500\u2500", "chrome", true, env)}
|
|
524
|
-
${lines.join("\n")}
|
|
525
|
-
${themeText("\u2514\u2500\u2500\u2500", "chrome", true, env)}`;
|
|
526
|
-
}
|
|
527
|
-
function highlightMarkdown(text, colorEnabled = resolveCliColorEnabled(), env = process.env) {
|
|
528
|
-
if (!colorEnabled) return text;
|
|
529
|
-
let result = text;
|
|
530
|
-
result = result.replace(/```([a-zA-Z-]*)\n([\s\S]*?)\n```/g, (match, lang, code) => {
|
|
531
|
-
if (lang.toLowerCase() === "diff") {
|
|
532
|
-
return renderDiffCodeBlock(code, env);
|
|
533
|
-
}
|
|
534
|
-
const infoColor = themeColorSequence("info", env);
|
|
535
|
-
const reset2 = "\x1B[39m\x1B[22m";
|
|
536
|
-
const border = themeText("\u2502", "chrome", true, env);
|
|
537
|
-
const formattedCode = code.split("\n").map((line) => ` ${border} ${infoColor}${line}${reset2}`).join("\n");
|
|
538
|
-
return ` ${themeText("\u250C\u2500\u2500\u2500", "chrome", true, env)}
|
|
539
|
-
${formattedCode}
|
|
540
|
-
${themeText("\u2514\u2500\u2500\u2500", "chrome", true, env)}`;
|
|
541
|
-
});
|
|
542
|
-
result = result.replace(/^(#{1,3})\s+(.+)$/gm, (match, hashes, title) => {
|
|
543
|
-
const level = hashes.length;
|
|
544
|
-
const reset2 = "\x1B[0m";
|
|
545
|
-
if (level === 1) {
|
|
546
|
-
return `\x1B[1m\x1B[4m${themeColorSequence("accent", env)}${title}${reset2}`;
|
|
547
|
-
}
|
|
548
|
-
if (level === 2) {
|
|
549
|
-
return `\x1B[1m${themeColorSequence("warning", env)}${title}${reset2}`;
|
|
550
|
-
}
|
|
551
|
-
return `\x1B[1m${themeColorSequence("info", env)}${title}${reset2}`;
|
|
552
|
-
});
|
|
553
|
-
result = result.replace(
|
|
554
|
-
/^(进入 nolo-plan[^\n]*)$/gm,
|
|
555
|
-
(match, content) => `${themeColorSequence("chrome", env)}\x1B[2m${content}\x1B[0m`
|
|
556
|
-
);
|
|
557
|
-
result = result.replace(/^>\s?(.*)$/gm, (match, content) => {
|
|
558
|
-
const border = themeColorSequence("chrome", env);
|
|
559
|
-
return `${border}\u2502\x1B[39m \x1B[2m${content}\x1B[22m`;
|
|
560
|
-
});
|
|
561
|
-
result = result.replace(/\*\*([\s\S]*?)\*\*/g, "\x1B[1m$1\x1B[22m");
|
|
562
|
-
const mutedColor = themeColorSequence("muted", env);
|
|
563
|
-
const reset = "\x1B[39m";
|
|
564
|
-
result = result.replace(/`([^`\n]+)`/g, `${mutedColor}$1${reset}`);
|
|
565
|
-
result = result.replace(/(?<!\*)\*([^*\n]+?)\*(?!\*)/g, `\x1B[2m$1\x1B[22m`);
|
|
566
|
-
result = result.replace(/~~([^~\n]+?)~~/g, `\x1B[2m\x1B[9m$1\x1B[29m\x1B[22m`);
|
|
567
|
-
return result;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// packages/cli/client/assistantOutput.ts
|
|
571
|
-
var STYLE = {
|
|
572
|
-
reset: "\x1B[0m",
|
|
573
|
-
bold: "\x1B[1m",
|
|
574
|
-
dim: "\x1B[2m"
|
|
575
|
-
};
|
|
576
|
-
function colorSeq(token, brightness) {
|
|
577
|
-
return themeColorSequence(token, process.env, brightness);
|
|
578
|
-
}
|
|
579
|
-
function splitTableCells(line) {
|
|
580
|
-
const trimmed = line.trim();
|
|
581
|
-
if (!trimmed.includes("|")) return [];
|
|
582
|
-
const core = trimmed.replace(/^\|/, "").replace(/\|$/, "");
|
|
583
|
-
return core.split("|").map((cell) => cell.trim()).filter(Boolean);
|
|
584
|
-
}
|
|
585
|
-
function isTableSeparator(line) {
|
|
586
|
-
const cells = splitTableCells(line);
|
|
587
|
-
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
588
|
-
}
|
|
589
|
-
function isTableRow(line) {
|
|
590
|
-
const cells = splitTableCells(line);
|
|
591
|
-
return cells.length >= 2 && cells.some((cell) => cell.length > 0);
|
|
592
|
-
}
|
|
593
|
-
function isPipeWrappedTableRow(line) {
|
|
594
|
-
const trimmed = line.trim();
|
|
595
|
-
return trimmed.startsWith("|") && trimmed.endsWith("|") && isTableRow(line);
|
|
596
|
-
}
|
|
597
|
-
function isCodeFenceLine(line) {
|
|
598
|
-
return /^\s*```/.test(line);
|
|
599
|
-
}
|
|
600
|
-
function readFenceLanguage(line) {
|
|
601
|
-
const m = line.match(/^\s*```\s*([a-zA-Z0-9+#_-]*)/);
|
|
602
|
-
return m ? (m[1] ?? "").toLowerCase() : "";
|
|
603
|
-
}
|
|
604
|
-
function normalizeCodeLang(raw) {
|
|
605
|
-
switch (raw) {
|
|
606
|
-
case "js":
|
|
607
|
-
case "jsx":
|
|
608
|
-
case "ts":
|
|
609
|
-
case "tsx":
|
|
610
|
-
case "javascript":
|
|
611
|
-
case "typescript":
|
|
612
|
-
return "js";
|
|
613
|
-
case "py":
|
|
614
|
-
case "python":
|
|
615
|
-
return "py";
|
|
616
|
-
case "sh":
|
|
617
|
-
case "bash":
|
|
618
|
-
case "zsh":
|
|
619
|
-
case "shell":
|
|
620
|
-
case "console":
|
|
621
|
-
return "sh";
|
|
622
|
-
case "json":
|
|
623
|
-
return "json";
|
|
624
|
-
case "diff":
|
|
625
|
-
return "diff";
|
|
626
|
-
default:
|
|
627
|
-
return "unknown";
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
var KEYWORDS = {
|
|
631
|
-
js: /* @__PURE__ */ new Set([
|
|
632
|
-
"const",
|
|
633
|
-
"let",
|
|
634
|
-
"var",
|
|
635
|
-
"function",
|
|
636
|
-
"return",
|
|
637
|
-
"if",
|
|
638
|
-
"else",
|
|
639
|
-
"for",
|
|
640
|
-
"while",
|
|
641
|
-
"class",
|
|
642
|
-
"new",
|
|
643
|
-
"await",
|
|
644
|
-
"async",
|
|
645
|
-
"import",
|
|
646
|
-
"export",
|
|
647
|
-
"from",
|
|
648
|
-
"type",
|
|
649
|
-
"interface",
|
|
650
|
-
"extends",
|
|
651
|
-
"implements",
|
|
652
|
-
"null",
|
|
653
|
-
"undefined",
|
|
654
|
-
"true",
|
|
655
|
-
"false"
|
|
656
|
-
]),
|
|
657
|
-
py: /* @__PURE__ */ new Set([
|
|
658
|
-
"def",
|
|
659
|
-
"class",
|
|
660
|
-
"return",
|
|
661
|
-
"if",
|
|
662
|
-
"elif",
|
|
663
|
-
"else",
|
|
664
|
-
"for",
|
|
665
|
-
"while",
|
|
666
|
-
"import",
|
|
667
|
-
"from",
|
|
668
|
-
"as",
|
|
669
|
-
"with",
|
|
670
|
-
"try",
|
|
671
|
-
"except",
|
|
672
|
-
"finally",
|
|
673
|
-
"lambda",
|
|
674
|
-
"None",
|
|
675
|
-
"True",
|
|
676
|
-
"False",
|
|
677
|
-
"self"
|
|
678
|
-
]),
|
|
679
|
-
sh: /* @__PURE__ */ new Set([
|
|
680
|
-
"if",
|
|
681
|
-
"then",
|
|
682
|
-
"else",
|
|
683
|
-
"fi",
|
|
684
|
-
"for",
|
|
685
|
-
"do",
|
|
686
|
-
"done",
|
|
687
|
-
"while",
|
|
688
|
-
"case",
|
|
689
|
-
"esac",
|
|
690
|
-
"function",
|
|
691
|
-
"export",
|
|
692
|
-
"local",
|
|
693
|
-
"return",
|
|
694
|
-
"source",
|
|
695
|
-
"echo",
|
|
696
|
-
"cd"
|
|
697
|
-
]),
|
|
698
|
-
json: /* @__PURE__ */ new Set(["true", "false", "null"]),
|
|
699
|
-
diff: /* @__PURE__ */ new Set([])
|
|
700
|
-
};
|
|
701
|
-
function scanStringCommentRegions(line, lang) {
|
|
702
|
-
const regions = [];
|
|
703
|
-
const n = line.length;
|
|
704
|
-
let i = 0;
|
|
705
|
-
const commentMarkers = lang === "py" || lang === "sh" ? ["#"] : ["//"];
|
|
706
|
-
while (i < n) {
|
|
707
|
-
const ch = line[i];
|
|
708
|
-
if (ch === "'" || ch === '"' || lang === "js" && ch === "`") {
|
|
709
|
-
const quote = ch;
|
|
710
|
-
const start = i;
|
|
711
|
-
i += 1;
|
|
712
|
-
while (i < n) {
|
|
713
|
-
if (line[i] === "\\") {
|
|
714
|
-
i += 2;
|
|
715
|
-
continue;
|
|
716
|
-
}
|
|
717
|
-
if (line[i] === quote) {
|
|
718
|
-
i += 1;
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
i += 1;
|
|
722
|
-
}
|
|
723
|
-
regions.push({ start, end: i, kind: "string" });
|
|
724
|
-
continue;
|
|
725
|
-
}
|
|
726
|
-
let matched = false;
|
|
727
|
-
for (const marker of commentMarkers) {
|
|
728
|
-
if (line.startsWith(marker, i)) {
|
|
729
|
-
regions.push({ start: i, end: n, kind: "comment" });
|
|
730
|
-
i = n;
|
|
731
|
-
matched = true;
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
if (matched) continue;
|
|
736
|
-
i += 1;
|
|
737
|
-
}
|
|
738
|
-
return regions;
|
|
739
|
-
}
|
|
740
|
-
function highlightCodeLine(line, lang, brightness) {
|
|
741
|
-
const info = colorSeq("info", brightness);
|
|
742
|
-
if (lang === "unknown") {
|
|
743
|
-
return `${info}${line}${STYLE.reset}`;
|
|
744
|
-
}
|
|
745
|
-
if (lang === "diff") {
|
|
746
|
-
const added = colorSeq("success", brightness);
|
|
747
|
-
const deleted = colorSeq("danger", brightness);
|
|
748
|
-
const hunk = colorSeq("info", brightness);
|
|
749
|
-
const context = colorSeq("chrome", brightness);
|
|
750
|
-
const reset2 = STYLE.reset;
|
|
751
|
-
let color = context;
|
|
752
|
-
if (line.startsWith("@@")) {
|
|
753
|
-
color = hunk;
|
|
754
|
-
} else if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
755
|
-
color = added;
|
|
756
|
-
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
757
|
-
color = deleted;
|
|
758
|
-
}
|
|
759
|
-
return `${color}${line}${reset2}`;
|
|
760
|
-
}
|
|
761
|
-
const regions = scanStringCommentRegions(line, lang);
|
|
762
|
-
const keywords = KEYWORDS[lang];
|
|
763
|
-
const accent = colorSeq("accent", brightness);
|
|
764
|
-
const success = colorSeq("success", brightness);
|
|
765
|
-
const warning = colorSeq("warning", brightness);
|
|
766
|
-
const chrome = colorSeq("chrome", brightness);
|
|
767
|
-
const dim = STYLE.dim;
|
|
768
|
-
const reset = STYLE.reset;
|
|
769
|
-
const out = [];
|
|
770
|
-
let cursor = 0;
|
|
771
|
-
for (const region of regions) {
|
|
772
|
-
if (region.start > cursor) {
|
|
773
|
-
out.push(emitPlainGap(line.slice(cursor, region.start), keywords, info, accent, warning, reset));
|
|
774
|
-
}
|
|
775
|
-
const text = line.slice(region.start, region.end);
|
|
776
|
-
if (region.kind === "string") {
|
|
777
|
-
out.push(`${success}${text}${reset}`);
|
|
778
|
-
} else {
|
|
779
|
-
out.push(`${chrome}${dim}${text}${reset}`);
|
|
780
|
-
}
|
|
781
|
-
cursor = region.end;
|
|
782
|
-
}
|
|
783
|
-
if (cursor < line.length) {
|
|
784
|
-
out.push(emitPlainGap(line.slice(cursor), keywords, info, accent, warning, reset));
|
|
785
|
-
}
|
|
786
|
-
return out.join("");
|
|
787
|
-
}
|
|
788
|
-
function emitPlainGap(text, keywords, info, accent, warning, reset) {
|
|
789
|
-
const parts = [];
|
|
790
|
-
const re = /([A-Za-z_]\w*)|(\d+(?:\.\d+)?)|([\s\S])/g;
|
|
791
|
-
let last = 0;
|
|
792
|
-
let m;
|
|
793
|
-
let started = false;
|
|
794
|
-
while ((m = re.exec(text)) !== null) {
|
|
795
|
-
if (!started) {
|
|
796
|
-
started = true;
|
|
797
|
-
}
|
|
798
|
-
if (m.index > last) {
|
|
799
|
-
parts.push(`${info}${text.slice(last, m.index)}`);
|
|
800
|
-
}
|
|
801
|
-
if (m[1] !== void 0) {
|
|
802
|
-
const word = m[1];
|
|
803
|
-
if (keywords.has(word)) {
|
|
804
|
-
parts.push(`${accent}${word}${reset}`);
|
|
805
|
-
} else {
|
|
806
|
-
parts.push(`${info}${word}`);
|
|
807
|
-
}
|
|
808
|
-
} else if (m[2] !== void 0) {
|
|
809
|
-
parts.push(`${warning}${m[2]}${reset}`);
|
|
810
|
-
} else {
|
|
811
|
-
parts.push(`${info}${m[3]}`);
|
|
812
|
-
}
|
|
813
|
-
last = re.lastIndex;
|
|
814
|
-
}
|
|
815
|
-
if (last < text.length) {
|
|
816
|
-
parts.push(`${info}${text.slice(last)}`);
|
|
817
|
-
}
|
|
818
|
-
return parts.join("");
|
|
819
|
-
}
|
|
820
|
-
function tableRowToBullet(line) {
|
|
821
|
-
const row = splitTableCells(line);
|
|
822
|
-
const label = row[0] ?? "";
|
|
823
|
-
const detail = row.slice(1).join(" \u2014 ").trim();
|
|
824
|
-
return detail ? ` \u2022 ${label} \u2014 ${detail}` : ` \u2022 ${label}`;
|
|
825
|
-
}
|
|
826
|
-
var UNORDERED_LIST_RE = /^(\s*)([-*+])\s+(.+)$/;
|
|
827
|
-
var ORDERED_LIST_RE = /^(\s*)(\d+)\.\s+(.+)$/;
|
|
828
|
-
var TASK_LIST_RE = /^(\s*)([-*+])\s+\[([ xX])\]\s+(.+)$/;
|
|
829
|
-
function normalizeListLine(line) {
|
|
830
|
-
const task = line.match(TASK_LIST_RE);
|
|
831
|
-
if (task) {
|
|
832
|
-
const checked = task[3] === "x" || task[3] === "X";
|
|
833
|
-
return `${task[1]}${checked ? "\u2611" : "\u2610"} ${task[4]}`;
|
|
834
|
-
}
|
|
835
|
-
const unordered = line.match(UNORDERED_LIST_RE);
|
|
836
|
-
if (unordered) {
|
|
837
|
-
return `${unordered[1]}\u2022 ${unordered[3]}`;
|
|
838
|
-
}
|
|
839
|
-
const ordered = line.match(ORDERED_LIST_RE);
|
|
840
|
-
if (ordered) {
|
|
841
|
-
return `${ordered[1]}${ordered[2]}. ${ordered[3]}`;
|
|
842
|
-
}
|
|
843
|
-
return line;
|
|
844
|
-
}
|
|
845
|
-
function convertMarkdownTablesForTerminal(text) {
|
|
846
|
-
const lines = text.split("\n");
|
|
847
|
-
const out = [];
|
|
848
|
-
let inFence = false;
|
|
849
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
850
|
-
const line = lines[index] ?? "";
|
|
851
|
-
if (isCodeFenceLine(line)) {
|
|
852
|
-
inFence = !inFence;
|
|
853
|
-
out.push(line);
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
|
-
if (inFence) {
|
|
857
|
-
out.push(line);
|
|
858
|
-
continue;
|
|
859
|
-
}
|
|
860
|
-
const next = lines[index + 1] ?? "";
|
|
861
|
-
if (isTableRow(line) && isTableSeparator(next)) {
|
|
862
|
-
index += 1;
|
|
863
|
-
while (index + 1 < lines.length && isTableRow(lines[index + 1] ?? "") && !isTableSeparator(lines[index + 1] ?? "")) {
|
|
864
|
-
index += 1;
|
|
865
|
-
out.push(tableRowToBullet(lines[index] ?? ""));
|
|
866
|
-
}
|
|
867
|
-
if (out.length > 0 && out[out.length - 1] !== "") out.push("");
|
|
868
|
-
continue;
|
|
869
|
-
}
|
|
870
|
-
if (isPipeWrappedTableRow(line)) {
|
|
871
|
-
if (!isTableSeparator(line)) out.push(tableRowToBullet(line));
|
|
872
|
-
continue;
|
|
873
|
-
}
|
|
874
|
-
out.push(normalizeListLine(line));
|
|
875
|
-
}
|
|
876
|
-
return out.join("\n");
|
|
877
|
-
}
|
|
878
|
-
function polishAssistantStructure(text, options = {}) {
|
|
879
|
-
const converted = convertMarkdownTablesForTerminal(text).replace(/\r\n/g, "\n").replace(/\x00/g, "");
|
|
880
|
-
const lines = converted.split("\n");
|
|
881
|
-
let inFence = false;
|
|
882
|
-
const maskedLines = lines.map((line, index) => {
|
|
883
|
-
if (isCodeFenceLine(line)) {
|
|
884
|
-
inFence = !inFence;
|
|
885
|
-
return line;
|
|
886
|
-
}
|
|
887
|
-
if (inFence) {
|
|
888
|
-
return `\0F${index}\0`;
|
|
889
|
-
}
|
|
890
|
-
return line;
|
|
891
|
-
});
|
|
892
|
-
const afterHeading = maskedLines.join("\n").replace(/([^\n])\n(#{1,3} )/g, "$1\n\n$2").replace(/^(#{1,3} .+)\n(?!\n)/gm, "$1\n\n").replace(/\n{4,}/g, "\n\n\n");
|
|
893
|
-
const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]/;
|
|
894
|
-
const headingLines = afterHeading.split("\n");
|
|
895
|
-
const breathed = [];
|
|
896
|
-
for (let i = 0; i < headingLines.length; i++) {
|
|
897
|
-
breathed.push(headingLines[i]);
|
|
898
|
-
const cur = headingLines[i];
|
|
899
|
-
const next = headingLines[i + 1];
|
|
900
|
-
if (cur === "" || next === void 0 || next === "") continue;
|
|
901
|
-
if (LIST_LIKE.test(cur) === LIST_LIKE.test(next)) continue;
|
|
902
|
-
breathed.push("");
|
|
903
|
-
}
|
|
904
|
-
const polishedMasked = breathed.join("\n");
|
|
905
|
-
const polished = polishedMasked.replace(
|
|
906
|
-
/\x00F(\d+)\x00/g,
|
|
907
|
-
(_, id) => lines[Number(id)] ?? ""
|
|
908
|
-
);
|
|
909
|
-
return options.trimEdges === false ? polished : polished.trim();
|
|
910
|
-
}
|
|
911
|
-
function renderMarkdownLink(match, text, url) {
|
|
912
|
-
const visible = `${text} (${url})`;
|
|
913
|
-
return `\x1B]8;;${url}\x1B\\${visible}\x1B]8;;\x1B\\`;
|
|
914
|
-
}
|
|
915
|
-
var MARKDOWN_LINK_RE = /\[([^\]]+)\]\(([^)\s]+)\)/g;
|
|
916
|
-
function styleInlineMarkdown(line, brightness) {
|
|
917
|
-
const inlineCode = colorSeq("muted", brightness);
|
|
918
|
-
const reset = STYLE.reset;
|
|
919
|
-
const bold = STYLE.bold;
|
|
920
|
-
const dim = STYLE.dim;
|
|
921
|
-
return line.replace(MARKDOWN_LINK_RE, (m, t2, u) => renderMarkdownLink(m, t2, u)).replace(/`([^`]+)`/g, `${inlineCode}$1${reset}`).replace(/\*\*(.+?)\*\*/g, `${bold}$1${reset}`).replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, `${dim}$1${reset}`).replace(/~~([^~]+?)~~/g, `${dim}\x1B[9m$1\x1B[29m${reset}`);
|
|
922
|
-
}
|
|
923
|
-
function styleRichMarkdownLine(line, brightness) {
|
|
924
|
-
const heading = line.match(/^(#{1,3})\s+(.+)$/);
|
|
925
|
-
if (heading) {
|
|
926
|
-
const level = heading[1].length;
|
|
927
|
-
const title = heading[2];
|
|
928
|
-
if (level === 1) {
|
|
929
|
-
return `${STYLE.bold}\x1B[4m${colorSeq("accent", brightness)}${title}${STYLE.reset}`;
|
|
930
|
-
}
|
|
931
|
-
if (level === 2) {
|
|
932
|
-
return `${STYLE.bold}${colorSeq("warning", brightness)}${title}${STYLE.reset}`;
|
|
933
|
-
}
|
|
934
|
-
return `${STYLE.bold}${colorSeq("info", brightness)}${title}${STYLE.reset}`;
|
|
935
|
-
}
|
|
936
|
-
if (line.startsWith("\u8FDB\u5165 nolo-plan")) {
|
|
937
|
-
return `${colorSeq("chrome", brightness)}${STYLE.dim}${line}${STYLE.reset}`;
|
|
938
|
-
}
|
|
939
|
-
const blockquote = line.match(/^>\s?(.*)$/);
|
|
940
|
-
if (blockquote) {
|
|
941
|
-
const border = colorSeq("chrome", brightness);
|
|
942
|
-
const content = blockquote[1];
|
|
943
|
-
return `${border}\u2502${STYLE.reset} ${STYLE.dim}${content}${STYLE.reset}`;
|
|
944
|
-
}
|
|
945
|
-
if (/^---+$/.test(line.trim())) {
|
|
946
|
-
return `${colorSeq("chrome", brightness)}${"\u2500".repeat(Math.min(line.trim().length, 40))}${STYLE.reset}`;
|
|
947
|
-
}
|
|
948
|
-
const bullet = line.match(/^(\s*)(•)\s(.+)$/);
|
|
949
|
-
if (bullet) {
|
|
950
|
-
const styled = styleInlineMarkdown(bullet[3], brightness);
|
|
951
|
-
return `${bullet[1]}${colorSeq("accent", brightness)}\u2022${STYLE.reset} ${styled}`;
|
|
952
|
-
}
|
|
953
|
-
const ordered = line.match(/^(\s*)(\d+\.)\s(.+)$/);
|
|
954
|
-
if (ordered) {
|
|
955
|
-
const styled = styleInlineMarkdown(ordered[3], brightness);
|
|
956
|
-
return `${ordered[1]}${colorSeq("accent", brightness)}${ordered[2]}${STYLE.reset} ${styled}`;
|
|
957
|
-
}
|
|
958
|
-
const task = line.match(/^(\s*)(☐|☑)\s(.+)$/);
|
|
959
|
-
if (task) {
|
|
960
|
-
const styled = styleInlineMarkdown(task[3], brightness);
|
|
961
|
-
return `${task[1]}${colorSeq("accent", brightness)}${task[2]}${STYLE.reset} ${styled}`;
|
|
962
|
-
}
|
|
963
|
-
return styleInlineMarkdown(line, brightness);
|
|
964
|
-
}
|
|
965
|
-
function formatAssistantDisplay(text, options = {}) {
|
|
966
|
-
const brightness = resolveTuiBrightness();
|
|
967
|
-
const polished = polishAssistantStructure(text, options);
|
|
968
|
-
let inFence = false;
|
|
969
|
-
let fenceLang = "unknown";
|
|
970
|
-
return polished.split("\n").map((line) => {
|
|
971
|
-
if (isCodeFenceLine(line)) {
|
|
972
|
-
if (inFence) {
|
|
973
|
-
fenceLang = "unknown";
|
|
974
|
-
} else {
|
|
975
|
-
fenceLang = normalizeCodeLang(readFenceLanguage(line));
|
|
976
|
-
}
|
|
977
|
-
inFence = !inFence;
|
|
978
|
-
return `${STYLE.dim}${line}${STYLE.reset}`;
|
|
979
|
-
}
|
|
980
|
-
if (inFence) {
|
|
981
|
-
return highlightCodeLine(line, fenceLang, brightness);
|
|
982
|
-
}
|
|
983
|
-
return styleRichMarkdownLine(line, brightness);
|
|
984
|
-
}).join("\n");
|
|
985
|
-
}
|
|
986
|
-
function emitFormattedAssistantBlock(write, text, trailingNewline = false) {
|
|
987
|
-
if (!text) return;
|
|
988
|
-
write(formatAssistantDisplay(text, { trimEdges: false }));
|
|
989
|
-
if (trailingNewline) write("\n");
|
|
990
|
-
}
|
|
991
|
-
function classifyStreamLine(line) {
|
|
992
|
-
if (line === "") return "blank";
|
|
993
|
-
if (TASK_LIST_RE.test(line) || UNORDERED_LIST_RE.test(line) || ORDERED_LIST_RE.test(line) || /^\s*(?:•|☐|☑)\s/.test(line) || /^\s*[\u2460-\u2473]/.test(line)) {
|
|
994
|
-
return "list";
|
|
995
|
-
}
|
|
996
|
-
return "prose";
|
|
997
|
-
}
|
|
998
|
-
function needsListProseBreath(prev, next) {
|
|
999
|
-
if (prev === null || prev === "blank" || next === "blank") return false;
|
|
1000
|
-
const prevList = prev === "list";
|
|
1001
|
-
const nextList = next === "list";
|
|
1002
|
-
return prevList !== nextList;
|
|
1003
|
-
}
|
|
1004
|
-
function createRenderAwareStreamWriter(args) {
|
|
1005
|
-
const brightness = resolveTuiBrightness();
|
|
1006
|
-
let buffer = "";
|
|
1007
|
-
let inFence = false;
|
|
1008
|
-
let fenceLang = "unknown";
|
|
1009
|
-
let lastKind = null;
|
|
1010
|
-
const emitBreathIfNeeded = (nextKind) => {
|
|
1011
|
-
if (needsListProseBreath(lastKind, nextKind)) args.write("\n");
|
|
1012
|
-
};
|
|
1013
|
-
const flushCompleteBlocks = () => {
|
|
1014
|
-
while (buffer.includes("\n")) {
|
|
1015
|
-
const lines = buffer.split("\n");
|
|
1016
|
-
if (lines.length < 2) break;
|
|
1017
|
-
const firstLine = lines[0] ?? "";
|
|
1018
|
-
if (isCodeFenceLine(firstLine)) {
|
|
1019
|
-
if (inFence) {
|
|
1020
|
-
fenceLang = "unknown";
|
|
1021
|
-
} else {
|
|
1022
|
-
fenceLang = normalizeCodeLang(readFenceLanguage(firstLine));
|
|
1023
|
-
}
|
|
1024
|
-
inFence = !inFence;
|
|
1025
|
-
emitBreathIfNeeded("other");
|
|
1026
|
-
args.write(`${STYLE.dim}${firstLine}${STYLE.reset}
|
|
1027
|
-
`);
|
|
1028
|
-
lastKind = "other";
|
|
1029
|
-
buffer = lines.slice(1).join("\n");
|
|
1030
|
-
continue;
|
|
1031
|
-
}
|
|
1032
|
-
if (inFence) {
|
|
1033
|
-
args.write(`${highlightCodeLine(firstLine, fenceLang, brightness)}
|
|
1034
|
-
`);
|
|
1035
|
-
lastKind = "other";
|
|
1036
|
-
buffer = lines.slice(1).join("\n");
|
|
1037
|
-
continue;
|
|
1038
|
-
}
|
|
1039
|
-
if (isTableRow(firstLine)) {
|
|
1040
|
-
const nextLineComplete = lines.length > 2;
|
|
1041
|
-
if (!nextLineComplete) break;
|
|
1042
|
-
if (isTableSeparator(lines[1] ?? "")) {
|
|
1043
|
-
let end = 2;
|
|
1044
|
-
while (end < lines.length && isTableRow(lines[end] ?? "") && !isTableSeparator(lines[end] ?? "")) {
|
|
1045
|
-
end += 1;
|
|
1046
|
-
}
|
|
1047
|
-
const tableComplete = end < lines.length - 1;
|
|
1048
|
-
if (!tableComplete) break;
|
|
1049
|
-
emitBreathIfNeeded("list");
|
|
1050
|
-
emitFormattedAssistantBlock(
|
|
1051
|
-
args.write,
|
|
1052
|
-
lines.slice(0, end).join("\n"),
|
|
1053
|
-
true
|
|
1054
|
-
);
|
|
1055
|
-
lastKind = "list";
|
|
1056
|
-
buffer = lines.slice(end).join("\n");
|
|
1057
|
-
continue;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
const kind = classifyStreamLine(firstLine);
|
|
1061
|
-
emitBreathIfNeeded(kind);
|
|
1062
|
-
emitFormattedAssistantBlock(args.write, firstLine, true);
|
|
1063
|
-
lastKind = kind;
|
|
1064
|
-
buffer = lines.slice(1).join("\n");
|
|
1065
|
-
}
|
|
1066
|
-
};
|
|
1067
|
-
return {
|
|
1068
|
-
push(chunk) {
|
|
1069
|
-
if (!chunk) return;
|
|
1070
|
-
buffer += chunk;
|
|
1071
|
-
flushCompleteBlocks();
|
|
1072
|
-
},
|
|
1073
|
-
flush() {
|
|
1074
|
-
if (!buffer) return;
|
|
1075
|
-
if (inFence) {
|
|
1076
|
-
args.write(buffer);
|
|
1077
|
-
} else {
|
|
1078
|
-
emitFormattedAssistantBlock(args.write, buffer);
|
|
1079
|
-
}
|
|
1080
|
-
buffer = "";
|
|
1081
|
-
}
|
|
1082
|
-
};
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
// packages/cli/client/thinkingOutput.ts
|
|
1086
|
-
var THINK_OPEN = /<think>/i;
|
|
1087
|
-
var THINK_CLOSE = /<\/think>/i;
|
|
1088
|
-
var COLLAPSED_MARKER = /^\s*▸ 思考已折叠\s*$/;
|
|
1089
|
-
function normalizeThinkingDisplayMode(raw, fallback = "hide") {
|
|
1090
|
-
const normalized = asTrimmedLowercaseString(raw);
|
|
1091
|
-
if (normalized === "hide" || normalized === "off" || normalized === "false" || normalized === "0") {
|
|
1092
|
-
return "hide";
|
|
1093
|
-
}
|
|
1094
|
-
if (normalized === "marker" || normalized === "collapsed" || normalized === "fold") {
|
|
1095
|
-
return "marker";
|
|
1096
|
-
}
|
|
1097
|
-
if (normalized === "show" || normalized === "on" || normalized === "true" || normalized === "1") {
|
|
1098
|
-
return "show";
|
|
1099
|
-
}
|
|
1100
|
-
return fallback;
|
|
1101
|
-
}
|
|
1102
|
-
function resolveThinkingDisplayMode(env = process.env) {
|
|
1103
|
-
return normalizeThinkingDisplayMode(env.NOLO_CLI_THINKING ?? env.NOLO_THINKING, "hide");
|
|
1104
|
-
}
|
|
1105
|
-
function collapseThinkingBlocks(text, mode = "hide") {
|
|
1106
|
-
if (mode === "show") return text;
|
|
1107
|
-
const replacement = mode === "marker" ? "\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n" : "";
|
|
1108
|
-
return text.replace(/<think>[\s\S]*?<\/think>\s*/gi, replacement).replace(/\n{3,}/g, "\n\n").trim();
|
|
1109
|
-
}
|
|
1110
|
-
function stripCollapsedThinkingMarkers(text) {
|
|
1111
|
-
return text.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n").replace(/\n{2,}/g, "\n").trim();
|
|
1112
|
-
}
|
|
1113
|
-
function formatAssistantTextForCli(text, mode = "hide") {
|
|
1114
|
-
const collapsed = collapseThinkingBlocks(text, mode);
|
|
1115
|
-
return mode === "hide" ? stripCollapsedThinkingMarkers(collapsed) : collapsed;
|
|
1116
|
-
}
|
|
1117
|
-
function createThinkingEventSink(arg1, arg2) {
|
|
1118
|
-
let mode = "hide";
|
|
1119
|
-
let write = () => {
|
|
1120
|
-
};
|
|
1121
|
-
if (typeof arg1 === "function") {
|
|
1122
|
-
write = arg1;
|
|
1123
|
-
if (typeof arg2 === "string") {
|
|
1124
|
-
mode = arg2;
|
|
1125
|
-
}
|
|
1126
|
-
} else {
|
|
1127
|
-
mode = arg1;
|
|
1128
|
-
if (typeof arg2 === "function") {
|
|
1129
|
-
write = arg2;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
if (mode === "hide") {
|
|
1133
|
-
return {
|
|
1134
|
-
push(_chunk) {
|
|
1135
|
-
}
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
if (mode === "show") {
|
|
1139
|
-
return {
|
|
1140
|
-
push(chunk) {
|
|
1141
|
-
if (chunk) write(chunk);
|
|
1142
|
-
}
|
|
1143
|
-
};
|
|
1144
|
-
}
|
|
1145
|
-
let markerEmitted = false;
|
|
1146
|
-
return {
|
|
1147
|
-
push(chunk) {
|
|
1148
|
-
if (!chunk || markerEmitted) return;
|
|
1149
|
-
write("\n\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n");
|
|
1150
|
-
markerEmitted = true;
|
|
1151
|
-
}
|
|
1152
|
-
};
|
|
1153
|
-
}
|
|
1154
|
-
function createThinkingAwareStreamFilter(write, mode = "hide") {
|
|
1155
|
-
if (mode === "show") {
|
|
1156
|
-
return {
|
|
1157
|
-
push(chunk) {
|
|
1158
|
-
write(chunk);
|
|
1159
|
-
},
|
|
1160
|
-
flush() {
|
|
1161
|
-
}
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
let pending = "";
|
|
1165
|
-
let insideThink = false;
|
|
1166
|
-
let markerEmitted = false;
|
|
1167
|
-
const emit = (chunk) => {
|
|
1168
|
-
if (chunk) write(chunk);
|
|
1169
|
-
};
|
|
1170
|
-
const emitMarker = () => {
|
|
1171
|
-
if (mode !== "marker" || markerEmitted) return;
|
|
1172
|
-
emit("\n\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n");
|
|
1173
|
-
markerEmitted = true;
|
|
1174
|
-
};
|
|
1175
|
-
const consume = (input) => {
|
|
1176
|
-
pending += input;
|
|
1177
|
-
while (pending.length > 0) {
|
|
1178
|
-
if (insideThink) {
|
|
1179
|
-
const closeMatch = pending.match(THINK_CLOSE);
|
|
1180
|
-
if (!closeMatch || closeMatch.index == null) {
|
|
1181
|
-
emitMarker();
|
|
1182
|
-
pending = "";
|
|
1183
|
-
return;
|
|
1184
|
-
}
|
|
1185
|
-
emitMarker();
|
|
1186
|
-
pending = pending.slice(closeMatch.index + closeMatch[0].length);
|
|
1187
|
-
insideThink = false;
|
|
1188
|
-
markerEmitted = false;
|
|
1189
|
-
continue;
|
|
1190
|
-
}
|
|
1191
|
-
const openMatch = pending.match(THINK_OPEN);
|
|
1192
|
-
if (!openMatch || openMatch.index == null) {
|
|
1193
|
-
const nextMarker = pending.indexOf("<");
|
|
1194
|
-
if (nextMarker === -1) {
|
|
1195
|
-
const cleaned = mode === "hide" ? pending.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : pending;
|
|
1196
|
-
emit(cleaned);
|
|
1197
|
-
pending = "";
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
if (nextMarker > 0) {
|
|
1201
|
-
const head = pending.slice(0, nextMarker);
|
|
1202
|
-
const cleaned = mode === "hide" ? head.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : head;
|
|
1203
|
-
emit(cleaned);
|
|
1204
|
-
pending = pending.slice(nextMarker);
|
|
1205
|
-
continue;
|
|
1206
|
-
}
|
|
1207
|
-
if (pending.length < 7) return;
|
|
1208
|
-
emit(pending[0]);
|
|
1209
|
-
pending = pending.slice(1);
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
if (openMatch.index > 0) {
|
|
1213
|
-
const head = pending.slice(0, openMatch.index);
|
|
1214
|
-
const cleaned = mode === "hide" ? head.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : head;
|
|
1215
|
-
emit(cleaned);
|
|
1216
|
-
pending = pending.slice(openMatch.index);
|
|
1217
|
-
continue;
|
|
1218
|
-
}
|
|
1219
|
-
pending = pending.slice(openMatch[0].length);
|
|
1220
|
-
insideThink = true;
|
|
1221
|
-
markerEmitted = false;
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
|
-
return {
|
|
1225
|
-
push(chunk) {
|
|
1226
|
-
consume(chunk);
|
|
1227
|
-
},
|
|
1228
|
-
flush() {
|
|
1229
|
-
if (insideThink) emitMarker();
|
|
1230
|
-
if (pending) {
|
|
1231
|
-
const cleaned = mode === "hide" ? pending.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : pending;
|
|
1232
|
-
emit(cleaned);
|
|
1233
|
-
}
|
|
1234
|
-
pending = "";
|
|
1235
|
-
insideThink = false;
|
|
1236
|
-
markerEmitted = false;
|
|
1237
|
-
}
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
// packages/cli/client/formatReadPathTree.ts
|
|
1242
|
-
import { homedir as osHomedir } from "node:os";
|
|
1243
|
-
function clipPathAware(value, max = 72) {
|
|
1244
|
-
const compact = compactWhitespace(value);
|
|
1245
|
-
if (compact.length <= max) return compact;
|
|
1246
|
-
if (compact.includes(" ") || !compact.includes("/") && !compact.includes("\\")) {
|
|
1247
|
-
return clipCompactText(value, max, "\u2026");
|
|
1248
|
-
}
|
|
1249
|
-
const segments = compact.split(/[/\\]/);
|
|
1250
|
-
const filename = segments[segments.length - 1];
|
|
1251
|
-
if (filename.length >= max) {
|
|
1252
|
-
return clipCompactText(value, max, "\u2026");
|
|
1253
|
-
}
|
|
1254
|
-
const ELISION = "/\u2026/";
|
|
1255
|
-
let prefix = "";
|
|
1256
|
-
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
1257
|
-
const candidate = segments.slice(0, i + 1).join("/");
|
|
1258
|
-
if (candidate.length + ELISION.length + filename.length > max) break;
|
|
1259
|
-
prefix = candidate;
|
|
1260
|
-
}
|
|
1261
|
-
if (prefix) return `${prefix}${ELISION}${filename}`;
|
|
1262
|
-
const filenameOnly = `\u2026/${filename}`;
|
|
1263
|
-
if (filenameOnly.length <= max) return filenameOnly;
|
|
1264
|
-
return clipCompactText(value, max, "\u2026");
|
|
1265
|
-
}
|
|
1266
|
-
function formatHomePath(path, customHomedir) {
|
|
1267
|
-
if (!path) return "";
|
|
1268
|
-
const home = customHomedir || (typeof process !== "undefined" ? process.env?.HOME : void 0) || (typeof osHomedir === "function" ? osHomedir() : "");
|
|
1269
|
-
if (home && path.startsWith(home)) {
|
|
1270
|
-
return `~${path.slice(home.length)}`;
|
|
1271
|
-
}
|
|
1272
|
-
return path.replace(/^(\/Users\/[^\/]+\/|\/home\/[^\/]+\/)/, "~/");
|
|
1273
|
-
}
|
|
1274
|
-
function formatReadItemPath(rawPath, metadata, customHomedir) {
|
|
1275
|
-
const inputPath = rawPath || (typeof metadata?.path === "string" ? metadata.path : void 0) || (typeof metadata?.filePath === "string" ? metadata.filePath : void 0) || "file";
|
|
1276
|
-
let formattedPath = formatHomePath(inputPath, customHomedir);
|
|
1277
|
-
if (!formattedPath) return "file";
|
|
1278
|
-
let rangePart = "";
|
|
1279
|
-
const match = formattedPath.match(/(:[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*)$/);
|
|
1280
|
-
if (match) {
|
|
1281
|
-
rangePart = match[1];
|
|
1282
|
-
formattedPath = formattedPath.slice(0, -rangePart.length);
|
|
1283
|
-
} else if (metadata && typeof metadata.startLine === "number" && typeof metadata.endLine === "number" && typeof metadata.totalLines === "number") {
|
|
1284
|
-
const { startLine, endLine, totalLines, truncated } = metadata;
|
|
1285
|
-
if (truncated || startLine !== 1 || endLine !== totalLines) {
|
|
1286
|
-
rangePart = `:${startLine}-${endLine}`;
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
const clippedPath = clipPathAware(formattedPath, 72);
|
|
1290
|
-
return `${clippedPath}${rangePart}`;
|
|
1291
|
-
}
|
|
1292
|
-
function formatReadTreeLines(items, customHomedir) {
|
|
1293
|
-
const count = items.length;
|
|
1294
|
-
const header = `Read (${count})`;
|
|
1295
|
-
const lines = items.map((item, index) => {
|
|
1296
|
-
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1297
|
-
const pathWithRange = formatReadItemPath(item.path, item.metadata, customHomedir);
|
|
1298
|
-
return { connector, pathWithRange };
|
|
1299
|
-
});
|
|
1300
|
-
return { header, count, lines };
|
|
1301
|
-
}
|
|
1302
|
-
function formatSearchItemQuery(query, path, customHomedir) {
|
|
1303
|
-
let text = (query || "").trim();
|
|
1304
|
-
if (path) {
|
|
1305
|
-
const formattedPath = formatHomePath(path, customHomedir);
|
|
1306
|
-
if (formattedPath) {
|
|
1307
|
-
text = text ? `${text} in ${formattedPath}` : formattedPath;
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (!text) return "search";
|
|
1311
|
-
return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
1312
|
-
}
|
|
1313
|
-
function formatSearchTreeLines(items, customHomedir) {
|
|
1314
|
-
const count = items.length;
|
|
1315
|
-
const header = `Search (${count})`;
|
|
1316
|
-
const lines = items.map((item, index) => {
|
|
1317
|
-
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1318
|
-
const queryText = formatSearchItemQuery(item.query, item.path, customHomedir);
|
|
1319
|
-
return { connector, queryText };
|
|
1320
|
-
});
|
|
1321
|
-
return { header, count, lines };
|
|
1322
|
-
}
|
|
1323
|
-
function formatRunItemCommand(command, exitCode, timedOut) {
|
|
1324
|
-
let text = compactWhitespace(command || "");
|
|
1325
|
-
if (!text) text = "command";
|
|
1326
|
-
text = text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
1327
|
-
if (timedOut) return `${text} (timed out)`;
|
|
1328
|
-
if (typeof exitCode === "number" && exitCode !== 0) return `${text} (exit ${exitCode})`;
|
|
1329
|
-
return text;
|
|
1330
|
-
}
|
|
1331
|
-
function formatRunTreeLines(items) {
|
|
1332
|
-
const count = items.length;
|
|
1333
|
-
const header = `Run (${count})`;
|
|
1334
|
-
const lines = items.map((item, index) => {
|
|
1335
|
-
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1336
|
-
const commandText = formatRunItemCommand(item.command, item.exitCode, item.timedOut);
|
|
1337
|
-
return { connector, commandText };
|
|
1338
|
-
});
|
|
1339
|
-
return { header, count, lines };
|
|
1340
|
-
}
|
|
1341
|
-
function formatFetchItemUrl(url) {
|
|
1342
|
-
const text = (url || "").trim();
|
|
1343
|
-
if (!text) return "webpage";
|
|
1344
|
-
return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
1345
|
-
}
|
|
1346
|
-
function formatFetchTreeLines(items) {
|
|
1347
|
-
const count = items.length;
|
|
1348
|
-
const header = `Fetch (${count})`;
|
|
1349
|
-
const lines = items.map((item, index) => {
|
|
1350
|
-
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1351
|
-
const urlText = formatFetchItemUrl(item.url);
|
|
1352
|
-
return { connector, urlText };
|
|
1353
|
-
});
|
|
1354
|
-
return { header, count, lines };
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
// packages/cli/tui/i18n.ts
|
|
1358
|
-
var ZH_PATTERNS = /^zh/i;
|
|
1359
|
-
function parseCliLocale(raw) {
|
|
1360
|
-
const normalized = raw?.trim().toLowerCase();
|
|
1361
|
-
if (!normalized) return null;
|
|
1362
|
-
if (ZH_PATTERNS.test(normalized)) return "zh";
|
|
1363
|
-
if (normalized === "en" || normalized.startsWith("en")) return "en";
|
|
1364
|
-
return null;
|
|
1365
|
-
}
|
|
1366
|
-
function detectLocaleFromEnv(env) {
|
|
1367
|
-
const explicit = parseCliLocale(env.NOLO_LANG);
|
|
1368
|
-
if (explicit) return explicit;
|
|
1369
|
-
const candidates = [env.LC_ALL, env.LC_CTYPE, env.LANG].filter(Boolean);
|
|
1370
|
-
for (const candidate of candidates) {
|
|
1371
|
-
if (ZH_PATTERNS.test(candidate)) return "zh";
|
|
1372
|
-
if (candidate && !candidate.startsWith("C.") && !candidate.startsWith("POSIX")) {
|
|
1373
|
-
return "en";
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
return null;
|
|
1377
|
-
}
|
|
1378
|
-
function detectLocale(env) {
|
|
1379
|
-
return detectLocaleFromEnv(env) ?? "zh";
|
|
1380
|
-
}
|
|
1381
|
-
var currentLocale = detectLocale(process.env);
|
|
1382
|
-
function getCliLocale() {
|
|
1383
|
-
return currentLocale;
|
|
1384
|
-
}
|
|
1385
|
-
function setCliLocale(locale) {
|
|
1386
|
-
currentLocale = locale;
|
|
1387
|
-
}
|
|
1388
|
-
function initCliLocale(env = process.env) {
|
|
1389
|
-
currentLocale = detectLocale(env);
|
|
506
|
+
function initCliLocale(env = process.env) {
|
|
507
|
+
currentLocale = detectLocale(env);
|
|
1390
508
|
}
|
|
1391
509
|
var STRINGS = {
|
|
1392
510
|
welcomeHint: {
|
|
@@ -1457,6 +575,18 @@ var STRINGS = {
|
|
|
1457
575
|
en: "Stopped this reply.",
|
|
1458
576
|
zh: "\u5DF2\u505C\u6B62\u672C\u6B21\u56DE\u590D\u3002"
|
|
1459
577
|
},
|
|
578
|
+
turnStoppedToolPending: {
|
|
579
|
+
en: "Stopped waiting. {0} may still be finishing in the background \u2014 its result won't be added to this conversation.",
|
|
580
|
+
zh: "\u5DF2\u505C\u6B62\u7B49\u5F85\u3002{0} \u53EF\u80FD\u4ECD\u5728\u540E\u53F0\u5B8C\u6210\uFF0C\u5176\u7ED3\u679C\u4E0D\u4F1A\u8BA1\u5165\u672C\u6B21\u5BF9\u8BDD\u3002"
|
|
581
|
+
},
|
|
582
|
+
turnStopping: {
|
|
583
|
+
en: "Stopping\u2026 press Esc again to force",
|
|
584
|
+
zh: "\u6B63\u5728\u505C\u6B62\u2026\u518D\u6309\u4E00\u6B21 Esc \u5F3A\u5236\u505C\u6B62"
|
|
585
|
+
},
|
|
586
|
+
forceStopped: {
|
|
587
|
+
en: "Force stopped. Background tasks may still be finishing.",
|
|
588
|
+
zh: "\u5DF2\u5F3A\u5236\u505C\u6B62\uFF0C\u540E\u53F0\u4EFB\u52A1\u53EF\u80FD\u4ECD\u5728\u6536\u5C3E\u3002"
|
|
589
|
+
},
|
|
1460
590
|
turnFailed: {
|
|
1461
591
|
en: "This reply failed. Queued messages are kept \u2014 press Enter to resend.",
|
|
1462
592
|
zh: "\u672C\u6B21\u56DE\u590D\u51FA\u9519\u3002\u5DF2\u6392\u961F\u7684\u6D88\u606F\u4ECD\u4FDD\u7559\uFF0C\u6309 Enter \u53EF\u91CD\u65B0\u53D1\u9001\u3002"
|
|
@@ -1465,6 +595,18 @@ var STRINGS = {
|
|
|
1465
595
|
en: "[nolo] This agent seems to have hit a quota/rate limit (HTTP 429).\nUse /agent to switch to another agent and keep going \u2014 the dialog context is preserved.",
|
|
1466
596
|
zh: "[nolo] \u5F53\u524D agent \u4F3C\u4E4E\u989D\u5EA6/\u901F\u7387\u53D7\u9650\uFF08429\uFF09\u3002\n\u53EF\u4EE5\u7528 /agent \u5207\u6362\u5230\u5176\u4ED6 agent \u540E\u7EE7\u7EED\uFF0C\u540C\u4E00\u5BF9\u8BDD\u4F1A\u4FDD\u7559\u4E0A\u4E0B\u6587\u3002"
|
|
1467
597
|
},
|
|
598
|
+
balanceExhaustedHint: {
|
|
599
|
+
en: '[nolo] Insufficient balance. Your message is saved in this dialog \u2014 top up, then send again or say "continue".',
|
|
600
|
+
zh: "[nolo] \u4F59\u989D\u4E0D\u8DB3\u3002\u4F60\u521A\u53D1\u7684\u8BDD\u5DF2\u4FDD\u5B58\u5728\u5F53\u524D\u5BF9\u8BDD\u91CC\u2014\u2014\u5145\u503C\u540E\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\u5373\u53EF\uFF0C\u4E0D\u4F1A\u4E22\u4E0A\u4E0B\u6587\u3002"
|
|
601
|
+
},
|
|
602
|
+
dialogPreservedHint: {
|
|
603
|
+
en: '[nolo] This turn failed, but the dialog is kept. Send another message (or say "continue") to keep going in the same conversation.',
|
|
604
|
+
zh: "[nolo] \u672C\u8F6E\u5931\u8D25\u4E86\uFF0C\u4F46\u5BF9\u8BDD\u5DF2\u4FDD\u7559\u3002\u76F4\u63A5\u518D\u8BF4\u4E00\u53E5\uFF08\u6216\u8BF4\u300C\u7EE7\u7EED\u300D\uFF09\u5373\u53EF\u5728\u540C\u4E00\u5BF9\u8BDD\u91CC\u63A5\u7740\u804A\u3002"
|
|
605
|
+
},
|
|
606
|
+
dialogNotSavedHint: {
|
|
607
|
+
en: "[nolo] This turn did not create a dialog. Your next message will start a new conversation \u2014 restate what you need.",
|
|
608
|
+
zh: "[nolo] \u672C\u8F6E\u6CA1\u6709\u5EFA\u6210\u5BF9\u8BDD\u3002\u4E0B\u4E00\u53E5\u4F1A\u662F\u65B0\u5BF9\u8BDD\u2014\u2014\u8BF7\u628A\u4F60\u60F3\u505A\u7684\u4E8B\u518D\u8BF4\u4E00\u904D\u3002"
|
|
609
|
+
},
|
|
1468
610
|
copiedLastReply: {
|
|
1469
611
|
en: "Copied the last reply to the clipboard.",
|
|
1470
612
|
zh: "\u5DF2\u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F\u3002"
|
|
@@ -1513,6 +655,18 @@ var STRINGS = {
|
|
|
1513
655
|
en: "Usage: /mouse <on|off>",
|
|
1514
656
|
zh: "\u7528\u6CD5\uFF1A/mouse <on|off>"
|
|
1515
657
|
},
|
|
658
|
+
altscreenOn: {
|
|
659
|
+
en: "Alternate screen on: the TUI uses a private buffer so the terminal wheel no longer fights its own scroll state.",
|
|
660
|
+
zh: "\u5907\u7528\u5C4F\u5DF2\u5F00\u542F\uFF1ATUI \u4F7F\u7528\u72EC\u7ACB\u7F13\u51B2\u533A\uFF0C\u7EC8\u7AEF\u6EDA\u8F6E\u4E0D\u518D\u4E0E\u81EA\u8EAB\u6EDA\u52A8\u72B6\u6001\u4E92\u76F8\u6253\u67B6\u3002"
|
|
661
|
+
},
|
|
662
|
+
altscreenOff: {
|
|
663
|
+
en: "Alternate screen off: the TUI shares the shell scrollback (wheel may desync the viewport).",
|
|
664
|
+
zh: "\u5907\u7528\u5C4F\u5DF2\u5173\u95ED\uFF1ATUI \u4E0E shell \u5171\u7528\u56DE\u6EDA\u7F13\u51B2\u533A\uFF08\u6EDA\u8F6E\u53EF\u80FD\u8BA9\u89C6\u53E3\u9519\u4F4D\uFF09\u3002"
|
|
665
|
+
},
|
|
666
|
+
altscreenUsage: {
|
|
667
|
+
en: "Usage: /altscreen <on|off>",
|
|
668
|
+
zh: "\u7528\u6CD5\uFF1A/altscreen <on|off>"
|
|
669
|
+
},
|
|
1516
670
|
langSwitched: {
|
|
1517
671
|
en: "Language switched to English.",
|
|
1518
672
|
zh: "\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587\u3002"
|
|
@@ -1598,6 +752,47 @@ var STRINGS = {
|
|
|
1598
752
|
en: "abort the operation",
|
|
1599
753
|
zh: "\u4E2D\u6B62\u64CD\u4F5C"
|
|
1600
754
|
},
|
|
755
|
+
// --- Ask choice (ui_ask_choice) ------------------------------------------
|
|
756
|
+
askChoiceTitle: {
|
|
757
|
+
en: "question",
|
|
758
|
+
zh: "\u95EE\u9898"
|
|
759
|
+
},
|
|
760
|
+
askChoiceSubmit: {
|
|
761
|
+
en: "Submit",
|
|
762
|
+
zh: "\u63D0\u4EA4"
|
|
763
|
+
},
|
|
764
|
+
askChoiceOtherLabel: {
|
|
765
|
+
en: "Other",
|
|
766
|
+
zh: "\u5176\u4ED6"
|
|
767
|
+
},
|
|
768
|
+
askChoiceHintSingle: {
|
|
769
|
+
en: "Type your answer, then press Enter to save.",
|
|
770
|
+
zh: "\u8F93\u5165\u56DE\u7B54\u540E\u6309 Enter \u4FDD\u5B58\u3002"
|
|
771
|
+
},
|
|
772
|
+
askChoiceHintMulti: {
|
|
773
|
+
en: "Space to toggle, Enter to confirm selection.",
|
|
774
|
+
zh: "\u7A7A\u683C\u5207\u6362\u9009\u4E2D\uFF0CEnter \u786E\u8BA4\u63D0\u4EA4\u3002"
|
|
775
|
+
},
|
|
776
|
+
askChoiceFooterSingle: {
|
|
777
|
+
en: "\u21B5 pick/submit \xB7 tab switch \xB7 esc cancel",
|
|
778
|
+
zh: "\u21B5 \u9009\u62E9/\u63D0\u4EA4 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
|
|
779
|
+
},
|
|
780
|
+
askChoiceFooterMulti: {
|
|
781
|
+
en: "\u21B5 submit \xB7 space toggle \xB7 tab switch \xB7 esc cancel",
|
|
782
|
+
zh: "\u21B5 \u63D0\u4EA4 \xB7 space \u5207\u6362 \xB7 tab \u5207\u6362 \xB7 esc \u53D6\u6D88"
|
|
783
|
+
},
|
|
784
|
+
askChoiceHistoryHint: {
|
|
785
|
+
en: "Type a number to choose, or reply directly:",
|
|
786
|
+
zh: "\u8BF7\u8F93\u5165\u5E8F\u53F7\u9009\u62E9\uFF0C\u6216\u76F4\u63A5\u56DE\u590D\uFF1A"
|
|
787
|
+
},
|
|
788
|
+
askChoiceHistorySelected: {
|
|
789
|
+
en: "selected",
|
|
790
|
+
zh: "\u5DF2\u9009"
|
|
791
|
+
},
|
|
792
|
+
askChoiceHistoryCancelled: {
|
|
793
|
+
en: "cancelled",
|
|
794
|
+
zh: "\u5DF2\u53D6\u6D88"
|
|
795
|
+
},
|
|
1601
796
|
contextTitle: {
|
|
1602
797
|
en: "Workspace context",
|
|
1603
798
|
zh: "\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587"
|
|
@@ -1654,144 +849,1869 @@ var STRINGS = {
|
|
|
1654
849
|
en: "add working context",
|
|
1655
850
|
zh: "\u6DFB\u52A0\u5DE5\u4F5C\u4E0A\u4E0B\u6587"
|
|
1656
851
|
},
|
|
1657
|
-
contextNextSkill: {
|
|
1658
|
-
en: "attach a skill to this workspace",
|
|
1659
|
-
zh: "\u4E3A\u8BE5\u5DE5\u4F5C\u533A\u6302\u8F7D\u6280\u80FD"
|
|
852
|
+
contextNextSkill: {
|
|
853
|
+
en: "attach a skill to this workspace",
|
|
854
|
+
zh: "\u4E3A\u8BE5\u5DE5\u4F5C\u533A\u6302\u8F7D\u6280\u80FD"
|
|
855
|
+
},
|
|
856
|
+
contextNextNew: {
|
|
857
|
+
en: "start a clean dialog",
|
|
858
|
+
zh: "\u5F00\u59CB\u4E00\u4E2A\u5E72\u51C0\u7684\u5BF9\u8BDD"
|
|
859
|
+
},
|
|
860
|
+
agentsTitle: {
|
|
861
|
+
en: "Agents:",
|
|
862
|
+
zh: "\u667A\u80FD\u4F53\uFF1A"
|
|
863
|
+
},
|
|
864
|
+
agentsTip: {
|
|
865
|
+
en: "Tip: run /switch for the full picker, or /switch list for your private agents too.",
|
|
866
|
+
zh: "\u63D0\u793A\uFF1A\u7528 /switch \u6253\u5F00\u5B8C\u6574\u9009\u62E9\u5668\uFF0C\u6216 /switch list \u8FDE\u4F60\u7684\u79C1\u6709\u667A\u80FD\u4F53\u4E00\u8D77\u5217\u51FA\u3002"
|
|
867
|
+
},
|
|
868
|
+
helpText: {
|
|
869
|
+
en: [
|
|
870
|
+
"Commands:",
|
|
871
|
+
" /help Show this help",
|
|
872
|
+
" /new Clear screen and start a fresh dialog",
|
|
873
|
+
" /compact Compact current dialog and fork a new one",
|
|
874
|
+
" /context Show workspace context and next actions",
|
|
875
|
+
" /runtime <mode> Use auto, local, or server runtime",
|
|
876
|
+
" /tools <mode> Control tool trace: hide, compact, verbose",
|
|
877
|
+
" /thinking <mode> Control thinking output: hide, marker, show",
|
|
878
|
+
" /switch Pick an agent interactively (\u2191\u2193, Enter)",
|
|
879
|
+
" /switch list List agents as text",
|
|
880
|
+
" /switch <name> Switch directly by name, alias, or key (alias: /agent)",
|
|
881
|
+
" /agents List platform agent shortcuts",
|
|
882
|
+
" /history Pick a recent dialog to resume (\u2191\u2193, Enter)",
|
|
883
|
+
" /resume <dialogId> Resume a dialog directly by id",
|
|
884
|
+
" /lang <zh|en> Switch interface language",
|
|
885
|
+
" /copy Copy the last reply to the clipboard",
|
|
886
|
+
" /copy view Open native scrollback for partial selection (Ctrl+O)",
|
|
887
|
+
" /mouse <on|off> Toggle mouse mode (off = drag to select text)",
|
|
888
|
+
" /altscreen <on|off> Toggle the terminal alternate screen (default on; off shares shell scrollback)",
|
|
889
|
+
" /doc List attached docs",
|
|
890
|
+
" /doc attach <doc> Attach a doc to this workspace",
|
|
891
|
+
" /skill List attached skills",
|
|
892
|
+
" /skill attach <ref> Attach a skill (dbKey, name, or SKILL.md path)",
|
|
893
|
+
" /skill detach <ref> Detach a skill",
|
|
894
|
+
" /skill clear Detach all skills",
|
|
895
|
+
" /customize Describe how you want to tune nolo",
|
|
896
|
+
" /tasks List background process tasks (aliases: /jobs, /procs)",
|
|
897
|
+
" /stop <pid|all> Stop background process tasks",
|
|
898
|
+
" /login Show login/profile hint",
|
|
899
|
+
" /profile Show active profile",
|
|
900
|
+
" /update Update the nolo CLI install",
|
|
901
|
+
" /version Show version/update hint",
|
|
902
|
+
" /exit Leave the workspace",
|
|
903
|
+
"",
|
|
904
|
+
"You can also type normally. nolo routes simple read/status requests to CLI commands and sends the rest to the current agent."
|
|
905
|
+
].join("\n"),
|
|
906
|
+
zh: [
|
|
907
|
+
"\u547D\u4EE4\uFF1A",
|
|
908
|
+
" /help \u663E\u793A\u672C\u5E2E\u52A9",
|
|
909
|
+
" /new \u6E05\u5C4F\u5E76\u5F00\u59CB\u65B0\u5BF9\u8BDD",
|
|
910
|
+
" /compact \u538B\u7F29\u5F53\u524D\u5BF9\u8BDD\u5E76\u5206\u53C9\u51FA\u65B0\u5BF9\u8BDD",
|
|
911
|
+
" /context \u67E5\u770B\u5DE5\u4F5C\u533A\u4E0A\u4E0B\u6587\u4E0E\u540E\u7EED\u64CD\u4F5C",
|
|
912
|
+
" /runtime <mode> \u5207\u6362 runtime\uFF1Aauto\u3001local\u3001server",
|
|
913
|
+
" /tools <mode> \u5DE5\u5177\u8F68\u8FF9\u663E\u793A\uFF1Ahide\u3001compact\u3001verbose",
|
|
914
|
+
" /thinking <mode> \u601D\u8003\u8FC7\u7A0B\u663E\u793A\uFF1Ahide\u3001marker\u3001show",
|
|
915
|
+
" /switch \u4EA4\u4E92\u5F0F\u9009\u62E9 agent\uFF08\u2191\u2193 \u79FB\u52A8\uFF0CEnter \u786E\u8BA4\uFF09",
|
|
916
|
+
" /switch list \u4EE5\u6587\u672C\u5217\u51FA\u5168\u90E8 agent",
|
|
917
|
+
" /switch <name> \u6309\u540D\u79F0\u3001\u522B\u540D\u6216 key \u76F4\u63A5\u5207\u6362\uFF08\u522B\u540D\uFF1A/agent\uFF09",
|
|
918
|
+
" /agents \u5217\u51FA\u5E73\u53F0 agent \u5FEB\u6377\u65B9\u5F0F",
|
|
919
|
+
" /history \u4ECE\u6700\u8FD1\u5BF9\u8BDD\u4E2D\u9009\u62E9\u5E76\u6062\u590D\uFF08\u2191\u2193\uFF0CEnter\uFF09",
|
|
920
|
+
" /resume <dialogId> \u6309 id \u76F4\u63A5\u6062\u590D\u5BF9\u8BDD",
|
|
921
|
+
" /lang <zh|en> \u5207\u6362\u754C\u9762\u8BED\u8A00",
|
|
922
|
+
" /copy \u590D\u5236\u6700\u540E\u4E00\u6761\u56DE\u590D\u5230\u526A\u8D34\u677F",
|
|
923
|
+
" /copy view \u6253\u5F00\u539F\u751F\u56DE\u6EDA\u8FDB\u884C\u8DE8\u5C4F\u62D6\u9009\uFF08Ctrl+O\uFF09",
|
|
924
|
+
" /mouse <on|off> \u5207\u6362\u9F20\u6807\u6A21\u5F0F\uFF08off \u540E\u53EF\u76F4\u63A5\u62D6\u9009\u6587\u672C\uFF09",
|
|
925
|
+
" /altscreen <on|off> \u5207\u6362\u7EC8\u7AEF\u5907\u7528\u5C4F\uFF08\u9ED8\u8BA4 on\uFF1Boff \u6539\u4E3A\u4E0E shell \u5171\u7528\u56DE\u6EDA\uFF09",
|
|
926
|
+
" /doc \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6587\u6863",
|
|
927
|
+
" /doc attach <doc> \u6302\u8F7D\u6587\u6863\u5230\u5F53\u524D\u5DE5\u4F5C\u533A",
|
|
928
|
+
" /skill \u5217\u51FA\u5DF2\u6302\u8F7D\u7684\u6280\u80FD",
|
|
929
|
+
" /skill attach <ref> \u6302\u8F7D\u6280\u80FD\uFF08dbKey\u3001\u540D\u79F0\u6216 SKILL.md \u8DEF\u5F84\uFF09",
|
|
930
|
+
" /skill detach <ref> \u5378\u8F7D\u6307\u5B9A\u6280\u80FD",
|
|
931
|
+
" /skill clear \u5378\u8F7D\u5168\u90E8\u6280\u80FD",
|
|
932
|
+
" /customize \u63CF\u8FF0\u4F60\u60F3\u600E\u4E48\u8C03\u6559 nolo",
|
|
933
|
+
" /tasks \u5217\u51FA\u540E\u53F0\u5B50\u8FDB\u7A0B\u4EFB\u52A1\uFF08\u522B\u540D\uFF1A/jobs, /procs\uFF09",
|
|
934
|
+
" /stop <pid|all> \u505C\u6B62\u6307\u5B9A\u7684\u540E\u53F0\u4EFB\u52A1",
|
|
935
|
+
" /login \u67E5\u770B\u767B\u5F55 / \u914D\u7F6E\u63D0\u793A",
|
|
936
|
+
" /profile \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u73AF\u5883",
|
|
937
|
+
" /update \u66F4\u65B0 nolo CLI",
|
|
938
|
+
" /version \u67E5\u770B\u7248\u672C\u4E0E\u66F4\u65B0\u63D0\u793A",
|
|
939
|
+
" /exit \u9000\u51FA\u5DE5\u4F5C\u533A",
|
|
940
|
+
"",
|
|
941
|
+
"\u4E5F\u53EF\u4EE5\u76F4\u63A5\u8F93\u5165\u81EA\u7136\u8BED\u8A00\u3002\u7B80\u5355\u7684\u8BFB\u53D6/\u72B6\u6001\u8BF7\u6C42\u4F1A\u8D70 CLI \u547D\u4EE4\uFF0C\u5176\u4F59\u4EA4\u7ED9\u5F53\u524D agent\u3002"
|
|
942
|
+
].join("\n")
|
|
943
|
+
},
|
|
944
|
+
// --- Slash-command output ---------------------------------------------
|
|
945
|
+
// Command results that used to be hardcoded English. Usage lines keep the
|
|
946
|
+
// command literal untouched; only the surrounding words are translated.
|
|
947
|
+
unknownCommand: {
|
|
948
|
+
en: "Unknown command: {0}\n\n",
|
|
949
|
+
zh: "\u672A\u77E5\u547D\u4EE4\uFF1A{0}\n\n"
|
|
950
|
+
},
|
|
951
|
+
runtimeUsage: { en: "Usage: /runtime <auto|local|server>", zh: "\u7528\u6CD5\uFF1A/runtime <auto|local|server>" },
|
|
952
|
+
runtimeSet: { en: "Runtime: {0}", zh: "\u8FD0\u884C\u6A21\u5F0F\uFF1A{0}" },
|
|
953
|
+
toolsCurrent: {
|
|
954
|
+
en: "Tool display: {0} (hide | compact | verbose)",
|
|
955
|
+
zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}\uFF08hide | compact | verbose\uFF09"
|
|
956
|
+
},
|
|
957
|
+
toolsUsage: { en: "Usage: /tools <hide|compact|verbose>", zh: "\u7528\u6CD5\uFF1A/tools <hide|compact|verbose>" },
|
|
958
|
+
toolsSet: { en: "Tool display: {0}", zh: "\u5DE5\u5177\u663E\u793A\uFF1A{0}" },
|
|
959
|
+
thinkingCurrent: {
|
|
960
|
+
en: "Thinking display: {0} (hide | marker | show)",
|
|
961
|
+
zh: "\u601D\u8003\u663E\u793A\uFF1A{0}\uFF08hide | marker | show\uFF09"
|
|
962
|
+
},
|
|
963
|
+
thinkingUsage: { en: "Usage: /thinking <hide|marker|show>", zh: "\u7528\u6CD5\uFF1A/thinking <hide|marker|show>" },
|
|
964
|
+
thinkingSet: { en: "Thinking display: {0}", zh: "\u601D\u8003\u663E\u793A\uFF1A{0}" },
|
|
965
|
+
tasksRunning: { en: "Running processes ({0}):", zh: "\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\uFF08{0}\uFF09\uFF1A" },
|
|
966
|
+
tasksStopped: { en: "Stopped/exited ({0}):", zh: "\u5DF2\u505C\u6B62/\u5DF2\u9000\u51FA\uFF08{0}\uFF09\uFF1A" },
|
|
967
|
+
tasksNone: { en: "No processes.", zh: "\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u8FDB\u7A0B\u3002" },
|
|
968
|
+
stopUsage: { en: "Usage: /stop <pid|label|all>", zh: "\u7528\u6CD5\uFF1A/stop <pid|label|all>" },
|
|
969
|
+
stopAllDone: { en: "Stopped {0} processes", zh: "\u5DF2\u505C\u6B62 {0} \u4E2A\u8FDB\u7A0B" },
|
|
970
|
+
stopNoPid: { en: "No running process with pid {0}", zh: "\u6CA1\u6709 pid \u4E3A {0} \u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
|
|
971
|
+
stopPidDone: { en: "Stopped pid {0} ({1})", zh: "\u5DF2\u505C\u6B62 pid {0}\uFF08{1}\uFF09" },
|
|
972
|
+
stopNoLabel: { en: "No running process labeled '{0}'", zh: "\u6CA1\u6709\u540D\u4E3A\u201C{0}\u201D\u7684\u8FD0\u884C\u4E2D\u8FDB\u7A0B" },
|
|
973
|
+
stopLabelsDone: { en: "Stopped {0}", zh: "\u5DF2\u505C\u6B62 {0}" },
|
|
974
|
+
compactNothing: {
|
|
975
|
+
en: "Current dialog: new (nothing to compact yet)",
|
|
976
|
+
zh: "\u5F53\u524D\u5BF9\u8BDD\u8FD8\u662F\u65B0\u7684\uFF08\u8FD8\u6CA1\u6709\u53EF\u538B\u7F29\u7684\u5185\u5BB9\uFF09"
|
|
977
|
+
},
|
|
978
|
+
agentCurrent: { en: "Current agent: {0} ({1})", zh: "\u5F53\u524D agent\uFF1A{0}\uFF08{1}\uFF09" },
|
|
979
|
+
agentUnknown: {
|
|
980
|
+
en: `I don't know agent "{0}" yet.
|
|
981
|
+
Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
|
|
982
|
+
zh: "\u8FD8\u4E0D\u8BA4\u8BC6 agent\u201C{0}\u201D\u3002\n\u53EF\u4EE5\u7528 /switch\u3001/switch list\u3001/switch minimax-m3 \u6216\u5B8C\u6574\u7684 agent key \u6765\u5207\u6362\u3002"
|
|
983
|
+
},
|
|
984
|
+
themeCurrent: { en: "Current theme: {0} \xB7 {1}", zh: "\u5F53\u524D\u4E3B\u9898\uFF1A{0} \xB7 {1}" },
|
|
985
|
+
themeUsage: {
|
|
986
|
+
en: "Usage: /theme <name> | /theme light | /theme dark",
|
|
987
|
+
zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme light | /theme dark"
|
|
988
|
+
},
|
|
989
|
+
themeAvailable: { en: "Available themes: {0}", zh: "\u53EF\u7528\u4E3B\u9898\uFF1A{0}" },
|
|
990
|
+
themeBrightnessSwitched: { en: "Switched to {0} background colors.", zh: "\u5DF2\u5207\u6362\u5230 {0} \u80CC\u666F\u8272\u3002" },
|
|
991
|
+
themeBrightnessAuto: {
|
|
992
|
+
en: "Background colors follow terminal detection (now: {0}).",
|
|
993
|
+
zh: "\u80CC\u666F\u8272\u8DDF\u968F\u7EC8\u7AEF\u81EA\u52A8\u68C0\u6D4B\uFF08\u5F53\u524D\uFF1A{0}\uFF09\u3002"
|
|
994
|
+
},
|
|
995
|
+
themeSwitched: { en: "Switched to theme: {0}", zh: "\u5DF2\u5207\u6362\u5230\u4E3B\u9898\uFF1A{0}" },
|
|
996
|
+
themeUnknown: { en: "Unknown theme: {0}. Available themes: {1}", zh: "\u672A\u77E5\u4E3B\u9898\uFF1A{0}\u3002\u53EF\u7528\u4E3B\u9898\uFF1A{1}" },
|
|
997
|
+
densityCurrent: {
|
|
998
|
+
en: "Current density: {0}\nUsage: /density <cozy|spacious>",
|
|
999
|
+
zh: "\u5F53\u524D\u5BC6\u5EA6\uFF1A{0}\n\u7528\u6CD5\uFF1A/density <cozy|spacious>"
|
|
1000
|
+
},
|
|
1001
|
+
densitySwitched: { en: "Switched to layout density: {0}", zh: "\u5DF2\u5207\u6362\u5230\u5E03\u5C40\u5BC6\u5EA6\uFF1A{0}" },
|
|
1002
|
+
densityUnknown: {
|
|
1003
|
+
en: "Unknown density: {0}. Use 'cozy' or 'spacious'.",
|
|
1004
|
+
zh: "\u672A\u77E5\u5BC6\u5EA6\uFF1A{0}\u3002\u8BF7\u4F7F\u7528 cozy \u6216 spacious\u3002"
|
|
1005
|
+
},
|
|
1006
|
+
docAttachUsage: { en: "Usage: /doc attach <doc>", zh: "\u7528\u6CD5\uFF1A/doc attach <doc>" },
|
|
1007
|
+
docList: { en: "Attached docs: {0}", zh: "\u5DF2\u6302\u8F7D\u6587\u6863\uFF1A{0}" },
|
|
1008
|
+
docNone: { en: "No docs attached. Use /doc attach <doc>.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6587\u6863\u3002\u7528 /doc attach <doc> \u6302\u8F7D\u3002" },
|
|
1009
|
+
skillAttachUsage: { en: "Usage: /skill attach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill attach <skill-ref>" },
|
|
1010
|
+
skillAttached: { en: "Attached skill: {0}", zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}" },
|
|
1011
|
+
skillDetachUsage: { en: "Usage: /skill detach <skill-ref>", zh: "\u7528\u6CD5\uFF1A/skill detach <skill-ref>" },
|
|
1012
|
+
skillDetached: { en: "Detached skill: {0}", zh: "\u5DF2\u5378\u8F7D\u6280\u80FD\uFF1A{0}" },
|
|
1013
|
+
skillNotAttached: { en: "Skill not attached: {0}", zh: "\u6280\u80FD\u672A\u6302\u8F7D\uFF1A{0}" },
|
|
1014
|
+
skillNone: { en: "No skills attached.", zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002" },
|
|
1015
|
+
skillCleared: { en: "Cleared {0} skill(s).", zh: "\u5DF2\u6E05\u7A7A {0} \u4E2A\u6280\u80FD\u3002" },
|
|
1016
|
+
skillList: {
|
|
1017
|
+
en: "Attached skills: {0}\nUsage: /skill attach <ref> | /skill detach <ref> | /skill clear",
|
|
1018
|
+
zh: "\u5DF2\u6302\u8F7D\u6280\u80FD\uFF1A{0}\n\u7528\u6CD5\uFF1A/skill attach <ref> | /skill detach <ref> | /skill clear"
|
|
1019
|
+
},
|
|
1020
|
+
skillNoneHint: {
|
|
1021
|
+
en: "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.",
|
|
1022
|
+
zh: "\u8FD8\u6CA1\u6709\u6302\u8F7D\u6280\u80FD\u3002\u7528 /skill attach <skill-ref> \u6302\u8F7D\u6280\u80FD\u3002\n\u6280\u80FD\u5F15\u7528\u53EF\u4EE5\u662F dbKey\uFF08page-xxx\uFF09\u3001\u6280\u80FD\u540D\uFF08\u4F1A\u5728 .agents/skills/ \u4E0E docs/skills/ \u4E2D\u67E5\u627E\uFF09\u6216\u76F4\u63A5\u8DEF\u5F84\u3002"
|
|
1023
|
+
},
|
|
1024
|
+
customizeHint: {
|
|
1025
|
+
en: "Tell nolo what to change, for example: /customize make my default agent more concise.",
|
|
1026
|
+
zh: "\u544A\u8BC9 nolo \u4F60\u60F3\u6539\u4EC0\u4E48\uFF0C\u4F8B\u5982\uFF1A/customize make my default agent more concise\u3002"
|
|
1027
|
+
},
|
|
1028
|
+
loginHint: {
|
|
1029
|
+
en: "MVP login uses profile/env auth. Set AUTH_TOKEN, NOLO_SERVER, or NOLO_PROFILE before starting nolo.",
|
|
1030
|
+
zh: "MVP \u767B\u5F55\u8D70 profile/\u73AF\u5883\u53D8\u91CF\u8BA4\u8BC1\u3002\u542F\u52A8 nolo \u524D\u8BF7\u8BBE\u7F6E AUTH_TOKEN\u3001NOLO_SERVER \u6216 NOLO_PROFILE\u3002"
|
|
1031
|
+
},
|
|
1032
|
+
versionInfo: {
|
|
1033
|
+
en: "nolo {0}\nUpdate this install with: nolo update\nIf repo-local output differs, publish/install the latest npm package first.",
|
|
1034
|
+
zh: "nolo {0}\n\u7528 nolo update \u66F4\u65B0\u5F53\u524D\u5B89\u88C5\u3002\n\u5982\u679C\u672C\u5730\u4ED3\u5E93\u8F93\u51FA\u7684\u7248\u672C\u4E0D\u540C\uFF0C\u8BF7\u5148\u53D1\u5E03/\u5B89\u88C5\u6700\u65B0\u7684 npm \u5305\u3002"
|
|
1035
|
+
},
|
|
1036
|
+
versionUnknown: { en: "unknown version", zh: "\u672A\u77E5\u7248\u672C" },
|
|
1037
|
+
// --- Dialog list / timestamps -----------------------------------------
|
|
1038
|
+
recentDialogs: { en: "Recent dialogs:", zh: "\u6700\u8FD1\u5BF9\u8BDD\uFF1A" },
|
|
1039
|
+
dialogListTip: {
|
|
1040
|
+
en: "Tip: run /history to pick one interactively, or paste an id after /resume.",
|
|
1041
|
+
zh: "\u63D0\u793A\uFF1A\u7528 /history \u4EA4\u4E92\u5F0F\u9009\u62E9\uFF0C\u6216\u628A id \u7C98\u5230 /resume \u540E\u9762\u3002"
|
|
1042
|
+
},
|
|
1043
|
+
timeJustNow: { en: "just now", zh: "\u521A\u521A" },
|
|
1044
|
+
timeMinutesAgo: { en: "{0}m ago", zh: "{0} \u5206\u949F\u524D" },
|
|
1045
|
+
timeHoursAgo: { en: "{0}h ago", zh: "{0} \u5C0F\u65F6\u524D" },
|
|
1046
|
+
timeDaysAgo: { en: "{0}d ago", zh: "{0} \u5929\u524D" },
|
|
1047
|
+
// Overflow hints shared by select / multi-select / ask-choice. The arrows
|
|
1048
|
+
// and count are part of the copy so each locale can order them naturally.
|
|
1049
|
+
dialogMoreAbove: { en: "\u2191 {0} more", zh: "\u2191 {0} \u66F4\u591A" },
|
|
1050
|
+
dialogMoreBelow: { en: "\u2193 {0} more", zh: "\u2193 {0} \u66F4\u591A" }
|
|
1051
|
+
};
|
|
1052
|
+
function t(key, ...params) {
|
|
1053
|
+
const text = STRINGS[key][currentLocale];
|
|
1054
|
+
if (params.length === 0) return text;
|
|
1055
|
+
return text.replace(/\{(\d+)\}/g, (match, index) => {
|
|
1056
|
+
const replacement = params[Number(index)];
|
|
1057
|
+
return replacement === void 0 ? match : replacement;
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
var TOOL_LABELS = {
|
|
1061
|
+
// Local workspace tools (packages/agent-runtime/localWorkspaceTools.ts)
|
|
1062
|
+
readFile: { en: "Read", zh: "\u8BFB\u53D6" },
|
|
1063
|
+
writeFile: { en: "Write", zh: "\u5199\u5165" },
|
|
1064
|
+
editFile: { en: "Edit", zh: "\u7F16\u8F91" },
|
|
1065
|
+
listFiles: { en: "List", zh: "\u5217\u51FA" },
|
|
1066
|
+
searchFiles: { en: "Search", zh: "\u641C\u7D22" },
|
|
1067
|
+
globFiles: { en: "Glob", zh: "\u5339\u914D" },
|
|
1068
|
+
execShell: { en: "Run", zh: "\u6267\u884C" },
|
|
1069
|
+
runCommand: { en: "Run", zh: "\u6267\u884C" },
|
|
1070
|
+
captureVisualState: { en: "Capture", zh: "\u622A\u5C4F" },
|
|
1071
|
+
// Workspace / diagnostics
|
|
1072
|
+
searchWorkspace: { en: "Search workspace", zh: "\u641C\u7D22\u5DE5\u4F5C\u533A" },
|
|
1073
|
+
cliDoctor: { en: "Doctor", zh: "\u81EA\u68C0" },
|
|
1074
|
+
cliWhoami: { en: "Whoami", zh: "\u67E5\u770B\u8EAB\u4EFD" },
|
|
1075
|
+
checkEnv: { en: "Check env", zh: "\u68C0\u67E5\u73AF\u5883" },
|
|
1076
|
+
configure: { en: "Configure", zh: "\u914D\u7F6E" },
|
|
1077
|
+
notifyUser: { en: "Notify", zh: "\u901A\u77E5" },
|
|
1078
|
+
// Docs / dialogs / spaces
|
|
1079
|
+
readDoc: { en: "Read doc", zh: "\u8BFB\u53D6\u6587\u6863" },
|
|
1080
|
+
createDoc: { en: "Create doc", zh: "\u65B0\u5EFA\u6587\u6863" },
|
|
1081
|
+
updateDoc: { en: "Update doc", zh: "\u66F4\u65B0\u6587\u6863" },
|
|
1082
|
+
readDialog: { en: "Read dialog", zh: "\u8BFB\u53D6\u5BF9\u8BDD" },
|
|
1083
|
+
listDialogs: { en: "List dialogs", zh: "\u5217\u51FA\u5BF9\u8BDD" },
|
|
1084
|
+
queryDialogsBySubjectRef: { en: "Query dialogs", zh: "\u67E5\u8BE2\u5BF9\u8BDD" },
|
|
1085
|
+
searchDialogMessages: { en: "Search messages", zh: "\u641C\u7D22\u6D88\u606F" },
|
|
1086
|
+
listSpaces: { en: "List spaces", zh: "\u5217\u51FA\u7A7A\u95F4" },
|
|
1087
|
+
readSpace: { en: "Read space", zh: "\u8BFB\u53D6\u7A7A\u95F4" },
|
|
1088
|
+
// Tables
|
|
1089
|
+
createTable: { en: "Create table", zh: "\u521B\u5EFA\u8868" },
|
|
1090
|
+
queryTableRows: { en: "Query rows", zh: "\u67E5\u8BE2\u8868\u884C" },
|
|
1091
|
+
addTableRow: { en: "Add row", zh: "\u65B0\u589E\u8868\u884C" },
|
|
1092
|
+
addTableRows: { en: "Add rows", zh: "\u65B0\u589E\u8868\u884C" },
|
|
1093
|
+
updateTableRow: { en: "Update row", zh: "\u66F4\u65B0\u8868\u884C" },
|
|
1094
|
+
deleteTableRow: { en: "Delete row", zh: "\u5220\u9664\u8868\u884C" },
|
|
1095
|
+
// Web
|
|
1096
|
+
fetchWebpage: { en: "Fetch page", zh: "\u6293\u53D6\u7F51\u9875" },
|
|
1097
|
+
readPage: { en: "Read page", zh: "\u8BFB\u53D6\u7F51\u9875" },
|
|
1098
|
+
exaSearch: { en: "Web search", zh: "\u8054\u7F51\u641C\u7D22" },
|
|
1099
|
+
// Skill loading
|
|
1100
|
+
loadSkill: { en: "Used Skill", zh: "\u4F7F\u7528\u6280\u80FD" }
|
|
1101
|
+
};
|
|
1102
|
+
function toolLabel(name) {
|
|
1103
|
+
return TOOL_LABELS[name]?.[currentLocale] ?? name;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// packages/cli/tui/tuiAnsi.ts
|
|
1107
|
+
var ANSI_ESCAPE_REGEX = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
1108
|
+
var OSC_HYPERLINK_REGEX = /\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)\x1b\]8;;(?:\x07|\x1b\\)|\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
|
|
1109
|
+
function stripAnsi(text) {
|
|
1110
|
+
return text.replace(OSC_HYPERLINK_REGEX, "").replace(ANSI_ESCAPE_REGEX, "");
|
|
1111
|
+
}
|
|
1112
|
+
var SGR_SEQUENCE_REGEX = /^\x1b\[[0-9;]*m/;
|
|
1113
|
+
var TRAILING_SGR_REGEX = /(?:\x1b\[[0-9;]*m)+$/;
|
|
1114
|
+
function applyTerminalOutputToText(existing, chunk) {
|
|
1115
|
+
if (!chunk) return existing;
|
|
1116
|
+
let text = existing;
|
|
1117
|
+
let index = 0;
|
|
1118
|
+
while (index < chunk.length) {
|
|
1119
|
+
if (chunk[index] === "\x1B") {
|
|
1120
|
+
const sgr = SGR_SEQUENCE_REGEX.exec(chunk.slice(index));
|
|
1121
|
+
if (sgr) {
|
|
1122
|
+
text += sgr[0];
|
|
1123
|
+
index += sgr[0].length;
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
const osc = chunk.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
1127
|
+
if (osc) {
|
|
1128
|
+
index += osc[0].length;
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
const csi = chunk.slice(index).match(/^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/);
|
|
1132
|
+
if (csi) {
|
|
1133
|
+
index += csi[0].length;
|
|
1134
|
+
continue;
|
|
1135
|
+
}
|
|
1136
|
+
index += 1;
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
const ch = chunk[index];
|
|
1140
|
+
if (ch === "\r") {
|
|
1141
|
+
const lastNl = text.lastIndexOf("\n");
|
|
1142
|
+
text = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
|
|
1143
|
+
index += 1;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
if (ch === "\n") {
|
|
1147
|
+
text += "\n";
|
|
1148
|
+
index += 1;
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
if (ch === "\b") {
|
|
1152
|
+
const trailing = TRAILING_SGR_REGEX.exec(text);
|
|
1153
|
+
const sgrTail = trailing ? trailing[0] : "";
|
|
1154
|
+
const head = sgrTail ? text.slice(0, -sgrTail.length) : text;
|
|
1155
|
+
if (head.length > 0 && head[head.length - 1] !== "\n") {
|
|
1156
|
+
text = head.slice(0, -1) + sgrTail;
|
|
1157
|
+
}
|
|
1158
|
+
index += 1;
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
const code = ch.charCodeAt(0);
|
|
1162
|
+
if (code < 32 && ch !== " " || code === 127) {
|
|
1163
|
+
index += 1;
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
text += ch;
|
|
1167
|
+
index += 1;
|
|
1168
|
+
}
|
|
1169
|
+
return text;
|
|
1170
|
+
}
|
|
1171
|
+
function displayWidth(str) {
|
|
1172
|
+
let width = 0;
|
|
1173
|
+
for (const char of str) {
|
|
1174
|
+
const code = char.codePointAt(0) ?? 0;
|
|
1175
|
+
if (code < 32 || code === 127) continue;
|
|
1176
|
+
if (code >= 4352 && code <= 4447 || // 0x2768-0x2775 (ornamental brackets, incl. the ❯ prompt at U+276F)
|
|
1177
|
+
// render narrow in terminals; counting them wide drifts the cursor.
|
|
1178
|
+
code >= 9728 && code <= 10175 && !(code >= 10088 && code <= 10101) || // 0x2B00-0x2BFF (Misc Symbols and Arrows, incl. ⬢ U+2B22 used as the
|
|
1179
|
+
// status-line agent icon) render double-wide in common monospace fonts;
|
|
1180
|
+
// counting ⬢ as width 1 drifts the whole status line right of the icon.
|
|
1181
|
+
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 ‘ ’).
|
|
1182
|
+
// In CJK locale + CJK fonts these render double-wide like 全角 punctuation;
|
|
1183
|
+
// in English fonts they stay width 1. Follow the active locale so Chinese
|
|
1184
|
+
// replies align correctly without breaking English terminal output.
|
|
1185
|
+
getCliLocale() === "zh" && (code === 8220 || code === 8221 || code === 8216 || code === 8217)) {
|
|
1186
|
+
width += 2;
|
|
1187
|
+
} else {
|
|
1188
|
+
width += 1;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return width;
|
|
1192
|
+
}
|
|
1193
|
+
function visibleWidth(str) {
|
|
1194
|
+
return displayWidth(stripAnsi(str));
|
|
1195
|
+
}
|
|
1196
|
+
function truncateAnsi(text, maxWidth) {
|
|
1197
|
+
if (maxWidth <= 0) return "";
|
|
1198
|
+
if (visibleWidth(text) <= maxWidth) return text;
|
|
1199
|
+
let width = 0;
|
|
1200
|
+
let out = "";
|
|
1201
|
+
let i = 0;
|
|
1202
|
+
let sawAnsi = false;
|
|
1203
|
+
while (i < text.length) {
|
|
1204
|
+
if (text[i] === "\x1B" && text[i + 1] === "[") {
|
|
1205
|
+
sawAnsi = true;
|
|
1206
|
+
let j = i + 2;
|
|
1207
|
+
while (j < text.length) {
|
|
1208
|
+
const code = text.charCodeAt(j);
|
|
1209
|
+
j += 1;
|
|
1210
|
+
if (code >= 64 && code <= 126) break;
|
|
1211
|
+
}
|
|
1212
|
+
out += text.slice(i, j);
|
|
1213
|
+
i = j;
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
const codePoint = text.codePointAt(i) ?? 0;
|
|
1217
|
+
const char = String.fromCodePoint(codePoint);
|
|
1218
|
+
const charWidth = displayWidth(char);
|
|
1219
|
+
if (width + charWidth > maxWidth) break;
|
|
1220
|
+
out += char;
|
|
1221
|
+
width += charWidth;
|
|
1222
|
+
i += char.length;
|
|
1223
|
+
}
|
|
1224
|
+
return sawAnsi ? `${out}\x1B[0m` : out;
|
|
1225
|
+
}
|
|
1226
|
+
function fitAnsiLine(text, width, ellipsis = "\u2026") {
|
|
1227
|
+
if (width <= 0) return "";
|
|
1228
|
+
if (visibleWidth(text) <= width) return text;
|
|
1229
|
+
const ellipsisWidth = displayWidth(ellipsis);
|
|
1230
|
+
if (width < ellipsisWidth) return truncateAnsi(text, width);
|
|
1231
|
+
if (width === ellipsisWidth) return truncateAnsi(ellipsis, width) || truncateAnsi(text, width);
|
|
1232
|
+
return `${truncateAnsi(text, width - ellipsisWidth)}${ellipsis}`;
|
|
1233
|
+
}
|
|
1234
|
+
function countPhysicalLines(text, columns) {
|
|
1235
|
+
const lines = text.split("\n");
|
|
1236
|
+
let total = 0;
|
|
1237
|
+
for (const line of lines) {
|
|
1238
|
+
const width = displayWidth(line);
|
|
1239
|
+
total += Math.max(1, Math.ceil(width / columns));
|
|
1240
|
+
}
|
|
1241
|
+
return Math.max(total, 1);
|
|
1242
|
+
}
|
|
1243
|
+
function takeDisplayWidth(text, width) {
|
|
1244
|
+
let used = 0;
|
|
1245
|
+
let index = 0;
|
|
1246
|
+
for (const char of text) {
|
|
1247
|
+
const charWidth = displayWidth(char);
|
|
1248
|
+
if (used + charWidth > width && used > 0) break;
|
|
1249
|
+
used += charWidth;
|
|
1250
|
+
index += char.length;
|
|
1251
|
+
}
|
|
1252
|
+
return { prefix: text.slice(0, index), rest: text.slice(index) };
|
|
1253
|
+
}
|
|
1254
|
+
function padOrTruncateToWidth(text, width) {
|
|
1255
|
+
const textWidth = visibleWidth(text);
|
|
1256
|
+
if (textWidth > width) {
|
|
1257
|
+
return truncateAnsi(text, width);
|
|
1258
|
+
}
|
|
1259
|
+
return `${text}${" ".repeat(width - textWidth)}`;
|
|
1260
|
+
}
|
|
1261
|
+
var SGR_RESET_REGEX = /^\x1b\[0?m$/;
|
|
1262
|
+
function tokenizeAnsiLine(line) {
|
|
1263
|
+
const tokens = [];
|
|
1264
|
+
let index = 0;
|
|
1265
|
+
while (index < line.length) {
|
|
1266
|
+
if (line[index] === "\x1B") {
|
|
1267
|
+
const osc = line.slice(index).match(/^\x1b\]8;;[^\x07\x1b]*(?:\x07|\x1b\\)/);
|
|
1268
|
+
if (osc) {
|
|
1269
|
+
tokens.push({ kind: "sgr", value: osc[0], width: 0 });
|
|
1270
|
+
index += osc[0].length;
|
|
1271
|
+
continue;
|
|
1272
|
+
}
|
|
1273
|
+
const sgr = SGR_SEQUENCE_REGEX.exec(line.slice(index));
|
|
1274
|
+
if (sgr) {
|
|
1275
|
+
tokens.push({ kind: "sgr", value: sgr[0], width: 0 });
|
|
1276
|
+
index += sgr[0].length;
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
const codePoint = line.codePointAt(index) ?? 0;
|
|
1281
|
+
const value = String.fromCodePoint(codePoint);
|
|
1282
|
+
tokens.push({ kind: "char", value, width: displayWidth(value) });
|
|
1283
|
+
index += value.length;
|
|
1284
|
+
}
|
|
1285
|
+
return tokens;
|
|
1286
|
+
}
|
|
1287
|
+
function wrapTranscriptLine(line, columns) {
|
|
1288
|
+
if (line === "") return [""];
|
|
1289
|
+
const tokens = tokenizeAnsiLine(line);
|
|
1290
|
+
const result = [];
|
|
1291
|
+
let activeStyles = [];
|
|
1292
|
+
const applyStyleToken = (value) => {
|
|
1293
|
+
if (SGR_RESET_REGEX.test(value)) {
|
|
1294
|
+
activeStyles = [];
|
|
1295
|
+
} else {
|
|
1296
|
+
activeStyles.push(value);
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
let start = 0;
|
|
1300
|
+
while (start < tokens.length) {
|
|
1301
|
+
if (tokens.slice(start).every((token) => token.kind === "sgr")) {
|
|
1302
|
+
if (result.length > 0) break;
|
|
1303
|
+
}
|
|
1304
|
+
const openingStyles = [...activeStyles];
|
|
1305
|
+
let width = 0;
|
|
1306
|
+
let end = start;
|
|
1307
|
+
let lastBreak = -1;
|
|
1308
|
+
while (end < tokens.length) {
|
|
1309
|
+
const token = tokens[end];
|
|
1310
|
+
if (token.kind === "sgr") {
|
|
1311
|
+
end += 1;
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
if (width + token.width > columns && width > 0) break;
|
|
1315
|
+
width += token.width;
|
|
1316
|
+
end += 1;
|
|
1317
|
+
if (token.value === " " || token.value === " ") {
|
|
1318
|
+
lastBreak = end;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
let segmentEnd = end;
|
|
1322
|
+
if (end < tokens.length && lastBreak > start) {
|
|
1323
|
+
const overflowToken = tokens[end];
|
|
1324
|
+
if (overflowToken.kind === "char" && overflowToken.value !== " " && overflowToken.width === 1) {
|
|
1325
|
+
segmentEnd = lastBreak;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (segmentEnd === start) segmentEnd = start + 1;
|
|
1329
|
+
let segment = "";
|
|
1330
|
+
let sawStyle = openingStyles.length > 0;
|
|
1331
|
+
for (let i = start; i < segmentEnd; i += 1) {
|
|
1332
|
+
const token = tokens[i];
|
|
1333
|
+
segment += token.value;
|
|
1334
|
+
if (token.kind === "sgr") {
|
|
1335
|
+
sawStyle = true;
|
|
1336
|
+
applyStyleToken(token.value);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const prefix = openingStyles.join("");
|
|
1340
|
+
const needsReset = (sawStyle || activeStyles.length > 0) && !segment.endsWith("\x1B[0m");
|
|
1341
|
+
result.push(`${prefix}${segment}${needsReset ? "\x1B[0m" : ""}`);
|
|
1342
|
+
start = segmentEnd;
|
|
1343
|
+
while (start < tokens.length) {
|
|
1344
|
+
const token = tokens[start];
|
|
1345
|
+
if (token.kind === "char" && token.value === " ") {
|
|
1346
|
+
start += 1;
|
|
1347
|
+
continue;
|
|
1348
|
+
}
|
|
1349
|
+
break;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return result.length > 0 ? result : [""];
|
|
1353
|
+
}
|
|
1354
|
+
function wrapTextToLines(text, columns) {
|
|
1355
|
+
const result = [];
|
|
1356
|
+
for (const logicalLine of text.split("\n")) {
|
|
1357
|
+
if (logicalLine === "") {
|
|
1358
|
+
result.push("");
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
let remaining = logicalLine;
|
|
1362
|
+
while (remaining.length > 0) {
|
|
1363
|
+
const { prefix, rest } = takeDisplayWidth(remaining, columns);
|
|
1364
|
+
result.push(prefix);
|
|
1365
|
+
remaining = rest;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return result;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// packages/cli/tui/theme.ts
|
|
1372
|
+
var THEME_PALETTES = {
|
|
1373
|
+
trail: {
|
|
1374
|
+
light: {
|
|
1375
|
+
accent: { hex: "2E7DB5", ansiFallback: "\x1B[34m" },
|
|
1376
|
+
// ocean blue
|
|
1377
|
+
chrome: { hex: "768594", ansiFallback: "\x1B[90m" },
|
|
1378
|
+
// slate — two steps below app placeholder A3B0BD (was 8A97A5); rules/tool markers on white need the extra notch
|
|
1379
|
+
success: { hex: "3F8F5C", ansiFallback: "\x1B[32m" },
|
|
1380
|
+
// moss green
|
|
1381
|
+
warning: { hex: "9A6A1F", ansiFallback: "\x1B[33m" },
|
|
1382
|
+
// deeper amber — B57F2E still read as yellow/washed on white (H2 headers like ## Plan floated); 9A6A1F raises contrast
|
|
1383
|
+
info: { hex: "4A9FD4", ansiFallback: "\x1B[36m" },
|
|
1384
|
+
// sky blue
|
|
1385
|
+
danger: { hex: "C45C4A", ansiFallback: "\x1B[31m" },
|
|
1386
|
+
// reddish
|
|
1387
|
+
muted: { hex: "5E6A78", ansiFallback: "\x1B[90m" }
|
|
1388
|
+
// denser slate — 687584 read too blue in dense prose (inline code/tool labels); 5E6A78 pulls blue down while staying darker than the old value
|
|
1389
|
+
},
|
|
1390
|
+
dark: {
|
|
1391
|
+
accent: { hex: "89B4FA", ansiFallback: "\x1B[34m" },
|
|
1392
|
+
// blue
|
|
1393
|
+
chrome: { hex: "6C7086", ansiFallback: "\x1B[90m" },
|
|
1394
|
+
success: { hex: "A6E3A1", ansiFallback: "\x1B[32m" },
|
|
1395
|
+
warning: { hex: "F9E2AF", ansiFallback: "\x1B[33m" },
|
|
1396
|
+
info: { hex: "94E2D5", ansiFallback: "\x1B[36m" },
|
|
1397
|
+
danger: { hex: "F38BA8", ansiFallback: "\x1B[31m" },
|
|
1398
|
+
muted: { hex: "9AA3B8", ansiFallback: "\x1B[90m" }
|
|
1399
|
+
// dimmed from A6ADC8 so secondary text sits a step below body text
|
|
1400
|
+
}
|
|
1401
|
+
},
|
|
1402
|
+
catppuccin: {
|
|
1403
|
+
light: {
|
|
1404
|
+
accent: { hex: "0969DA", ansiFallback: "\x1B[34m" },
|
|
1405
|
+
chrome: { hex: "57606A", ansiFallback: "\x1B[90m" },
|
|
1406
|
+
success: { hex: "116329", ansiFallback: "\x1B[32m" },
|
|
1407
|
+
warning: { hex: "9A6700", ansiFallback: "\x1B[33m" },
|
|
1408
|
+
info: { hex: "0969DA", ansiFallback: "\x1B[36m" },
|
|
1409
|
+
danger: { hex: "CF222E", ansiFallback: "\x1B[31m" },
|
|
1410
|
+
muted: { hex: "6E7781", ansiFallback: "\x1B[90m" }
|
|
1411
|
+
},
|
|
1412
|
+
dark: {
|
|
1413
|
+
accent: { hex: "58A6FF", ansiFallback: "\x1B[34m" },
|
|
1414
|
+
// GitHub sky blue
|
|
1415
|
+
chrome: { hex: "6E7681", ansiFallback: "\x1B[90m" },
|
|
1416
|
+
success: { hex: "3FB950", ansiFallback: "\x1B[32m" },
|
|
1417
|
+
warning: { hex: "D29922", ansiFallback: "\x1B[33m" },
|
|
1418
|
+
info: { hex: "58A6FF", ansiFallback: "\x1B[36m" },
|
|
1419
|
+
danger: { hex: "FF7B72", ansiFallback: "\x1B[31m" },
|
|
1420
|
+
muted: { hex: "B1BAC4", ansiFallback: "\x1B[90m" }
|
|
1421
|
+
}
|
|
1660
1422
|
},
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1423
|
+
wave: {
|
|
1424
|
+
light: {
|
|
1425
|
+
accent: { hex: "4D699B", ansiFallback: "\x1B[34m" },
|
|
1426
|
+
// ink blue
|
|
1427
|
+
chrome: { hex: "9E9B8E", ansiFallback: "\x1B[90m" },
|
|
1428
|
+
success: { hex: "6F894E", ansiFallback: "\x1B[32m" },
|
|
1429
|
+
warning: { hex: "836F4A", ansiFallback: "\x1B[33m" },
|
|
1430
|
+
info: { hex: "4D699B", ansiFallback: "\x1B[36m" },
|
|
1431
|
+
danger: { hex: "C84053", ansiFallback: "\x1B[31m" },
|
|
1432
|
+
muted: { hex: "716E61", ansiFallback: "\x1B[90m" }
|
|
1433
|
+
},
|
|
1434
|
+
dark: {
|
|
1435
|
+
accent: { hex: "7E9CD8", ansiFallback: "\x1B[34m" },
|
|
1436
|
+
// crystalBlue
|
|
1437
|
+
chrome: { hex: "727169", ansiFallback: "\x1B[90m" },
|
|
1438
|
+
success: { hex: "98BB6C", ansiFallback: "\x1B[32m" },
|
|
1439
|
+
warning: { hex: "E6C384", ansiFallback: "\x1B[33m" },
|
|
1440
|
+
info: { hex: "7FB4CA", ansiFallback: "\x1B[36m" },
|
|
1441
|
+
danger: { hex: "E82424", ansiFallback: "\x1B[31m" },
|
|
1442
|
+
muted: { hex: "938AA9", ansiFallback: "\x1B[90m" }
|
|
1443
|
+
}
|
|
1664
1444
|
},
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1445
|
+
iris: {
|
|
1446
|
+
light: {
|
|
1447
|
+
accent: { hex: "5E6AD2", ansiFallback: "\x1B[34m" },
|
|
1448
|
+
chrome: { hex: "9E9AB5", ansiFallback: "\x1B[90m" },
|
|
1449
|
+
success: { hex: "16A34A", ansiFallback: "\x1B[32m" },
|
|
1450
|
+
warning: { hex: "D97706", ansiFallback: "\x1B[33m" },
|
|
1451
|
+
info: { hex: "5E6AD2", ansiFallback: "\x1B[36m" },
|
|
1452
|
+
danger: { hex: "E5484D", ansiFallback: "\x1B[31m" },
|
|
1453
|
+
muted: { hex: "6E6A8A", ansiFallback: "\x1B[90m" }
|
|
1454
|
+
},
|
|
1455
|
+
dark: {
|
|
1456
|
+
accent: { hex: "8B9CF4", ansiFallback: "\x1B[34m" },
|
|
1457
|
+
chrome: { hex: "5A5772", ansiFallback: "\x1B[90m" },
|
|
1458
|
+
success: { hex: "26BD6C", ansiFallback: "\x1B[32m" },
|
|
1459
|
+
warning: { hex: "F5A623", ansiFallback: "\x1B[33m" },
|
|
1460
|
+
info: { hex: "8B9CF4", ansiFallback: "\x1B[36m" },
|
|
1461
|
+
danger: { hex: "EC5B6E", ansiFallback: "\x1B[31m" },
|
|
1462
|
+
muted: { hex: "938AA9", ansiFallback: "\x1B[90m" }
|
|
1463
|
+
}
|
|
1668
1464
|
},
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1465
|
+
rose: {
|
|
1466
|
+
light: {
|
|
1467
|
+
accent: { hex: "D14D72", ansiFallback: "\x1B[35m" },
|
|
1468
|
+
chrome: { hex: "9893A5", ansiFallback: "\x1B[90m" },
|
|
1469
|
+
success: { hex: "56949F", ansiFallback: "\x1B[32m" },
|
|
1470
|
+
warning: { hex: "EA9D34", ansiFallback: "\x1B[33m" },
|
|
1471
|
+
info: { hex: "286983", ansiFallback: "\x1B[36m" },
|
|
1472
|
+
danger: { hex: "B4637A", ansiFallback: "\x1B[31m" },
|
|
1473
|
+
muted: { hex: "797593", ansiFallback: "\x1B[90m" }
|
|
1474
|
+
},
|
|
1475
|
+
dark: {
|
|
1476
|
+
accent: { hex: "EB6F92", ansiFallback: "\x1B[35m" },
|
|
1477
|
+
chrome: { hex: "6E6A86", ansiFallback: "\x1B[90m" },
|
|
1478
|
+
success: { hex: "9CCFD8", ansiFallback: "\x1B[32m" },
|
|
1479
|
+
warning: { hex: "F6C177", ansiFallback: "\x1B[33m" },
|
|
1480
|
+
info: { hex: "C4A7E7", ansiFallback: "\x1B[36m" },
|
|
1481
|
+
danger: { hex: "EB6F92", ansiFallback: "\x1B[31m" },
|
|
1482
|
+
muted: { hex: "908CAA", ansiFallback: "\x1B[90m" }
|
|
1483
|
+
}
|
|
1672
1484
|
},
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
"
|
|
1676
|
-
"
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1485
|
+
mono: {
|
|
1486
|
+
light: {
|
|
1487
|
+
accent: { hex: "FF9500", ansiFallback: "\x1B[33m" },
|
|
1488
|
+
chrome: { hex: "9DA6AF", ansiFallback: "\x1B[90m" },
|
|
1489
|
+
success: { hex: "16A34A", ansiFallback: "\x1B[32m" },
|
|
1490
|
+
warning: { hex: "D97706", ansiFallback: "\x1B[33m" },
|
|
1491
|
+
info: { hex: "2563EB", ansiFallback: "\x1B[34m" },
|
|
1492
|
+
danger: { hex: "DC2626", ansiFallback: "\x1B[31m" },
|
|
1493
|
+
muted: { hex: "7B8793", ansiFallback: "\x1B[90m" }
|
|
1494
|
+
},
|
|
1495
|
+
dark: {
|
|
1496
|
+
accent: { hex: "FFBF66", ansiFallback: "\x1B[33m" },
|
|
1497
|
+
chrome: { hex: "7B8793", ansiFallback: "\x1B[90m" },
|
|
1498
|
+
success: { hex: "4DE800", ansiFallback: "\x1B[32m" },
|
|
1499
|
+
warning: { hex: "FCD34D", ansiFallback: "\x1B[33m" },
|
|
1500
|
+
info: { hex: "60A5FA", ansiFallback: "\x1B[34m" },
|
|
1501
|
+
danger: { hex: "F87171", ansiFallback: "\x1B[31m" },
|
|
1502
|
+
muted: { hex: "C1C7CD", ansiFallback: "\x1B[90m" }
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
var activeThemeName = "catppuccin";
|
|
1507
|
+
function getActiveThemeName() {
|
|
1508
|
+
return activeThemeName;
|
|
1509
|
+
}
|
|
1510
|
+
function setActiveThemeName(name) {
|
|
1511
|
+
if (THEME_PALETTES[name]) {
|
|
1512
|
+
activeThemeName = name;
|
|
1513
|
+
return true;
|
|
1514
|
+
}
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
var activeBrightness = null;
|
|
1518
|
+
function getActiveBrightness() {
|
|
1519
|
+
return activeBrightness;
|
|
1520
|
+
}
|
|
1521
|
+
function setActiveBrightness(brightness) {
|
|
1522
|
+
activeBrightness = brightness;
|
|
1523
|
+
}
|
|
1524
|
+
var activeDensity = "spacious";
|
|
1525
|
+
function getActiveDensity() {
|
|
1526
|
+
return activeDensity;
|
|
1527
|
+
}
|
|
1528
|
+
function setActiveDensity(density) {
|
|
1529
|
+
activeDensity = density;
|
|
1530
|
+
}
|
|
1531
|
+
var TRUECOLOR_TERM_PROGRAMS = /* @__PURE__ */ new Set([
|
|
1532
|
+
"iterm.app",
|
|
1533
|
+
"wezterm",
|
|
1534
|
+
"ghostty",
|
|
1535
|
+
"vscode",
|
|
1536
|
+
"hyper",
|
|
1537
|
+
"tabby",
|
|
1538
|
+
"rio",
|
|
1539
|
+
"warpterminal"
|
|
1540
|
+
]);
|
|
1541
|
+
function supportsTruecolor(env = process.env) {
|
|
1542
|
+
const explicit = (env.NOLO_TUI_TRUECOLOR ?? "").trim().toLowerCase();
|
|
1543
|
+
if (explicit === "1" || explicit === "true") return true;
|
|
1544
|
+
if (explicit === "0" || explicit === "false") return false;
|
|
1545
|
+
if (/truecolor|24bit/i.test(env.COLORTERM ?? "")) return true;
|
|
1546
|
+
if (/direct|24bit/i.test(env.TERM ?? "")) return true;
|
|
1547
|
+
const program = (env.TERM_PROGRAM ?? "").toLowerCase();
|
|
1548
|
+
return TRUECOLOR_TERM_PROGRAMS.has(program);
|
|
1549
|
+
}
|
|
1550
|
+
function resolveTuiBrightness(env = process.env) {
|
|
1551
|
+
const explicit = (env.NOLO_TUI_THEME ?? "").trim().toLowerCase();
|
|
1552
|
+
if (explicit === "light") return "light";
|
|
1553
|
+
if (explicit === "dark") return "dark";
|
|
1554
|
+
if (activeBrightness) return activeBrightness;
|
|
1555
|
+
const colorfgbg = env.COLORFGBG ?? "";
|
|
1556
|
+
if (colorfgbg) {
|
|
1557
|
+
const parts = colorfgbg.split(";");
|
|
1558
|
+
const bg = parts.length > 1 ? Number.parseInt(parts[1] ?? "", 10) : NaN;
|
|
1559
|
+
if (!Number.isNaN(bg) && bg >= 0 && bg <= 6) return "dark";
|
|
1560
|
+
if (!Number.isNaN(bg) && bg >= 7 && bg <= 15) return "light";
|
|
1561
|
+
}
|
|
1562
|
+
return "dark";
|
|
1563
|
+
}
|
|
1564
|
+
function hexToSgr(hex) {
|
|
1565
|
+
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
1566
|
+
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
1567
|
+
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
1568
|
+
return `\x1B[38;2;${r};${g};${b}m`;
|
|
1569
|
+
}
|
|
1570
|
+
var SURFACE_HEX = {
|
|
1571
|
+
trail: { light: "E4E8EC", dark: "313244" },
|
|
1572
|
+
catppuccin: { light: "E8ECF0", dark: "161B22" },
|
|
1573
|
+
wave: { light: "E5E1D6", dark: "2A2A37" },
|
|
1574
|
+
iris: { light: "E9E8F2", dark: "2A2740" },
|
|
1575
|
+
rose: { light: "F2EAE4", dark: "26233A" },
|
|
1576
|
+
mono: { light: "E8EAED", dark: "2A2A2A" }
|
|
1577
|
+
};
|
|
1578
|
+
var TERMINAL_BASE = {
|
|
1579
|
+
dark: "1E1E2E",
|
|
1580
|
+
light: "FFFFFF"
|
|
1581
|
+
};
|
|
1582
|
+
var activeTerminalBaseHex = null;
|
|
1583
|
+
function setActiveTerminalBaseHex(hex) {
|
|
1584
|
+
if (hex === null) {
|
|
1585
|
+
activeTerminalBaseHex = null;
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
activeTerminalBaseHex = readHexChannels(hex.replace(/^#/, "").toUpperCase()) ? hex.replace(/^#/, "").toUpperCase() : null;
|
|
1589
|
+
}
|
|
1590
|
+
function resolveTerminalBaseHex(brightness) {
|
|
1591
|
+
return activeTerminalBaseHex ?? TERMINAL_BASE[brightness];
|
|
1592
|
+
}
|
|
1593
|
+
function readHexChannels(hex) {
|
|
1594
|
+
if (!/^[0-9A-F]{6}$/.test(hex)) return null;
|
|
1595
|
+
return [
|
|
1596
|
+
Number.parseInt(hex.slice(0, 2), 16),
|
|
1597
|
+
Number.parseInt(hex.slice(2, 4), 16),
|
|
1598
|
+
Number.parseInt(hex.slice(4, 6), 16)
|
|
1599
|
+
];
|
|
1600
|
+
}
|
|
1601
|
+
function hexToBgSgr(hex) {
|
|
1602
|
+
const channels = readHexChannels(hex.replace(/^#/, "").toUpperCase());
|
|
1603
|
+
if (!channels) return "";
|
|
1604
|
+
const [r, g, b] = channels;
|
|
1605
|
+
return `\x1B[48;2;${r};${g};${b}m`;
|
|
1606
|
+
}
|
|
1607
|
+
function blendHex(fg, base, weight) {
|
|
1608
|
+
const w = Math.min(1, Math.max(0, weight));
|
|
1609
|
+
const normFg = fg.replace(/^#/, "").toUpperCase();
|
|
1610
|
+
const normBase = base.replace(/^#/, "").toUpperCase();
|
|
1611
|
+
if (w === 0) return normBase;
|
|
1612
|
+
if (w === 1) return normFg;
|
|
1613
|
+
if (!readHexChannels(normFg) || !readHexChannels(normBase)) return normBase;
|
|
1614
|
+
const fgR = Number.parseInt(normFg.slice(0, 2), 16);
|
|
1615
|
+
const fgG = Number.parseInt(normFg.slice(2, 4), 16);
|
|
1616
|
+
const fgB = Number.parseInt(normFg.slice(4, 6), 16);
|
|
1617
|
+
const baseR = Number.parseInt(normBase.slice(0, 2), 16);
|
|
1618
|
+
const baseG = Number.parseInt(normBase.slice(2, 4), 16);
|
|
1619
|
+
const baseB = Number.parseInt(normBase.slice(4, 6), 16);
|
|
1620
|
+
const r = Math.round(baseR + (fgR - baseR) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
1621
|
+
const g = Math.round(baseG + (fgG - baseG) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
1622
|
+
const b = Math.round(baseB + (fgB - baseB) * w).toString(16).padStart(2, "0").toUpperCase();
|
|
1623
|
+
return `${r}${g}${b}`;
|
|
1624
|
+
}
|
|
1625
|
+
function diffLineSequences(env = process.env, brightness = resolveTuiBrightness(env)) {
|
|
1626
|
+
if (!supportsTruecolor(env)) return null;
|
|
1627
|
+
const palette = THEME_PALETTES[activeThemeName] ?? THEME_PALETTES.trail;
|
|
1628
|
+
const successHex = palette[brightness].success.hex;
|
|
1629
|
+
const dangerHex = palette[brightness].danger.hex;
|
|
1630
|
+
const infoHex = palette[brightness].info.hex;
|
|
1631
|
+
const weight = brightness === "dark" ? 0.18 : 0.12;
|
|
1632
|
+
const baseHex = resolveTerminalBaseHex(brightness);
|
|
1633
|
+
const addedBgHex = blendHex(successHex, baseHex, weight);
|
|
1634
|
+
const removedBgHex = blendHex(dangerHex, baseHex, weight);
|
|
1635
|
+
const hunkBgHex = blendHex(infoHex, baseHex, weight * 0.6);
|
|
1636
|
+
const successSgr = hexToSgr(successHex);
|
|
1637
|
+
const dangerSgr = hexToSgr(dangerHex);
|
|
1638
|
+
const infoSgr = hexToSgr(infoHex);
|
|
1639
|
+
return {
|
|
1640
|
+
added: {
|
|
1641
|
+
fg: successSgr,
|
|
1642
|
+
bg: hexToBgSgr(addedBgHex),
|
|
1643
|
+
bar: `${successSgr}\u258C\x1B[39m`
|
|
1644
|
+
},
|
|
1645
|
+
removed: {
|
|
1646
|
+
fg: dangerSgr,
|
|
1647
|
+
bg: hexToBgSgr(removedBgHex),
|
|
1648
|
+
bar: `${dangerSgr}\u258C\x1B[39m`
|
|
1649
|
+
},
|
|
1650
|
+
hunk: {
|
|
1651
|
+
fg: infoSgr,
|
|
1652
|
+
bg: hexToBgSgr(hunkBgHex),
|
|
1653
|
+
bar: " "
|
|
1654
|
+
},
|
|
1655
|
+
context: { fg: "", bg: "", bar: " " }
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
function renderDiffLine(args) {
|
|
1659
|
+
const { kind, text } = args;
|
|
1660
|
+
const env = args.env ?? process.env;
|
|
1661
|
+
const colorEnabled = args.colorEnabled ?? resolveCliColorEnabled();
|
|
1662
|
+
if (!colorEnabled) return text;
|
|
1663
|
+
const seqs = diffLineSequences(env);
|
|
1664
|
+
if (!seqs) {
|
|
1665
|
+
if (kind === "context") return text;
|
|
1666
|
+
const token = kind === "added" ? "success" : kind === "removed" ? "danger" : "info";
|
|
1667
|
+
return `${themeColorSequence(token, env)}${text}\x1B[39m`;
|
|
1668
|
+
}
|
|
1669
|
+
const seq = seqs[kind];
|
|
1670
|
+
const padding = args.padTo === void 0 ? "" : " ".repeat(Math.max(0, args.padTo - displayWidth(text)));
|
|
1671
|
+
return `${seq.bar}${seq.bg}${seq.fg}${text}${padding}\x1B[0m`;
|
|
1672
|
+
}
|
|
1673
|
+
function surfaceBackgroundSequence(env = process.env, brightness = resolveTuiBrightness(env)) {
|
|
1674
|
+
if (!supportsTruecolor(env)) return "";
|
|
1675
|
+
return hexToBgSgr((SURFACE_HEX[activeThemeName] ?? SURFACE_HEX.trail)[brightness]);
|
|
1676
|
+
}
|
|
1677
|
+
function themeColorSequence(token, env = process.env, brightness = resolveTuiBrightness(env)) {
|
|
1678
|
+
const palette = THEME_PALETTES[activeThemeName] ?? THEME_PALETTES.trail;
|
|
1679
|
+
const entry = palette[brightness][token];
|
|
1680
|
+
return supportsTruecolor(env) ? hexToSgr(entry.hex) : entry.ansiFallback;
|
|
1681
|
+
}
|
|
1682
|
+
function themeText(text, token, colorEnabled = resolveCliColorEnabled(), env = process.env) {
|
|
1683
|
+
if (!colorEnabled) return text;
|
|
1684
|
+
return `${themeColorSequence(token, env)}${text}\x1B[39m`;
|
|
1685
|
+
}
|
|
1686
|
+
function classifyDiffLine(line) {
|
|
1687
|
+
if (line.startsWith("@@")) return "hunk";
|
|
1688
|
+
if (line.startsWith("+") && !line.startsWith("+++")) return "added";
|
|
1689
|
+
if (line.startsWith("-") && !line.startsWith("---")) return "removed";
|
|
1690
|
+
return "context";
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
// packages/cli/client/assistantOutput.ts
|
|
1694
|
+
var STYLE = {
|
|
1695
|
+
reset: "\x1B[0m",
|
|
1696
|
+
bold: "\x1B[1m",
|
|
1697
|
+
dim: "\x1B[2m"
|
|
1698
|
+
};
|
|
1699
|
+
function colorSeq(token, brightness) {
|
|
1700
|
+
return themeColorSequence(token, process.env, brightness);
|
|
1701
|
+
}
|
|
1702
|
+
function splitTableCells(line) {
|
|
1703
|
+
const trimmed = line.trim();
|
|
1704
|
+
if (!trimmed.includes("|")) return [];
|
|
1705
|
+
const core = trimmed.replace(/^\|/, "").replace(/\|$/, "");
|
|
1706
|
+
return core.split("|").map((cell) => cell.trim()).filter(Boolean);
|
|
1707
|
+
}
|
|
1708
|
+
function isTableSeparator(line) {
|
|
1709
|
+
const cells = splitTableCells(line);
|
|
1710
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
1711
|
+
}
|
|
1712
|
+
function isTableRow(line) {
|
|
1713
|
+
const cells = splitTableCells(line);
|
|
1714
|
+
return cells.length >= 2 && cells.some((cell) => cell.length > 0);
|
|
1715
|
+
}
|
|
1716
|
+
function isPipeWrappedTableRow(line) {
|
|
1717
|
+
const trimmed = line.trim();
|
|
1718
|
+
return trimmed.startsWith("|") && trimmed.endsWith("|") && isTableRow(line);
|
|
1719
|
+
}
|
|
1720
|
+
function isCodeFenceLine(line) {
|
|
1721
|
+
return /^\s*```/.test(line);
|
|
1722
|
+
}
|
|
1723
|
+
function readFenceLanguage(line) {
|
|
1724
|
+
const m = line.match(/^\s*```\s*([a-zA-Z0-9+#_-]*)/);
|
|
1725
|
+
return m ? (m[1] ?? "").toLowerCase() : "";
|
|
1726
|
+
}
|
|
1727
|
+
function normalizeCodeLang(raw) {
|
|
1728
|
+
switch (raw) {
|
|
1729
|
+
case "js":
|
|
1730
|
+
case "jsx":
|
|
1731
|
+
case "ts":
|
|
1732
|
+
case "tsx":
|
|
1733
|
+
case "javascript":
|
|
1734
|
+
case "typescript":
|
|
1735
|
+
return "js";
|
|
1736
|
+
case "py":
|
|
1737
|
+
case "python":
|
|
1738
|
+
return "py";
|
|
1739
|
+
case "sh":
|
|
1740
|
+
case "bash":
|
|
1741
|
+
case "zsh":
|
|
1742
|
+
case "shell":
|
|
1743
|
+
case "console":
|
|
1744
|
+
return "sh";
|
|
1745
|
+
case "json":
|
|
1746
|
+
return "json";
|
|
1747
|
+
case "diff":
|
|
1748
|
+
return "diff";
|
|
1749
|
+
default:
|
|
1750
|
+
return "unknown";
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
var KEYWORDS = {
|
|
1754
|
+
js: /* @__PURE__ */ new Set([
|
|
1755
|
+
"const",
|
|
1756
|
+
"let",
|
|
1757
|
+
"var",
|
|
1758
|
+
"function",
|
|
1759
|
+
"return",
|
|
1760
|
+
"if",
|
|
1761
|
+
"else",
|
|
1762
|
+
"for",
|
|
1763
|
+
"while",
|
|
1764
|
+
"class",
|
|
1765
|
+
"new",
|
|
1766
|
+
"await",
|
|
1767
|
+
"async",
|
|
1768
|
+
"import",
|
|
1769
|
+
"export",
|
|
1770
|
+
"from",
|
|
1771
|
+
"type",
|
|
1772
|
+
"interface",
|
|
1773
|
+
"extends",
|
|
1774
|
+
"implements",
|
|
1775
|
+
"null",
|
|
1776
|
+
"undefined",
|
|
1777
|
+
"true",
|
|
1778
|
+
"false"
|
|
1779
|
+
]),
|
|
1780
|
+
py: /* @__PURE__ */ new Set([
|
|
1781
|
+
"def",
|
|
1782
|
+
"class",
|
|
1783
|
+
"return",
|
|
1784
|
+
"if",
|
|
1785
|
+
"elif",
|
|
1786
|
+
"else",
|
|
1787
|
+
"for",
|
|
1788
|
+
"while",
|
|
1789
|
+
"import",
|
|
1790
|
+
"from",
|
|
1791
|
+
"as",
|
|
1792
|
+
"with",
|
|
1793
|
+
"try",
|
|
1794
|
+
"except",
|
|
1795
|
+
"finally",
|
|
1796
|
+
"lambda",
|
|
1797
|
+
"None",
|
|
1798
|
+
"True",
|
|
1799
|
+
"False",
|
|
1800
|
+
"self"
|
|
1801
|
+
]),
|
|
1802
|
+
sh: /* @__PURE__ */ new Set([
|
|
1803
|
+
"if",
|
|
1804
|
+
"then",
|
|
1805
|
+
"else",
|
|
1806
|
+
"fi",
|
|
1807
|
+
"for",
|
|
1808
|
+
"do",
|
|
1809
|
+
"done",
|
|
1810
|
+
"while",
|
|
1811
|
+
"case",
|
|
1812
|
+
"esac",
|
|
1813
|
+
"function",
|
|
1814
|
+
"export",
|
|
1815
|
+
"local",
|
|
1816
|
+
"return",
|
|
1817
|
+
"source",
|
|
1818
|
+
"echo",
|
|
1819
|
+
"cd"
|
|
1820
|
+
]),
|
|
1821
|
+
json: /* @__PURE__ */ new Set(["true", "false", "null"]),
|
|
1822
|
+
diff: /* @__PURE__ */ new Set([])
|
|
1823
|
+
};
|
|
1824
|
+
function scanStringCommentRegions(line, lang) {
|
|
1825
|
+
const regions = [];
|
|
1826
|
+
const n = line.length;
|
|
1827
|
+
let i = 0;
|
|
1828
|
+
const commentMarkers = lang === "py" || lang === "sh" ? ["#"] : ["//"];
|
|
1829
|
+
while (i < n) {
|
|
1830
|
+
const ch = line[i];
|
|
1831
|
+
if (ch === "'" || ch === '"' || lang === "js" && ch === "`") {
|
|
1832
|
+
const quote = ch;
|
|
1833
|
+
const start = i;
|
|
1834
|
+
i += 1;
|
|
1835
|
+
while (i < n) {
|
|
1836
|
+
if (line[i] === "\\") {
|
|
1837
|
+
i += 2;
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
if (line[i] === quote) {
|
|
1841
|
+
i += 1;
|
|
1842
|
+
break;
|
|
1843
|
+
}
|
|
1844
|
+
i += 1;
|
|
1845
|
+
}
|
|
1846
|
+
regions.push({ start, end: i, kind: "string" });
|
|
1847
|
+
continue;
|
|
1848
|
+
}
|
|
1849
|
+
let matched = false;
|
|
1850
|
+
for (const marker of commentMarkers) {
|
|
1851
|
+
if (line.startsWith(marker, i)) {
|
|
1852
|
+
regions.push({ start: i, end: n, kind: "comment" });
|
|
1853
|
+
i = n;
|
|
1854
|
+
matched = true;
|
|
1855
|
+
break;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
if (matched) continue;
|
|
1859
|
+
i += 1;
|
|
1860
|
+
}
|
|
1861
|
+
return regions;
|
|
1862
|
+
}
|
|
1863
|
+
function highlightCodeLine(line, lang, brightness) {
|
|
1864
|
+
const info = colorSeq("info", brightness);
|
|
1865
|
+
if (lang === "unknown") {
|
|
1866
|
+
return `${info}${line}${STYLE.reset}`;
|
|
1867
|
+
}
|
|
1868
|
+
if (lang === "diff") {
|
|
1869
|
+
return renderDiffLine({ kind: classifyDiffLine(line), text: line, colorEnabled: true });
|
|
1870
|
+
}
|
|
1871
|
+
const regions = scanStringCommentRegions(line, lang);
|
|
1872
|
+
const keywords = KEYWORDS[lang];
|
|
1873
|
+
const accent = colorSeq("accent", brightness);
|
|
1874
|
+
const success = colorSeq("success", brightness);
|
|
1875
|
+
const warning = colorSeq("warning", brightness);
|
|
1876
|
+
const chrome = colorSeq("chrome", brightness);
|
|
1877
|
+
const dim = STYLE.dim;
|
|
1878
|
+
const reset = STYLE.reset;
|
|
1879
|
+
const out = [];
|
|
1880
|
+
let cursor = 0;
|
|
1881
|
+
for (const region of regions) {
|
|
1882
|
+
if (region.start > cursor) {
|
|
1883
|
+
out.push(emitPlainGap(line.slice(cursor, region.start), keywords, info, accent, warning, reset));
|
|
1884
|
+
}
|
|
1885
|
+
const text = line.slice(region.start, region.end);
|
|
1886
|
+
if (region.kind === "string") {
|
|
1887
|
+
out.push(`${success}${text}${reset}`);
|
|
1888
|
+
} else {
|
|
1889
|
+
out.push(`${chrome}${dim}${text}${reset}`);
|
|
1890
|
+
}
|
|
1891
|
+
cursor = region.end;
|
|
1892
|
+
}
|
|
1893
|
+
if (cursor < line.length) {
|
|
1894
|
+
out.push(emitPlainGap(line.slice(cursor), keywords, info, accent, warning, reset));
|
|
1895
|
+
}
|
|
1896
|
+
return out.join("");
|
|
1897
|
+
}
|
|
1898
|
+
function emitPlainGap(text, keywords, info, accent, warning, reset) {
|
|
1899
|
+
const parts = [];
|
|
1900
|
+
const re = /([A-Za-z_]\w*)|(\d+(?:\.\d+)?)|([\s\S])/g;
|
|
1901
|
+
let last = 0;
|
|
1902
|
+
let m;
|
|
1903
|
+
let started = false;
|
|
1904
|
+
while ((m = re.exec(text)) !== null) {
|
|
1905
|
+
if (!started) {
|
|
1906
|
+
started = true;
|
|
1907
|
+
}
|
|
1908
|
+
if (m.index > last) {
|
|
1909
|
+
parts.push(`${info}${text.slice(last, m.index)}`);
|
|
1910
|
+
}
|
|
1911
|
+
if (m[1] !== void 0) {
|
|
1912
|
+
const word = m[1];
|
|
1913
|
+
if (keywords.has(word)) {
|
|
1914
|
+
parts.push(`${accent}${word}${reset}`);
|
|
1915
|
+
} else {
|
|
1916
|
+
parts.push(`${info}${word}`);
|
|
1917
|
+
}
|
|
1918
|
+
} else if (m[2] !== void 0) {
|
|
1919
|
+
parts.push(`${warning}${m[2]}${reset}`);
|
|
1920
|
+
} else {
|
|
1921
|
+
parts.push(`${info}${m[3]}`);
|
|
1922
|
+
}
|
|
1923
|
+
last = re.lastIndex;
|
|
1924
|
+
}
|
|
1925
|
+
if (last < text.length) {
|
|
1926
|
+
parts.push(`${info}${text.slice(last)}`);
|
|
1927
|
+
}
|
|
1928
|
+
return parts.join("");
|
|
1929
|
+
}
|
|
1930
|
+
function tableRowToBullet(line) {
|
|
1931
|
+
const row = splitTableCells(line);
|
|
1932
|
+
const label = row[0] ?? "";
|
|
1933
|
+
const detail = row.slice(1).join(" \u2014 ").trim();
|
|
1934
|
+
return detail ? ` \u2022 ${label} \u2014 ${detail}` : ` \u2022 ${label}`;
|
|
1935
|
+
}
|
|
1936
|
+
var UNORDERED_LIST_RE = /^(\s*)([-*+])\s+(.+)$/;
|
|
1937
|
+
var ORDERED_LIST_RE = /^(\s*)(\d+)\.\s+(.+)$/;
|
|
1938
|
+
var TASK_LIST_RE = /^(\s*)([-*+])\s+\[([ xX])\]\s+(.+)$/;
|
|
1939
|
+
function normalizeListLine(line) {
|
|
1940
|
+
const task = line.match(TASK_LIST_RE);
|
|
1941
|
+
if (task) {
|
|
1942
|
+
const checked = task[3] === "x" || task[3] === "X";
|
|
1943
|
+
return `${task[1]}${checked ? "\u2611" : "\u2610"} ${task[4]}`;
|
|
1944
|
+
}
|
|
1945
|
+
const unordered = line.match(UNORDERED_LIST_RE);
|
|
1946
|
+
if (unordered) {
|
|
1947
|
+
return `${unordered[1]}\u2022 ${unordered[3]}`;
|
|
1948
|
+
}
|
|
1949
|
+
const ordered = line.match(ORDERED_LIST_RE);
|
|
1950
|
+
if (ordered) {
|
|
1951
|
+
return `${ordered[1]}${ordered[2]}. ${ordered[3]}`;
|
|
1952
|
+
}
|
|
1953
|
+
return line;
|
|
1954
|
+
}
|
|
1955
|
+
function convertMarkdownTablesForTerminal(text) {
|
|
1956
|
+
const lines = text.split("\n");
|
|
1957
|
+
const out = [];
|
|
1958
|
+
let inFence = false;
|
|
1959
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
1960
|
+
const line = lines[index] ?? "";
|
|
1961
|
+
if (isCodeFenceLine(line)) {
|
|
1962
|
+
inFence = !inFence;
|
|
1963
|
+
out.push(line);
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (inFence) {
|
|
1967
|
+
out.push(line);
|
|
1968
|
+
continue;
|
|
1969
|
+
}
|
|
1970
|
+
const next = lines[index + 1] ?? "";
|
|
1971
|
+
if (isTableRow(line) && isTableSeparator(next)) {
|
|
1972
|
+
index += 1;
|
|
1973
|
+
while (index + 1 < lines.length && isTableRow(lines[index + 1] ?? "") && !isTableSeparator(lines[index + 1] ?? "")) {
|
|
1974
|
+
index += 1;
|
|
1975
|
+
out.push(tableRowToBullet(lines[index] ?? ""));
|
|
1976
|
+
}
|
|
1977
|
+
if (out.length > 0 && out[out.length - 1] !== "") out.push("");
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
if (isPipeWrappedTableRow(line)) {
|
|
1981
|
+
if (!isTableSeparator(line)) out.push(tableRowToBullet(line));
|
|
1982
|
+
continue;
|
|
1983
|
+
}
|
|
1984
|
+
out.push(normalizeListLine(line));
|
|
1985
|
+
}
|
|
1986
|
+
return out.join("\n");
|
|
1987
|
+
}
|
|
1988
|
+
function polishAssistantStructure(text, options = {}) {
|
|
1989
|
+
const converted = convertMarkdownTablesForTerminal(text).replace(/\r\n/g, "\n").replace(/\x00/g, "");
|
|
1990
|
+
const lines = converted.split("\n");
|
|
1991
|
+
let inFence = false;
|
|
1992
|
+
const maskedLines = lines.map((line, index) => {
|
|
1993
|
+
if (isCodeFenceLine(line)) {
|
|
1994
|
+
inFence = !inFence;
|
|
1995
|
+
return line;
|
|
1996
|
+
}
|
|
1997
|
+
if (inFence) {
|
|
1998
|
+
return `\0F${index}\0`;
|
|
1999
|
+
}
|
|
2000
|
+
return line;
|
|
2001
|
+
});
|
|
2002
|
+
const afterHeading = maskedLines.join("\n").replace(/([^\n])\n(#{1,3} )/g, "$1\n\n$2").replace(/^(#{1,3} .+)\n(?!\n)/gm, "$1\n\n").replace(/\n{4,}/g, "\n\n\n");
|
|
2003
|
+
const LIST_LIKE = /^\s*(?:•|☐|☑|\d+\.)\s|^\s*[\u2460-\u2473]/;
|
|
2004
|
+
const headingLines = afterHeading.split("\n");
|
|
2005
|
+
const breathed = [];
|
|
2006
|
+
for (let i = 0; i < headingLines.length; i++) {
|
|
2007
|
+
breathed.push(headingLines[i]);
|
|
2008
|
+
const cur = headingLines[i];
|
|
2009
|
+
const next = headingLines[i + 1];
|
|
2010
|
+
if (cur === "" || next === void 0 || next === "") continue;
|
|
2011
|
+
if (LIST_LIKE.test(cur) === LIST_LIKE.test(next)) continue;
|
|
2012
|
+
breathed.push("");
|
|
2013
|
+
}
|
|
2014
|
+
const polishedMasked = breathed.join("\n");
|
|
2015
|
+
const polished = polishedMasked.replace(
|
|
2016
|
+
/\x00F(\d+)\x00/g,
|
|
2017
|
+
(_, id) => lines[Number(id)] ?? ""
|
|
2018
|
+
);
|
|
2019
|
+
return options.trimEdges === false ? polished : polished.trim();
|
|
2020
|
+
}
|
|
2021
|
+
function renderMarkdownLink(match, text, url) {
|
|
2022
|
+
const visible = `${text} (${url})`;
|
|
2023
|
+
return `\x1B]8;;${url}\x1B\\${visible}\x1B]8;;\x1B\\`;
|
|
2024
|
+
}
|
|
2025
|
+
var MARKDOWN_LINK_RE = /\[([^\]]+)\]\(([^)\s]+)\)/g;
|
|
2026
|
+
function styleInlineMarkdown(line, brightness) {
|
|
2027
|
+
const inlineCode = colorSeq("muted", brightness);
|
|
2028
|
+
const reset = STYLE.reset;
|
|
2029
|
+
const bold = STYLE.bold;
|
|
2030
|
+
const dim = STYLE.dim;
|
|
2031
|
+
return line.replace(MARKDOWN_LINK_RE, (m, t2, u) => renderMarkdownLink(m, t2, u)).replace(/`([^`]+)`/g, `${inlineCode}$1${reset}`).replace(/\*\*(.+?)\*\*/g, `${bold}$1${reset}`).replace(/(?<!\*)\*([^*]+?)\*(?!\*)/g, `${dim}$1${reset}`).replace(/~~([^~]+?)~~/g, `${dim}\x1B[9m$1\x1B[29m${reset}`);
|
|
2032
|
+
}
|
|
2033
|
+
function styleRichMarkdownLine(line, brightness) {
|
|
2034
|
+
const heading = line.match(/^(#{1,3})\s+(.+)$/);
|
|
2035
|
+
if (heading) {
|
|
2036
|
+
const level = heading[1].length;
|
|
2037
|
+
const title = heading[2];
|
|
2038
|
+
if (level === 1) {
|
|
2039
|
+
return `${STYLE.bold}\x1B[4m${colorSeq("accent", brightness)}${title}${STYLE.reset}`;
|
|
2040
|
+
}
|
|
2041
|
+
if (level === 2) {
|
|
2042
|
+
return `${STYLE.bold}${colorSeq("warning", brightness)}${title}${STYLE.reset}`;
|
|
2043
|
+
}
|
|
2044
|
+
return `${STYLE.bold}${colorSeq("info", brightness)}${title}${STYLE.reset}`;
|
|
2045
|
+
}
|
|
2046
|
+
if (line.startsWith("\u8FDB\u5165 nolo-plan")) {
|
|
2047
|
+
return `${colorSeq("chrome", brightness)}${STYLE.dim}${line}${STYLE.reset}`;
|
|
2048
|
+
}
|
|
2049
|
+
const blockquote = line.match(/^>\s?(.*)$/);
|
|
2050
|
+
if (blockquote) {
|
|
2051
|
+
const border = colorSeq("chrome", brightness);
|
|
2052
|
+
const content = blockquote[1];
|
|
2053
|
+
return `${border}\u2502${STYLE.reset} ${STYLE.dim}${content}${STYLE.reset}`;
|
|
2054
|
+
}
|
|
2055
|
+
if (/^---+$/.test(line.trim())) {
|
|
2056
|
+
return `${colorSeq("chrome", brightness)}${"\u2500".repeat(Math.min(line.trim().length, 40))}${STYLE.reset}`;
|
|
2057
|
+
}
|
|
2058
|
+
const bullet = line.match(/^(\s*)(•)\s(.+)$/);
|
|
2059
|
+
if (bullet) {
|
|
2060
|
+
const styled = styleInlineMarkdown(bullet[3], brightness);
|
|
2061
|
+
return `${bullet[1]}${colorSeq("accent", brightness)}\u2022${STYLE.reset} ${styled}`;
|
|
2062
|
+
}
|
|
2063
|
+
const ordered = line.match(/^(\s*)(\d+\.)\s(.+)$/);
|
|
2064
|
+
if (ordered) {
|
|
2065
|
+
const styled = styleInlineMarkdown(ordered[3], brightness);
|
|
2066
|
+
return `${ordered[1]}${colorSeq("accent", brightness)}${ordered[2]}${STYLE.reset} ${styled}`;
|
|
2067
|
+
}
|
|
2068
|
+
const task = line.match(/^(\s*)(☐|☑)\s(.+)$/);
|
|
2069
|
+
if (task) {
|
|
2070
|
+
const styled = styleInlineMarkdown(task[3], brightness);
|
|
2071
|
+
return `${task[1]}${colorSeq("accent", brightness)}${task[2]}${STYLE.reset} ${styled}`;
|
|
2072
|
+
}
|
|
2073
|
+
return styleInlineMarkdown(line, brightness);
|
|
2074
|
+
}
|
|
2075
|
+
function formatAssistantDisplay(text, options = {}) {
|
|
2076
|
+
const brightness = resolveTuiBrightness();
|
|
2077
|
+
const polished = polishAssistantStructure(text, options);
|
|
2078
|
+
let inFence = false;
|
|
2079
|
+
let fenceLang = "unknown";
|
|
2080
|
+
return polished.split("\n").map((line) => {
|
|
2081
|
+
if (isCodeFenceLine(line)) {
|
|
2082
|
+
if (inFence) {
|
|
2083
|
+
fenceLang = "unknown";
|
|
2084
|
+
} else {
|
|
2085
|
+
fenceLang = normalizeCodeLang(readFenceLanguage(line));
|
|
2086
|
+
}
|
|
2087
|
+
inFence = !inFence;
|
|
2088
|
+
return `${STYLE.dim}${line}${STYLE.reset}`;
|
|
2089
|
+
}
|
|
2090
|
+
if (inFence) {
|
|
2091
|
+
return highlightCodeLine(line, fenceLang, brightness);
|
|
2092
|
+
}
|
|
2093
|
+
return styleRichMarkdownLine(line, brightness);
|
|
2094
|
+
}).join("\n");
|
|
2095
|
+
}
|
|
2096
|
+
function emitFormattedAssistantBlock(write, text, trailingNewline = false) {
|
|
2097
|
+
if (!text) return;
|
|
2098
|
+
write(formatAssistantDisplay(text, { trimEdges: false }));
|
|
2099
|
+
if (trailingNewline) write("\n");
|
|
2100
|
+
}
|
|
2101
|
+
function classifyStreamLine(line) {
|
|
2102
|
+
if (line === "") return "blank";
|
|
2103
|
+
if (TASK_LIST_RE.test(line) || UNORDERED_LIST_RE.test(line) || ORDERED_LIST_RE.test(line) || /^\s*(?:•|☐|☑)\s/.test(line) || /^\s*[\u2460-\u2473]/.test(line)) {
|
|
2104
|
+
return "list";
|
|
2105
|
+
}
|
|
2106
|
+
return "prose";
|
|
2107
|
+
}
|
|
2108
|
+
function needsListProseBreath(prev, next) {
|
|
2109
|
+
if (prev === null || prev === "blank" || next === "blank") return false;
|
|
2110
|
+
const prevList = prev === "list";
|
|
2111
|
+
const nextList = next === "list";
|
|
2112
|
+
return prevList !== nextList;
|
|
2113
|
+
}
|
|
2114
|
+
function createRenderAwareStreamWriter(args) {
|
|
2115
|
+
const brightness = resolveTuiBrightness();
|
|
2116
|
+
let buffer = "";
|
|
2117
|
+
let inFence = false;
|
|
2118
|
+
let fenceLang = "unknown";
|
|
2119
|
+
let lastKind = null;
|
|
2120
|
+
const emitBreathIfNeeded = (nextKind) => {
|
|
2121
|
+
if (needsListProseBreath(lastKind, nextKind)) args.write("\n");
|
|
2122
|
+
};
|
|
2123
|
+
const flushCompleteBlocks = () => {
|
|
2124
|
+
while (buffer.includes("\n")) {
|
|
2125
|
+
const lines = buffer.split("\n");
|
|
2126
|
+
if (lines.length < 2) break;
|
|
2127
|
+
const firstLine = lines[0] ?? "";
|
|
2128
|
+
if (isCodeFenceLine(firstLine)) {
|
|
2129
|
+
if (inFence) {
|
|
2130
|
+
fenceLang = "unknown";
|
|
2131
|
+
} else {
|
|
2132
|
+
fenceLang = normalizeCodeLang(readFenceLanguage(firstLine));
|
|
2133
|
+
}
|
|
2134
|
+
inFence = !inFence;
|
|
2135
|
+
emitBreathIfNeeded("other");
|
|
2136
|
+
args.write(`${STYLE.dim}${firstLine}${STYLE.reset}
|
|
2137
|
+
`);
|
|
2138
|
+
lastKind = "other";
|
|
2139
|
+
buffer = lines.slice(1).join("\n");
|
|
2140
|
+
continue;
|
|
2141
|
+
}
|
|
2142
|
+
if (inFence) {
|
|
2143
|
+
args.write(`${highlightCodeLine(firstLine, fenceLang, brightness)}
|
|
2144
|
+
`);
|
|
2145
|
+
lastKind = "other";
|
|
2146
|
+
buffer = lines.slice(1).join("\n");
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
if (isTableRow(firstLine)) {
|
|
2150
|
+
const nextLineComplete = lines.length > 2;
|
|
2151
|
+
if (!nextLineComplete) break;
|
|
2152
|
+
if (isTableSeparator(lines[1] ?? "")) {
|
|
2153
|
+
let end = 2;
|
|
2154
|
+
while (end < lines.length && isTableRow(lines[end] ?? "") && !isTableSeparator(lines[end] ?? "")) {
|
|
2155
|
+
end += 1;
|
|
2156
|
+
}
|
|
2157
|
+
const tableComplete = end < lines.length - 1;
|
|
2158
|
+
if (!tableComplete) break;
|
|
2159
|
+
emitBreathIfNeeded("list");
|
|
2160
|
+
emitFormattedAssistantBlock(
|
|
2161
|
+
args.write,
|
|
2162
|
+
lines.slice(0, end).join("\n"),
|
|
2163
|
+
true
|
|
2164
|
+
);
|
|
2165
|
+
lastKind = "list";
|
|
2166
|
+
buffer = lines.slice(end).join("\n");
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
const kind = classifyStreamLine(firstLine);
|
|
2171
|
+
emitBreathIfNeeded(kind);
|
|
2172
|
+
emitFormattedAssistantBlock(args.write, firstLine, true);
|
|
2173
|
+
lastKind = kind;
|
|
2174
|
+
buffer = lines.slice(1).join("\n");
|
|
2175
|
+
}
|
|
2176
|
+
};
|
|
2177
|
+
return {
|
|
2178
|
+
push(chunk) {
|
|
2179
|
+
if (!chunk) return;
|
|
2180
|
+
buffer += chunk;
|
|
2181
|
+
flushCompleteBlocks();
|
|
2182
|
+
},
|
|
2183
|
+
flush() {
|
|
2184
|
+
if (!buffer) return;
|
|
2185
|
+
if (inFence) {
|
|
2186
|
+
args.write(buffer);
|
|
2187
|
+
} else {
|
|
2188
|
+
emitFormattedAssistantBlock(args.write, buffer);
|
|
2189
|
+
}
|
|
2190
|
+
buffer = "";
|
|
2191
|
+
}
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
// packages/cli/client/thinkingOutput.ts
|
|
2196
|
+
var THINK_OPEN = /<think>/i;
|
|
2197
|
+
var THINK_CLOSE = /<\/think>/i;
|
|
2198
|
+
var COLLAPSED_MARKER = /^\s*▸ 思考已折叠\s*$/;
|
|
2199
|
+
function normalizeThinkingDisplayMode(raw, fallback = "hide") {
|
|
2200
|
+
const normalized = asTrimmedLowercaseString(raw);
|
|
2201
|
+
if (normalized === "hide" || normalized === "off" || normalized === "false" || normalized === "0") {
|
|
2202
|
+
return "hide";
|
|
2203
|
+
}
|
|
2204
|
+
if (normalized === "marker" || normalized === "collapsed" || normalized === "fold") {
|
|
2205
|
+
return "marker";
|
|
2206
|
+
}
|
|
2207
|
+
if (normalized === "show" || normalized === "on" || normalized === "true" || normalized === "1") {
|
|
2208
|
+
return "show";
|
|
2209
|
+
}
|
|
2210
|
+
return fallback;
|
|
2211
|
+
}
|
|
2212
|
+
function resolveThinkingDisplayMode(env = process.env) {
|
|
2213
|
+
return normalizeThinkingDisplayMode(env.NOLO_CLI_THINKING ?? env.NOLO_THINKING, "hide");
|
|
2214
|
+
}
|
|
2215
|
+
function collapseThinkingBlocks(text, mode = "hide") {
|
|
2216
|
+
if (mode === "show") return text;
|
|
2217
|
+
const replacement = mode === "marker" ? "\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n" : "";
|
|
2218
|
+
return text.replace(/<think>[\s\S]*?<\/think>\s*/gi, replacement).replace(/\n{3,}/g, "\n\n").trim();
|
|
2219
|
+
}
|
|
2220
|
+
function stripCollapsedThinkingMarkers(text) {
|
|
2221
|
+
return text.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n").replace(/\n{2,}/g, "\n").trim();
|
|
2222
|
+
}
|
|
2223
|
+
function formatAssistantTextForCli(text, mode = "hide") {
|
|
2224
|
+
const collapsed = collapseThinkingBlocks(text, mode);
|
|
2225
|
+
return mode === "hide" ? stripCollapsedThinkingMarkers(collapsed) : collapsed;
|
|
2226
|
+
}
|
|
2227
|
+
function createThinkingEventSink(arg1, arg2) {
|
|
2228
|
+
let mode = "hide";
|
|
2229
|
+
let write = () => {
|
|
2230
|
+
};
|
|
2231
|
+
if (typeof arg1 === "function") {
|
|
2232
|
+
write = arg1;
|
|
2233
|
+
if (typeof arg2 === "string") {
|
|
2234
|
+
mode = arg2;
|
|
2235
|
+
}
|
|
2236
|
+
} else {
|
|
2237
|
+
mode = arg1;
|
|
2238
|
+
if (typeof arg2 === "function") {
|
|
2239
|
+
write = arg2;
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
if (mode === "hide") {
|
|
2243
|
+
return {
|
|
2244
|
+
push(_chunk) {
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
if (mode === "show") {
|
|
2249
|
+
return {
|
|
2250
|
+
push(chunk) {
|
|
2251
|
+
if (chunk) write(chunk);
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
let markerEmitted = false;
|
|
2256
|
+
return {
|
|
2257
|
+
push(chunk) {
|
|
2258
|
+
if (!chunk || markerEmitted) return;
|
|
2259
|
+
write("\n\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n");
|
|
2260
|
+
markerEmitted = true;
|
|
2261
|
+
}
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
function createThinkingAwareStreamFilter(write, mode = "hide") {
|
|
2265
|
+
if (mode === "show") {
|
|
2266
|
+
return {
|
|
2267
|
+
push(chunk) {
|
|
2268
|
+
write(chunk);
|
|
2269
|
+
},
|
|
2270
|
+
flush() {
|
|
2271
|
+
}
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
let pending = "";
|
|
2275
|
+
let insideThink = false;
|
|
2276
|
+
let markerEmitted = false;
|
|
2277
|
+
const emit = (chunk) => {
|
|
2278
|
+
if (chunk) write(chunk);
|
|
2279
|
+
};
|
|
2280
|
+
const emitMarker = () => {
|
|
2281
|
+
if (mode !== "marker" || markerEmitted) return;
|
|
2282
|
+
emit("\n\u25B8 \u601D\u8003\u5DF2\u6298\u53E0\n");
|
|
2283
|
+
markerEmitted = true;
|
|
2284
|
+
};
|
|
2285
|
+
const consume = (input) => {
|
|
2286
|
+
pending += input;
|
|
2287
|
+
while (pending.length > 0) {
|
|
2288
|
+
if (insideThink) {
|
|
2289
|
+
const closeMatch = pending.match(THINK_CLOSE);
|
|
2290
|
+
if (!closeMatch || closeMatch.index == null) {
|
|
2291
|
+
emitMarker();
|
|
2292
|
+
pending = "";
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
emitMarker();
|
|
2296
|
+
pending = pending.slice(closeMatch.index + closeMatch[0].length);
|
|
2297
|
+
insideThink = false;
|
|
2298
|
+
markerEmitted = false;
|
|
2299
|
+
continue;
|
|
2300
|
+
}
|
|
2301
|
+
const openMatch = pending.match(THINK_OPEN);
|
|
2302
|
+
if (!openMatch || openMatch.index == null) {
|
|
2303
|
+
const nextMarker = pending.indexOf("<");
|
|
2304
|
+
if (nextMarker === -1) {
|
|
2305
|
+
const cleaned = mode === "hide" ? pending.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : pending;
|
|
2306
|
+
emit(cleaned);
|
|
2307
|
+
pending = "";
|
|
2308
|
+
return;
|
|
2309
|
+
}
|
|
2310
|
+
if (nextMarker > 0) {
|
|
2311
|
+
const head = pending.slice(0, nextMarker);
|
|
2312
|
+
const cleaned = mode === "hide" ? head.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : head;
|
|
2313
|
+
emit(cleaned);
|
|
2314
|
+
pending = pending.slice(nextMarker);
|
|
2315
|
+
continue;
|
|
2316
|
+
}
|
|
2317
|
+
if (pending.length < 7) return;
|
|
2318
|
+
emit(pending[0]);
|
|
2319
|
+
pending = pending.slice(1);
|
|
2320
|
+
continue;
|
|
2321
|
+
}
|
|
2322
|
+
if (openMatch.index > 0) {
|
|
2323
|
+
const head = pending.slice(0, openMatch.index);
|
|
2324
|
+
const cleaned = mode === "hide" ? head.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : head;
|
|
2325
|
+
emit(cleaned);
|
|
2326
|
+
pending = pending.slice(openMatch.index);
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
pending = pending.slice(openMatch[0].length);
|
|
2330
|
+
insideThink = true;
|
|
2331
|
+
markerEmitted = false;
|
|
2332
|
+
}
|
|
2333
|
+
};
|
|
2334
|
+
return {
|
|
2335
|
+
push(chunk) {
|
|
2336
|
+
consume(chunk);
|
|
2337
|
+
},
|
|
2338
|
+
flush() {
|
|
2339
|
+
if (insideThink) emitMarker();
|
|
2340
|
+
if (pending) {
|
|
2341
|
+
const cleaned = mode === "hide" ? pending.split("\n").filter((line) => !COLLAPSED_MARKER.test(line)).join("\n") : pending;
|
|
2342
|
+
emit(cleaned);
|
|
2343
|
+
}
|
|
2344
|
+
pending = "";
|
|
2345
|
+
insideThink = false;
|
|
2346
|
+
markerEmitted = false;
|
|
2347
|
+
}
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
// packages/cli/client/formatReadPathTree.ts
|
|
2352
|
+
import { homedir as osHomedir } from "node:os";
|
|
2353
|
+
function clipPathAware(value, max = 72) {
|
|
2354
|
+
const compact = compactWhitespace(value);
|
|
2355
|
+
if (compact.length <= max) return compact;
|
|
2356
|
+
if (compact.includes(" ") || !compact.includes("/") && !compact.includes("\\")) {
|
|
2357
|
+
return clipCompactText(value, max, "\u2026");
|
|
1746
2358
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
2359
|
+
const segments = compact.split(/[/\\]/);
|
|
2360
|
+
const filename = segments[segments.length - 1];
|
|
2361
|
+
if (filename.length >= max) {
|
|
2362
|
+
return clipCompactText(value, max, "\u2026");
|
|
2363
|
+
}
|
|
2364
|
+
const ELISION = "/\u2026/";
|
|
2365
|
+
let prefix = "";
|
|
2366
|
+
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
2367
|
+
const candidate = segments.slice(0, i + 1).join("/");
|
|
2368
|
+
if (candidate.length + ELISION.length + filename.length > max) break;
|
|
2369
|
+
prefix = candidate;
|
|
2370
|
+
}
|
|
2371
|
+
if (prefix) return `${prefix}${ELISION}${filename}`;
|
|
2372
|
+
const filenameOnly = `\u2026/${filename}`;
|
|
2373
|
+
if (filenameOnly.length <= max) return filenameOnly;
|
|
2374
|
+
return clipCompactText(value, max, "\u2026");
|
|
1750
2375
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2376
|
+
function formatHomePath(path, customHomedir) {
|
|
2377
|
+
if (!path) return "";
|
|
2378
|
+
const home = customHomedir || (typeof process !== "undefined" ? process.env?.HOME : void 0) || (typeof osHomedir === "function" ? osHomedir() : "");
|
|
2379
|
+
if (home && path.startsWith(home)) {
|
|
2380
|
+
return `~${path.slice(home.length)}`;
|
|
2381
|
+
}
|
|
2382
|
+
return path.replace(/^(\/Users\/[^\/]+\/|\/home\/[^\/]+\/)/, "~/");
|
|
2383
|
+
}
|
|
2384
|
+
function formatReadItemPath(rawPath, metadata, customHomedir) {
|
|
2385
|
+
const inputPath = rawPath || (typeof metadata?.path === "string" ? metadata.path : void 0) || (typeof metadata?.filePath === "string" ? metadata.filePath : void 0) || "file";
|
|
2386
|
+
let formattedPath = formatHomePath(inputPath, customHomedir);
|
|
2387
|
+
if (!formattedPath) return "file";
|
|
2388
|
+
let rangePart = "";
|
|
2389
|
+
const match = formattedPath.match(/(:[0-9]+(-[0-9]+)?(,[0-9]+(-[0-9]+)?)*)$/);
|
|
2390
|
+
if (match) {
|
|
2391
|
+
rangePart = match[1];
|
|
2392
|
+
formattedPath = formattedPath.slice(0, -rangePart.length);
|
|
2393
|
+
} else if (metadata && typeof metadata.startLine === "number" && typeof metadata.endLine === "number" && typeof metadata.totalLines === "number") {
|
|
2394
|
+
const { startLine, endLine, totalLines, truncated } = metadata;
|
|
2395
|
+
if (truncated || startLine !== 1 || endLine !== totalLines) {
|
|
2396
|
+
rangePart = `:${startLine}-${endLine}`;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
const clippedPath = clipPathAware(formattedPath, 72);
|
|
2400
|
+
return `${clippedPath}${rangePart}`;
|
|
2401
|
+
}
|
|
2402
|
+
function formatReadTreeLines(items, customHomedir) {
|
|
2403
|
+
const count = items.length;
|
|
2404
|
+
const header = `Read (${count})`;
|
|
2405
|
+
const lines = items.map((item, index) => {
|
|
2406
|
+
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
2407
|
+
const pathWithRange = formatReadItemPath(item.path, item.metadata, customHomedir);
|
|
2408
|
+
return { connector, pathWithRange };
|
|
2409
|
+
});
|
|
2410
|
+
return { header, count, lines };
|
|
2411
|
+
}
|
|
2412
|
+
function formatSearchItemQuery(query, path, customHomedir) {
|
|
2413
|
+
let text = (query || "").trim();
|
|
2414
|
+
if (path) {
|
|
2415
|
+
const formattedPath = formatHomePath(path, customHomedir);
|
|
2416
|
+
if (formattedPath) {
|
|
2417
|
+
text = text ? `${text} in ${formattedPath}` : formattedPath;
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
if (!text) return "search";
|
|
2421
|
+
return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
2422
|
+
}
|
|
2423
|
+
function formatSearchTreeLines(items, customHomedir) {
|
|
2424
|
+
const count = items.length;
|
|
2425
|
+
const header = `Search (${count})`;
|
|
2426
|
+
const lines = items.map((item, index) => {
|
|
2427
|
+
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
2428
|
+
const queryText = formatSearchItemQuery(item.query, item.path, customHomedir);
|
|
2429
|
+
return { connector, queryText };
|
|
2430
|
+
});
|
|
2431
|
+
return { header, count, lines };
|
|
2432
|
+
}
|
|
2433
|
+
function formatRunItemCommand(command, exitCode, timedOut) {
|
|
2434
|
+
let text = compactWhitespace(command || "");
|
|
2435
|
+
if (!text) text = "command";
|
|
2436
|
+
text = text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
2437
|
+
if (timedOut) return `${text} (timed out)`;
|
|
2438
|
+
if (typeof exitCode === "number" && exitCode !== 0) return `${text} (exit ${exitCode})`;
|
|
2439
|
+
return text;
|
|
2440
|
+
}
|
|
2441
|
+
function formatRunTreeLines(items) {
|
|
2442
|
+
const count = items.length;
|
|
2443
|
+
const header = `Run (${count})`;
|
|
2444
|
+
const lines = items.map((item, index) => {
|
|
2445
|
+
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
2446
|
+
const commandText = formatRunItemCommand(item.command, item.exitCode, item.timedOut);
|
|
2447
|
+
return { connector, commandText };
|
|
2448
|
+
});
|
|
2449
|
+
return { header, count, lines };
|
|
2450
|
+
}
|
|
2451
|
+
function formatFetchItemUrl(url) {
|
|
2452
|
+
const text = (url || "").trim();
|
|
2453
|
+
if (!text) return "webpage";
|
|
2454
|
+
return text.length > 80 ? `${text.slice(0, 79)}\u2026` : text;
|
|
2455
|
+
}
|
|
2456
|
+
function formatFetchTreeLines(items) {
|
|
2457
|
+
const count = items.length;
|
|
2458
|
+
const header = `Fetch (${count})`;
|
|
2459
|
+
const lines = items.map((item, index) => {
|
|
2460
|
+
const connector = index === items.length - 1 ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
2461
|
+
const urlText = formatFetchItemUrl(item.url);
|
|
2462
|
+
return { connector, urlText };
|
|
2463
|
+
});
|
|
2464
|
+
return { header, count, lines };
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// packages/cli/node_modules/diff/libesm/diff/base.js
|
|
2468
|
+
var Diff = class {
|
|
2469
|
+
diff(oldStr, newStr, options = {}) {
|
|
2470
|
+
let callback;
|
|
2471
|
+
if (typeof options === "function") {
|
|
2472
|
+
callback = options;
|
|
2473
|
+
options = {};
|
|
2474
|
+
} else if ("callback" in options) {
|
|
2475
|
+
callback = options.callback;
|
|
2476
|
+
}
|
|
2477
|
+
const oldString = this.castInput(oldStr, options);
|
|
2478
|
+
const newString = this.castInput(newStr, options);
|
|
2479
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
2480
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
2481
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
2482
|
+
}
|
|
2483
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
2484
|
+
var _a;
|
|
2485
|
+
const done = (value) => {
|
|
2486
|
+
value = this.postProcess(value, options);
|
|
2487
|
+
if (callback) {
|
|
2488
|
+
setTimeout(function() {
|
|
2489
|
+
callback(value);
|
|
2490
|
+
}, 0);
|
|
2491
|
+
return void 0;
|
|
2492
|
+
} else {
|
|
2493
|
+
return value;
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
2497
|
+
let editLength = 1;
|
|
2498
|
+
let maxEditLength = newLen + oldLen;
|
|
2499
|
+
if (options.maxEditLength != null) {
|
|
2500
|
+
maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
2501
|
+
}
|
|
2502
|
+
const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
|
|
2503
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
2504
|
+
const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
|
|
2505
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
2506
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
2507
|
+
return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
2508
|
+
}
|
|
2509
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
2510
|
+
const execEditLength = () => {
|
|
2511
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
2512
|
+
let basePath;
|
|
2513
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
2514
|
+
if (removePath) {
|
|
2515
|
+
bestPath[diagonalPath - 1] = void 0;
|
|
2516
|
+
}
|
|
2517
|
+
let canAdd = false;
|
|
2518
|
+
if (addPath) {
|
|
2519
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
2520
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
2521
|
+
}
|
|
2522
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
2523
|
+
if (!canAdd && !canRemove) {
|
|
2524
|
+
bestPath[diagonalPath] = void 0;
|
|
2525
|
+
continue;
|
|
2526
|
+
}
|
|
2527
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
|
|
2528
|
+
basePath = this.addToPath(addPath, true, false, 0, options);
|
|
2529
|
+
} else {
|
|
2530
|
+
basePath = this.addToPath(removePath, false, true, 1, options);
|
|
2531
|
+
}
|
|
2532
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
2533
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
2534
|
+
return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
2535
|
+
} else {
|
|
2536
|
+
bestPath[diagonalPath] = basePath;
|
|
2537
|
+
if (basePath.oldPos + 1 >= oldLen) {
|
|
2538
|
+
maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
2539
|
+
}
|
|
2540
|
+
if (newPos + 1 >= newLen) {
|
|
2541
|
+
minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
editLength++;
|
|
2546
|
+
};
|
|
2547
|
+
if (callback) {
|
|
2548
|
+
(function exec() {
|
|
2549
|
+
setTimeout(function() {
|
|
2550
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
2551
|
+
return callback(void 0);
|
|
2552
|
+
}
|
|
2553
|
+
if (!execEditLength()) {
|
|
2554
|
+
exec();
|
|
2555
|
+
}
|
|
2556
|
+
}, 0);
|
|
2557
|
+
})();
|
|
2558
|
+
} else {
|
|
2559
|
+
while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
2560
|
+
const ret = execEditLength();
|
|
2561
|
+
if (ret) {
|
|
2562
|
+
return ret;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
addToPath(path, added, removed, oldPosInc, options) {
|
|
2568
|
+
const last = path.lastComponent;
|
|
2569
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
2570
|
+
return {
|
|
2571
|
+
oldPos: path.oldPos + oldPosInc,
|
|
2572
|
+
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
2573
|
+
};
|
|
2574
|
+
} else {
|
|
2575
|
+
return {
|
|
2576
|
+
oldPos: path.oldPos + oldPosInc,
|
|
2577
|
+
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
2582
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
2583
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
2584
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
2585
|
+
newPos++;
|
|
2586
|
+
oldPos++;
|
|
2587
|
+
commonCount++;
|
|
2588
|
+
if (options.oneChangePerToken) {
|
|
2589
|
+
basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
if (commonCount && !options.oneChangePerToken) {
|
|
2593
|
+
basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
2594
|
+
}
|
|
2595
|
+
basePath.oldPos = oldPos;
|
|
2596
|
+
return newPos;
|
|
2597
|
+
}
|
|
2598
|
+
equals(left, right, options) {
|
|
2599
|
+
if (options.comparator) {
|
|
2600
|
+
return options.comparator(left, right);
|
|
2601
|
+
} else {
|
|
2602
|
+
return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
removeEmpty(array) {
|
|
2606
|
+
const ret = [];
|
|
2607
|
+
for (let i = 0; i < array.length; i++) {
|
|
2608
|
+
if (array[i]) {
|
|
2609
|
+
ret.push(array[i]);
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
return ret;
|
|
2613
|
+
}
|
|
2614
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2615
|
+
castInput(value, options) {
|
|
2616
|
+
return value;
|
|
2617
|
+
}
|
|
2618
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2619
|
+
tokenize(value, options) {
|
|
2620
|
+
return Array.from(value);
|
|
2621
|
+
}
|
|
2622
|
+
join(chars) {
|
|
2623
|
+
return chars.join("");
|
|
2624
|
+
}
|
|
2625
|
+
postProcess(changeObjects, options) {
|
|
2626
|
+
return changeObjects;
|
|
2627
|
+
}
|
|
2628
|
+
get useLongestToken() {
|
|
2629
|
+
return false;
|
|
2630
|
+
}
|
|
2631
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
2632
|
+
const components = [];
|
|
2633
|
+
let nextComponent;
|
|
2634
|
+
while (lastComponent) {
|
|
2635
|
+
components.push(lastComponent);
|
|
2636
|
+
nextComponent = lastComponent.previousComponent;
|
|
2637
|
+
delete lastComponent.previousComponent;
|
|
2638
|
+
lastComponent = nextComponent;
|
|
2639
|
+
}
|
|
2640
|
+
components.reverse();
|
|
2641
|
+
const componentLen = components.length;
|
|
2642
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
2643
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
2644
|
+
const component = components[componentPos];
|
|
2645
|
+
if (!component.removed) {
|
|
2646
|
+
if (!component.added && this.useLongestToken) {
|
|
2647
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
2648
|
+
value = value.map(function(value2, i) {
|
|
2649
|
+
const oldValue = oldTokens[oldPos + i];
|
|
2650
|
+
return oldValue.length > value2.length ? oldValue : value2;
|
|
2651
|
+
});
|
|
2652
|
+
component.value = this.join(value);
|
|
2653
|
+
} else {
|
|
2654
|
+
component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
2655
|
+
}
|
|
2656
|
+
newPos += component.count;
|
|
2657
|
+
if (!component.added) {
|
|
2658
|
+
oldPos += component.count;
|
|
2659
|
+
}
|
|
2660
|
+
} else {
|
|
2661
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
2662
|
+
oldPos += component.count;
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return components;
|
|
2666
|
+
}
|
|
1792
2667
|
};
|
|
1793
|
-
|
|
1794
|
-
|
|
2668
|
+
|
|
2669
|
+
// packages/cli/node_modules/diff/libesm/diff/line.js
|
|
2670
|
+
var LineDiff = class extends Diff {
|
|
2671
|
+
constructor() {
|
|
2672
|
+
super(...arguments);
|
|
2673
|
+
this.tokenize = tokenize;
|
|
2674
|
+
}
|
|
2675
|
+
equals(left, right, options) {
|
|
2676
|
+
if (options.ignoreWhitespace) {
|
|
2677
|
+
if (!options.newlineIsToken || !left.includes("\n")) {
|
|
2678
|
+
left = left.trim();
|
|
2679
|
+
}
|
|
2680
|
+
if (!options.newlineIsToken || !right.includes("\n")) {
|
|
2681
|
+
right = right.trim();
|
|
2682
|
+
}
|
|
2683
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
2684
|
+
if (left.endsWith("\n")) {
|
|
2685
|
+
left = left.slice(0, -1);
|
|
2686
|
+
}
|
|
2687
|
+
if (right.endsWith("\n")) {
|
|
2688
|
+
right = right.slice(0, -1);
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
return super.equals(left, right, options);
|
|
2692
|
+
}
|
|
2693
|
+
};
|
|
2694
|
+
var lineDiff = new LineDiff();
|
|
2695
|
+
function diffLines(oldStr, newStr, options) {
|
|
2696
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
2697
|
+
}
|
|
2698
|
+
function tokenize(value, options) {
|
|
2699
|
+
if (options.stripTrailingCr) {
|
|
2700
|
+
value = value.replace(/\r\n/g, "\n");
|
|
2701
|
+
}
|
|
2702
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
2703
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) {
|
|
2704
|
+
linesAndNewlines.pop();
|
|
2705
|
+
}
|
|
2706
|
+
for (let i = 0; i < linesAndNewlines.length; i++) {
|
|
2707
|
+
const line = linesAndNewlines[i];
|
|
2708
|
+
if (i % 2 && !options.newlineIsToken) {
|
|
2709
|
+
retLines[retLines.length - 1] += line;
|
|
2710
|
+
} else {
|
|
2711
|
+
retLines.push(line);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
return retLines;
|
|
1795
2715
|
}
|
|
1796
2716
|
|
|
1797
2717
|
// packages/cli/client/toolOutput.ts
|
|
@@ -1864,25 +2784,65 @@ function readReadFileRange(metadata) {
|
|
|
1864
2784
|
if (!truncated && startLine === 1 && endLine === totalLines) return void 0;
|
|
1865
2785
|
return `${startLine}-${endLine}/${totalLines}`;
|
|
1866
2786
|
}
|
|
1867
|
-
var EDIT_SNIPPET_MAX_LINES =
|
|
2787
|
+
var EDIT_SNIPPET_MAX_LINES = 10;
|
|
1868
2788
|
var EDIT_SNIPPET_MAX_WIDTH = 96;
|
|
1869
2789
|
function formatEditFileSnippet(metadata) {
|
|
1870
2790
|
const oldSnippet = typeof metadata.oldSnippet === "string" ? metadata.oldSnippet : void 0;
|
|
1871
2791
|
const newSnippet = typeof metadata.newSnippet === "string" ? metadata.newSnippet : void 0;
|
|
1872
2792
|
if (!oldSnippet && !newSnippet) return void 0;
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
2793
|
+
if (oldSnippet && !newSnippet) {
|
|
2794
|
+
return snippetLinesWithKind(oldSnippet, "removed");
|
|
2795
|
+
}
|
|
2796
|
+
if (newSnippet && !oldSnippet) {
|
|
2797
|
+
return snippetLinesWithKind(newSnippet, "added");
|
|
1876
2798
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
2799
|
+
const parts = diffLines(oldSnippet, newSnippet);
|
|
2800
|
+
const all = [];
|
|
2801
|
+
for (const part of parts) {
|
|
2802
|
+
const kind = part.added ? "added" : part.removed ? "removed" : "context";
|
|
2803
|
+
const raw = part.value.split("\n");
|
|
2804
|
+
if (raw.length > 0 && raw[raw.length - 1] === "") raw.pop();
|
|
2805
|
+
for (const line of raw) all.push(buildEditLine(kind, line));
|
|
1879
2806
|
}
|
|
1880
|
-
|
|
2807
|
+
const changeCount = all.filter((l) => l.kind !== "context").length;
|
|
2808
|
+
if (changeCount === 0) return void 0;
|
|
2809
|
+
return windowAndTruncate(all, EDIT_SNIPPET_MAX_LINES);
|
|
1881
2810
|
}
|
|
1882
|
-
function
|
|
2811
|
+
function prefixFor(kind) {
|
|
2812
|
+
return kind === "added" ? "+ " : kind === "removed" ? "- " : " ";
|
|
2813
|
+
}
|
|
2814
|
+
function buildEditLine(kind, body) {
|
|
2815
|
+
return { kind, text: prefixFor(kind) + truncateByDisplayWidth(body, EDIT_SNIPPET_MAX_WIDTH) };
|
|
2816
|
+
}
|
|
2817
|
+
function snippetLinesWithKind(snippet, kind) {
|
|
1883
2818
|
const lines = snippet.split(/\r?\n/).filter((line) => line.length > 0);
|
|
1884
|
-
|
|
1885
|
-
|
|
2819
|
+
return lines.slice(0, EDIT_SNIPPET_MAX_LINES).map((line) => buildEditLine(kind, line));
|
|
2820
|
+
}
|
|
2821
|
+
function truncateByDisplayWidth(line, maxWidth) {
|
|
2822
|
+
if (displayWidth(line) <= maxWidth) return line;
|
|
2823
|
+
let width = 0;
|
|
2824
|
+
let kept = "";
|
|
2825
|
+
for (const char of line) {
|
|
2826
|
+
const w = displayWidth(char);
|
|
2827
|
+
if (width + w + 1 > maxWidth) break;
|
|
2828
|
+
kept += char;
|
|
2829
|
+
width += w;
|
|
2830
|
+
}
|
|
2831
|
+
return `${kept}\u2026`;
|
|
2832
|
+
}
|
|
2833
|
+
function windowAndTruncate(lines, maxLines) {
|
|
2834
|
+
if (lines.length <= maxLines) return lines;
|
|
2835
|
+
const firstChange = lines.findIndex((l) => l.kind !== "context");
|
|
2836
|
+
if (firstChange === -1) return lines.slice(0, maxLines);
|
|
2837
|
+
const half = Math.floor(maxLines / 2);
|
|
2838
|
+
let start = Math.max(0, firstChange - half);
|
|
2839
|
+
if (start + maxLines > lines.length) start = Math.max(0, lines.length - maxLines);
|
|
2840
|
+
const kept = lines.slice(start, start + maxLines);
|
|
2841
|
+
const omitted = lines.length - kept.length;
|
|
2842
|
+
if (omitted > 0) {
|
|
2843
|
+
kept.push({ kind: "context", text: ` \u2026 +${omitted} more lines` });
|
|
2844
|
+
}
|
|
2845
|
+
return kept;
|
|
1886
2846
|
}
|
|
1887
2847
|
function isFailedToolResult(event) {
|
|
1888
2848
|
const exitCode = event.metadata?.exitCode;
|
|
@@ -1904,18 +2864,66 @@ function parseUiAskChoiceForCli(event) {
|
|
|
1904
2864
|
label: String(c.label ?? "").trim(),
|
|
1905
2865
|
userMessage: typeof c.userMessage === "string" ? c.userMessage : void 0
|
|
1906
2866
|
})).filter((c) => c.label.length > 0);
|
|
1907
|
-
|
|
1908
|
-
|
|
2867
|
+
const selected = parsed.selected && typeof parsed.selected === "object" ? {
|
|
2868
|
+
label: String(parsed.selected.label ?? "").trim(),
|
|
2869
|
+
userMessage: String(parsed.selected.userMessage ?? "").trim()
|
|
2870
|
+
} : void 0;
|
|
2871
|
+
const answers = Array.isArray(parsed.answers) ? parsed.answers : void 0;
|
|
2872
|
+
const cancelled = Boolean(parsed.cancelled);
|
|
2873
|
+
const resolved = Boolean(
|
|
2874
|
+
event.metadata?.resolved || selected || cancelled || answers && answers.length > 0
|
|
2875
|
+
);
|
|
2876
|
+
if (!resolved && (!question || choices.length === 0)) return null;
|
|
2877
|
+
if (!question && !selected && !cancelled) return null;
|
|
2878
|
+
return {
|
|
2879
|
+
question,
|
|
2880
|
+
choices,
|
|
2881
|
+
...selected ? { selected } : {},
|
|
2882
|
+
...answers ? { answers } : {},
|
|
2883
|
+
...cancelled ? { cancelled: true } : {},
|
|
2884
|
+
resolved
|
|
2885
|
+
};
|
|
1909
2886
|
}
|
|
1910
2887
|
function formatUiAskChoiceBlock(event, colorEnabled) {
|
|
1911
2888
|
const parsed = parseUiAskChoiceForCli(event);
|
|
1912
2889
|
if (!parsed) return null;
|
|
1913
2890
|
const lines = [];
|
|
1914
2891
|
lines.push("");
|
|
2892
|
+
const questionText = parsed.question || "";
|
|
1915
2893
|
if (colorEnabled) {
|
|
1916
|
-
lines.push(`${themeText("\u2753 ", "info", true)}${styleCliText(
|
|
2894
|
+
lines.push(`${themeText("\u2753 ", "info", true)}${styleCliText(questionText, "cyan", true)}`);
|
|
1917
2895
|
} else {
|
|
1918
|
-
lines.push(`\u2753 ${
|
|
2896
|
+
lines.push(`\u2753 ${questionText}`);
|
|
2897
|
+
}
|
|
2898
|
+
if (parsed.resolved) {
|
|
2899
|
+
if (parsed.cancelled) {
|
|
2900
|
+
const cancelled = t("askChoiceHistoryCancelled");
|
|
2901
|
+
lines.push(
|
|
2902
|
+
colorEnabled ? ` ${themeText("\xB7", "chrome", true)} ${themeText(cancelled, "muted", true)}` : ` \xB7 ${cancelled}`
|
|
2903
|
+
);
|
|
2904
|
+
return `${lines.join("\n")}
|
|
2905
|
+
`;
|
|
2906
|
+
}
|
|
2907
|
+
const selectedLabel = parsed.selected?.label || parsed.selected?.userMessage || (parsed.answers ? parsed.answers.map((a) => a.userMessage).filter(Boolean).join(", ") : "");
|
|
2908
|
+
const marker = t("askChoiceHistorySelected");
|
|
2909
|
+
const displayLabel = selectedLabel || "\u2014";
|
|
2910
|
+
if (colorEnabled) {
|
|
2911
|
+
lines.push(
|
|
2912
|
+
` ${themeText("\u2713", "success", true)} ${themeText(marker, "muted", true)} ${displayLabel}`
|
|
2913
|
+
);
|
|
2914
|
+
} else {
|
|
2915
|
+
lines.push(` \u2713 ${marker} ${displayLabel}`);
|
|
2916
|
+
}
|
|
2917
|
+
if (parsed.answers && parsed.answers.length > 1) {
|
|
2918
|
+
for (const answer of parsed.answers) {
|
|
2919
|
+
if (!answer.userMessage) continue;
|
|
2920
|
+
lines.push(
|
|
2921
|
+
colorEnabled ? ` ${themeText("\xB7", "chrome", true)} ${answer.userMessage}` : ` \xB7 ${answer.userMessage}`
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return `${lines.join("\n")}
|
|
2926
|
+
`;
|
|
1919
2927
|
}
|
|
1920
2928
|
parsed.choices.forEach((choice, i) => {
|
|
1921
2929
|
const num = String(i + 1);
|
|
@@ -1928,7 +2936,7 @@ function formatUiAskChoiceBlock(event, colorEnabled) {
|
|
|
1928
2936
|
lines.push(` ${num}. ${label}`);
|
|
1929
2937
|
}
|
|
1930
2938
|
});
|
|
1931
|
-
const hint = "
|
|
2939
|
+
const hint = t("askChoiceHistoryHint");
|
|
1932
2940
|
if (colorEnabled) {
|
|
1933
2941
|
lines.push(` ${dimCliText(hint, true)}`);
|
|
1934
2942
|
} else {
|
|
@@ -2158,42 +3166,23 @@ ${detail}
|
|
|
2158
3166
|
} else {
|
|
2159
3167
|
const chromePointer = themeText("\u25B8", "chrome", true);
|
|
2160
3168
|
const mutedLabel = themeText(rawLabel, "muted", true);
|
|
2161
|
-
const argsPart = rawArgs ? ` ${dimCliText(rawArgs, true)}` : "";
|
|
2162
|
-
const statusToken = failed ? themeText("\u2717", "danger", true) : isNeedsActionToolResult(event) ? themeText("!", "warning", true) : themeText("\u2713", "success", true);
|
|
2163
|
-
const suffixPart = hint.inline ? ` ${dimCliText(hint.inline, true)}` : "";
|
|
2164
|
-
mainLine = `${chromePointer} ${mutedLabel}${argsPart} ${statusToken}${suffixPart}
|
|
2165
|
-
`;
|
|
2166
|
-
}
|
|
2167
|
-
if (!hint.detail) return mainLine;
|
|
2168
|
-
const detailLines = hint.detail.split("\n").map((line) => formatEditDetailLine(line, colorEnabled)).join("");
|
|
2169
|
-
return `${mainLine}${detailLines}`;
|
|
2170
|
-
}
|
|
2171
|
-
function formatEditDetailLine(line, colorEnabled) {
|
|
2172
|
-
const marker = line.slice(0, 2);
|
|
2173
|
-
const rest = line.slice(2);
|
|
2174
|
-
if (!colorEnabled) return ` ${line}
|
|
2175
|
-
`;
|
|
2176
|
-
const diff = diffLineSequences();
|
|
2177
|
-
if (!diff) {
|
|
2178
|
-
const color = marker === "- " ? "red" : marker === "+ " ? "green" : void 0;
|
|
2179
|
-
if (color) {
|
|
2180
|
-
return ` ${styleCliText(marker, color, true)}${dimCliText(rest, true)}
|
|
2181
|
-
`;
|
|
2182
|
-
}
|
|
2183
|
-
return ` ${dimCliText(line, true)}
|
|
2184
|
-
`;
|
|
2185
|
-
}
|
|
2186
|
-
const RESET2 = "\x1B[0m";
|
|
2187
|
-
if (marker === "- ") {
|
|
2188
|
-
return ` ${diff.removed.bg}${diff.removed.fg}- ${rest}${RESET2}
|
|
3169
|
+
const argsPart = rawArgs ? ` ${dimCliText(rawArgs, true)}` : "";
|
|
3170
|
+
const statusToken = failed ? themeText("\u2717", "danger", true) : isNeedsActionToolResult(event) ? themeText("!", "warning", true) : themeText("\u2713", "success", true);
|
|
3171
|
+
const suffixPart = hint.inline ? ` ${dimCliText(hint.inline, true)}` : "";
|
|
3172
|
+
mainLine = `${chromePointer} ${mutedLabel}${argsPart} ${statusToken}${suffixPart}
|
|
2189
3173
|
`;
|
|
2190
3174
|
}
|
|
2191
|
-
if (
|
|
2192
|
-
|
|
2193
|
-
|
|
3175
|
+
if (!hint.detail?.length) return mainLine;
|
|
3176
|
+
return `${mainLine}${formatEditDetailBlock(hint.detail, colorEnabled)}`;
|
|
3177
|
+
}
|
|
3178
|
+
function formatEditDetailBlock(lines, colorEnabled) {
|
|
3179
|
+
if (!colorEnabled) {
|
|
3180
|
+
return lines.map((line) => ` ${line.text}
|
|
3181
|
+
`).join("");
|
|
2194
3182
|
}
|
|
2195
|
-
|
|
2196
|
-
|
|
3183
|
+
const padTo = Math.max(...lines.map((line) => displayWidth(line.text))) + 1;
|
|
3184
|
+
return lines.map((line) => ` ${renderDiffLine({ kind: line.kind, text: line.text, padTo, colorEnabled: true })}
|
|
3185
|
+
`).join("");
|
|
2197
3186
|
}
|
|
2198
3187
|
function createToolEventFormatter(mode, colorEnabled = resolveCliColorEnabled()) {
|
|
2199
3188
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -2823,10 +3812,165 @@ function isKnownServerPlatformAgent(options) {
|
|
|
2823
3812
|
);
|
|
2824
3813
|
}
|
|
2825
3814
|
|
|
3815
|
+
// packages/core/collapsedPaste.ts
|
|
3816
|
+
var COLLAPSE_PASTE_MIN_LINES = 8;
|
|
3817
|
+
var COLLAPSE_PASTE_MIN_CHARS = 400;
|
|
3818
|
+
var COLLAPSED_PASTE_PLACEHOLDER_RE = /\[paste #(\d+) · (\d+) lines\]/g;
|
|
3819
|
+
var COLLAPSED_PASTE_MODEL_REFERENCE_RE = /\[paste #(\d+)(?: scope:([a-zA-Z0-9_-]+))? · [^\]]+; full content available via readPastedText\(pasteId=(\d+)\)\]/g;
|
|
3820
|
+
function countTextLines(text) {
|
|
3821
|
+
if (text.length === 0) return 0;
|
|
3822
|
+
let lines = 1;
|
|
3823
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
3824
|
+
if (text.charCodeAt(i) === 10) lines += 1;
|
|
3825
|
+
}
|
|
3826
|
+
return lines;
|
|
3827
|
+
}
|
|
3828
|
+
function shouldCollapsePaste(text, threshold = {}) {
|
|
3829
|
+
const minLines = threshold.minLines ?? COLLAPSE_PASTE_MIN_LINES;
|
|
3830
|
+
const minChars = threshold.minChars ?? COLLAPSE_PASTE_MIN_CHARS;
|
|
3831
|
+
if (text.length === 0) return false;
|
|
3832
|
+
if (text.length >= minChars) return true;
|
|
3833
|
+
return countTextLines(text) >= minLines;
|
|
3834
|
+
}
|
|
3835
|
+
function formatPasteByteSize(bytes) {
|
|
3836
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "0 B";
|
|
3837
|
+
if (bytes < 1024) return `${Math.round(bytes)} B`;
|
|
3838
|
+
if (bytes < 1024 * 1024) {
|
|
3839
|
+
const kb = bytes / 1024;
|
|
3840
|
+
return `${kb >= 10 ? kb.toFixed(0) : kb.toFixed(1)} KB`;
|
|
3841
|
+
}
|
|
3842
|
+
const mb = bytes / (1024 * 1024);
|
|
3843
|
+
return `${mb >= 10 ? mb.toFixed(0) : mb.toFixed(1)} MB`;
|
|
3844
|
+
}
|
|
3845
|
+
function estimatePasteBytes(text) {
|
|
3846
|
+
let bytes = 0;
|
|
3847
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
3848
|
+
const code = text.charCodeAt(i);
|
|
3849
|
+
if (code <= 127) bytes += 1;
|
|
3850
|
+
else if (code <= 2047) bytes += 2;
|
|
3851
|
+
else if (code >= 55296 && code <= 56319) {
|
|
3852
|
+
bytes += 4;
|
|
3853
|
+
i += 1;
|
|
3854
|
+
} else bytes += 3;
|
|
3855
|
+
}
|
|
3856
|
+
return bytes;
|
|
3857
|
+
}
|
|
3858
|
+
function formatCollapsedPastePlaceholder(id, text) {
|
|
3859
|
+
const lines = countTextLines(text);
|
|
3860
|
+
return `[paste #${id} \xB7 ${lines} lines]`;
|
|
3861
|
+
}
|
|
3862
|
+
function generatePasteScope() {
|
|
3863
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
3864
|
+
return crypto.randomUUID().slice(0, 8);
|
|
3865
|
+
}
|
|
3866
|
+
return Math.random().toString(36).slice(2, 10);
|
|
3867
|
+
}
|
|
3868
|
+
function formatCollapsedPasteModelReference(id, text, scope) {
|
|
3869
|
+
const lines = countTextLines(text);
|
|
3870
|
+
const size = formatPasteByteSize(estimatePasteBytes(text));
|
|
3871
|
+
const scopeAttr = scope ? ` scope:${scope}` : "";
|
|
3872
|
+
return `[paste #${id}${scopeAttr} \xB7 ${lines} lines \xB7 ${size}; full content available via readPastedText(pasteId=${id})]`;
|
|
3873
|
+
}
|
|
3874
|
+
function createCollapsedPasteStore(scope) {
|
|
3875
|
+
return { scope: scope ?? generatePasteScope(), nextId: 1, items: /* @__PURE__ */ new Map() };
|
|
3876
|
+
}
|
|
3877
|
+
function allocateCollapsedPaste(store, text) {
|
|
3878
|
+
const id = store.nextId;
|
|
3879
|
+
store.nextId += 1;
|
|
3880
|
+
store.items.set(id, text);
|
|
3881
|
+
return { id, placeholder: formatCollapsedPastePlaceholder(id, text) };
|
|
3882
|
+
}
|
|
3883
|
+
function releaseCollapsedPaste(store, id) {
|
|
3884
|
+
store.items.delete(id);
|
|
3885
|
+
}
|
|
3886
|
+
function clearCollapsedPasteStore(store) {
|
|
3887
|
+
store.items.clear();
|
|
3888
|
+
store.nextId = 1;
|
|
3889
|
+
store.scope = generatePasteScope();
|
|
3890
|
+
}
|
|
3891
|
+
function expandCollapsedPastes(buffer, store) {
|
|
3892
|
+
COLLAPSED_PASTE_MODEL_REFERENCE_RE.lastIndex = 0;
|
|
3893
|
+
const expandedReferences = buffer.replace(
|
|
3894
|
+
COLLAPSED_PASTE_MODEL_REFERENCE_RE,
|
|
3895
|
+
(match, _displayIdRaw, scopeRaw, idRaw) => {
|
|
3896
|
+
if (scopeRaw && scopeRaw === store.scope) {
|
|
3897
|
+
const full = store.items.get(Number(idRaw));
|
|
3898
|
+
return full === void 0 ? match : full;
|
|
3899
|
+
}
|
|
3900
|
+
return match;
|
|
3901
|
+
}
|
|
3902
|
+
);
|
|
3903
|
+
if (store.items.size === 0) return expandedReferences;
|
|
3904
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
3905
|
+
return expandedReferences.replace(COLLAPSED_PASTE_PLACEHOLDER_RE, (match, idRaw) => {
|
|
3906
|
+
const id = Number(idRaw);
|
|
3907
|
+
const full = store.items.get(id);
|
|
3908
|
+
return full === void 0 ? match : full;
|
|
3909
|
+
});
|
|
3910
|
+
}
|
|
3911
|
+
function replaceCollapsedPastesWithReferences(buffer, store) {
|
|
3912
|
+
if (store.items.size === 0) return buffer;
|
|
3913
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
3914
|
+
return buffer.replace(COLLAPSED_PASTE_PLACEHOLDER_RE, (match, idRaw) => {
|
|
3915
|
+
const id = Number(idRaw);
|
|
3916
|
+
const full = store.items.get(id);
|
|
3917
|
+
return full === void 0 ? match : formatCollapsedPasteModelReference(id, full, store.scope);
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
function releaseCollapsedPasteReferences(buffer, store) {
|
|
3921
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3922
|
+
COLLAPSED_PASTE_MODEL_REFERENCE_RE.lastIndex = 0;
|
|
3923
|
+
let modelMatch;
|
|
3924
|
+
while ((modelMatch = COLLAPSED_PASTE_MODEL_REFERENCE_RE.exec(buffer)) !== null) {
|
|
3925
|
+
const id = Number(modelMatch[3]);
|
|
3926
|
+
const scope = modelMatch[2];
|
|
3927
|
+
if (scope && scope === store.scope) {
|
|
3928
|
+
ids.add(id);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
3932
|
+
let placeholderMatch;
|
|
3933
|
+
while ((placeholderMatch = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(buffer)) !== null) {
|
|
3934
|
+
ids.add(Number(placeholderMatch[1]));
|
|
3935
|
+
}
|
|
3936
|
+
for (const id of ids) releaseCollapsedPaste(store, id);
|
|
3937
|
+
}
|
|
3938
|
+
function expandRangeToCollapsedPasteChips(buffer, start, end) {
|
|
3939
|
+
let s = Math.max(0, Math.min(start, end));
|
|
3940
|
+
let e = Math.max(s, Math.max(start, end));
|
|
3941
|
+
if (s === e) return { start: s, end: e };
|
|
3942
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
3943
|
+
let match;
|
|
3944
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(buffer)) !== null) {
|
|
3945
|
+
const chipStart = match.index;
|
|
3946
|
+
const chipEnd = chipStart + match[0].length;
|
|
3947
|
+
if (chipStart < e && chipEnd > s) {
|
|
3948
|
+
if (chipStart < s) s = chipStart;
|
|
3949
|
+
if (chipEnd > e) e = chipEnd;
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
return { start: s, end: e };
|
|
3953
|
+
}
|
|
3954
|
+
function findCollapsedPasteSpanAt(buffer, pos, opts = {}) {
|
|
3955
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE.lastIndex = 0;
|
|
3956
|
+
let match;
|
|
3957
|
+
while ((match = COLLAPSED_PASTE_PLACEHOLDER_RE.exec(buffer)) !== null) {
|
|
3958
|
+
const start = match.index;
|
|
3959
|
+
const end = start + match[0].length;
|
|
3960
|
+
const inside = pos > start && pos < end;
|
|
3961
|
+
const atEnd = opts.preferLeft && pos === end;
|
|
3962
|
+
const atStart = !opts.preferLeft && pos === start;
|
|
3963
|
+
if (inside || atEnd || atStart) {
|
|
3964
|
+
return { id: Number(match[1]), start, end };
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
return null;
|
|
3968
|
+
}
|
|
3969
|
+
|
|
2826
3970
|
// packages/cli/client/agentRun.ts
|
|
2827
3971
|
import { ulid } from "ulid";
|
|
2828
3972
|
async function loadRunLocalAgentTurn() {
|
|
2829
|
-
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-
|
|
3973
|
+
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-V5UV7S4R.js");
|
|
2830
3974
|
return runLocalAgentTurn;
|
|
2831
3975
|
}
|
|
2832
3976
|
async function resolveCurrentMachineId(options) {
|
|
@@ -2839,6 +3983,12 @@ function resolveRequestedRuntimeMode(options) {
|
|
|
2839
3983
|
return envMode;
|
|
2840
3984
|
return "auto";
|
|
2841
3985
|
}
|
|
3986
|
+
function canResolveCollapsedPasteReference(store, content) {
|
|
3987
|
+
const expand = (text) => expandCollapsedPastes(text, store) !== text;
|
|
3988
|
+
if (typeof content === "string") return expand(content);
|
|
3989
|
+
if (!Array.isArray(content)) return false;
|
|
3990
|
+
return content.some((part) => part.type === "text" && expand(part.text));
|
|
3991
|
+
}
|
|
2842
3992
|
function buildDefaultLocalRuntimeAdapter(options) {
|
|
2843
3993
|
return createCliLocalRuntimeAdapter({
|
|
2844
3994
|
env: options.env,
|
|
@@ -2846,7 +3996,8 @@ function buildDefaultLocalRuntimeAdapter(options) {
|
|
|
2846
3996
|
cwd: options.localRuntimeCwd,
|
|
2847
3997
|
output: options.output,
|
|
2848
3998
|
...options.confirmDestructiveAction ? { confirmDestructiveAction: options.confirmDestructiveAction } : {},
|
|
2849
|
-
...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {}
|
|
3999
|
+
...options.requestUserChoice ? { requestUserChoice: options.requestUserChoice } : {},
|
|
4000
|
+
...options.pastedTextStore?.items.size ? { pastedTextStore: options.pastedTextStore } : {}
|
|
2850
4001
|
});
|
|
2851
4002
|
}
|
|
2852
4003
|
function resolveLocalRuntimeAdapter(options) {
|
|
@@ -2985,6 +4136,35 @@ function isMissingLocalAgentConfigError(error, agentRef) {
|
|
|
2985
4136
|
error && typeof error === "object" && "code" in error && error.code === LOCAL_AGENT_CONFIG_MISSING_CODE && error.agentRef === agentRef
|
|
2986
4137
|
);
|
|
2987
4138
|
}
|
|
4139
|
+
var PLATFORM_PROVIDER_FAILED_RE = /platform provider failed:\s*HTTP\s+(\d+)\b/i;
|
|
4140
|
+
function classifyLocalRunError(message) {
|
|
4141
|
+
const m = message.match(PLATFORM_PROVIDER_FAILED_RE);
|
|
4142
|
+
if (!m) return { kind: "generic" };
|
|
4143
|
+
const status = Number(m[1]);
|
|
4144
|
+
if (status >= 500 && status <= 599) {
|
|
4145
|
+
return { kind: "platform-proxy-transient", status };
|
|
4146
|
+
}
|
|
4147
|
+
return { kind: "platform-proxy-upstream", status };
|
|
4148
|
+
}
|
|
4149
|
+
function describeLocalRunFailure(message) {
|
|
4150
|
+
if (/UPSTREAM_402|Insufficient Balance|余额不足|insufficient\s+balance/i.test(
|
|
4151
|
+
message
|
|
4152
|
+
)) {
|
|
4153
|
+
return `[nolo] auto runtime: local run unavailable (${message}). Not falling back to server. Top up your balance, then send again (or say "\u7EE7\u7EED") \u2014 if a dialog was kept, context is preserved.
|
|
4154
|
+
`;
|
|
4155
|
+
}
|
|
4156
|
+
const cls = classifyLocalRunError(message);
|
|
4157
|
+
if (cls.kind === "platform-proxy-transient") {
|
|
4158
|
+
return `[nolo] auto runtime: local run unavailable (server chat proxy returned HTTP ${cls.status}; this is an upstream/gateway issue, not your local credential or config).${message ? ` Detail: ${message}` : ""} Not falling back to server. Retry shortly, or use --server to run on the server explicitly.
|
|
4159
|
+
`;
|
|
4160
|
+
}
|
|
4161
|
+
if (cls.kind === "platform-proxy-upstream") {
|
|
4162
|
+
return `[nolo] auto runtime: local run unavailable (server chat proxy returned HTTP ${cls.status}).${message ? ` Detail: ${message}` : ""} Not falling back to server. Check the agent's provider/api-key settings on nolo.chat, or use --server to run on the server explicitly.
|
|
4163
|
+
`;
|
|
4164
|
+
}
|
|
4165
|
+
return `[nolo] auto runtime: local run unavailable (${message}). Not falling back to server. Fix the local credential/config and retry, or use --server to run on the server explicitly.
|
|
4166
|
+
`;
|
|
4167
|
+
}
|
|
2988
4168
|
function shouldAttemptAutoLocal(options) {
|
|
2989
4169
|
if (options.localRuntimeAdapter || options.localRuntimeAdapterFactory)
|
|
2990
4170
|
return true;
|
|
@@ -3042,12 +4222,14 @@ async function runHttpAgentTurn(options, authToken) {
|
|
|
3042
4222
|
(name) => name.trim()
|
|
3043
4223
|
);
|
|
3044
4224
|
const shouldStream = !options.noStream && !options.background;
|
|
4225
|
+
const expandedMessage = options.pastedTextStore?.items.size ? expandCollapsedPastes(options.message, options.pastedTextStore) : options.message;
|
|
4226
|
+
const serverContextBlockScopes = options.contextBlockScopes && options.contextBlockScopes.length > 0 ? options.contextBlockScopes : options.extraContextBlocks && options.extraContextBlocks.length > 0 ? options.extraContextBlocks.map((block) => ({
|
|
4227
|
+
content: block,
|
|
4228
|
+
cacheScope: "turn"
|
|
4229
|
+
})) : void 0;
|
|
3045
4230
|
const buildRequestBody = (stream) => JSON.stringify({
|
|
3046
4231
|
agentKey: options.agentKey,
|
|
3047
|
-
userInput: buildUserInputContent(
|
|
3048
|
-
options.extraContextBlocks?.length ? [...options.extraContextBlocks, "", options.message].join("\n") : options.message,
|
|
3049
|
-
options.imageUrls
|
|
3050
|
-
),
|
|
4232
|
+
userInput: buildUserInputContent(expandedMessage, options.imageUrls),
|
|
3051
4233
|
runtimeContext: {
|
|
3052
4234
|
surface: "cli",
|
|
3053
4235
|
host: "terminal",
|
|
@@ -3067,6 +4249,7 @@ async function runHttpAgentTurn(options, authToken) {
|
|
|
3067
4249
|
...options.background ? { background: true } : {},
|
|
3068
4250
|
...typeof options.timeoutMs === "number" ? { timeoutMs: options.timeoutMs } : {},
|
|
3069
4251
|
...options.modelOverride ? { runtimeOptions: { quickChatModelOverride: options.modelOverride } } : {},
|
|
4252
|
+
...serverContextBlockScopes ? { contextBlockScopes: serverContextBlockScopes } : {},
|
|
3070
4253
|
stream
|
|
3071
4254
|
});
|
|
3072
4255
|
const postAgentRun = (stream) => fetchImpl(`${options.serverUrl}/api/agent/run`, {
|
|
@@ -3224,7 +4407,7 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3224
4407
|
} : void 0;
|
|
3225
4408
|
const currentDialogId = options.continueDialogId ?? ulid();
|
|
3226
4409
|
const runChildTurn = async (input) => {
|
|
3227
|
-
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-
|
|
4410
|
+
const { runLocalAgentTurn } = await import("./agentRuntimeLocal-V5UV7S4R.js");
|
|
3228
4411
|
return runLocalAgentTurn(input);
|
|
3229
4412
|
};
|
|
3230
4413
|
const createFreshChildBaseAdapter = () => {
|
|
@@ -3272,6 +4455,7 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3272
4455
|
spaceId: options.spaceId,
|
|
3273
4456
|
runtimeContext
|
|
3274
4457
|
});
|
|
4458
|
+
const expandedMessage = options.pastedTextStore?.items.size ? expandCollapsedPastes(options.message, options.pastedTextStore) : options.message;
|
|
3275
4459
|
const workingLabel = `${options.agentName} -> working locally`;
|
|
3276
4460
|
const turnOutput = createCliTurnOutput({
|
|
3277
4461
|
options,
|
|
@@ -3284,6 +4468,19 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3284
4468
|
adapter,
|
|
3285
4469
|
agentRef: options.agentKey,
|
|
3286
4470
|
input: buildUserInputContent(options.message, options.imageUrls),
|
|
4471
|
+
...expandedMessage !== options.message ? {
|
|
4472
|
+
persistedInput: buildUserInputContent(
|
|
4473
|
+
expandedMessage,
|
|
4474
|
+
options.imageUrls
|
|
4475
|
+
),
|
|
4476
|
+
persistedInputReference: buildUserInputContent(
|
|
4477
|
+
options.message,
|
|
4478
|
+
options.imageUrls
|
|
4479
|
+
)
|
|
4480
|
+
} : {},
|
|
4481
|
+
...options.pastedTextStore ? {
|
|
4482
|
+
contextReferenceResolver: (reference) => canResolveCollapsedPasteReference(options.pastedTextStore, reference)
|
|
4483
|
+
} : {},
|
|
3287
4484
|
continueDialogId: currentDialogId,
|
|
3288
4485
|
spaceId: options.spaceId,
|
|
3289
4486
|
category: options.category,
|
|
@@ -3292,8 +4489,7 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3292
4489
|
background: options.background,
|
|
3293
4490
|
noStream: options.noStream,
|
|
3294
4491
|
...runtimeContext ? { runtimeContext } : {},
|
|
3295
|
-
...options.extraContextBlocks?.length ? { contextBlocks: options.extraContextBlocks } : {},
|
|
3296
|
-
...options.contextBlockScopes?.length ? { contextBlockScopes: options.contextBlockScopes } : {},
|
|
4492
|
+
...options.contextBlockScopes?.length ? { contextBlockScopes: options.contextBlockScopes } : options.extraContextBlocks?.length ? { contextBlocks: options.extraContextBlocks } : {},
|
|
3297
4493
|
...typeof options.timeoutMs === "number" ? { timeoutMs: options.timeoutMs } : {},
|
|
3298
4494
|
...options.actionGateHandler ? { onActionGate: options.actionGateHandler } : {},
|
|
3299
4495
|
onLoopEvent: (event) => {
|
|
@@ -3327,12 +4523,14 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3327
4523
|
};
|
|
3328
4524
|
} catch (error) {
|
|
3329
4525
|
turnOutput.spinner.stop();
|
|
4526
|
+
const savedDialogId = error?.dialogId;
|
|
3330
4527
|
if (error?.code === LOCAL_TURN_ABORTED_CODE || options.abortSignal?.aborted) {
|
|
3331
|
-
const
|
|
4528
|
+
const pendingToolName = error?.pendingToolName;
|
|
3332
4529
|
return {
|
|
3333
4530
|
exitCode: 0,
|
|
3334
4531
|
streamInterrupted: true,
|
|
3335
|
-
...
|
|
4532
|
+
...savedDialogId ? { dialogId: savedDialogId } : {},
|
|
4533
|
+
...pendingToolName ? { pendingToolName } : {}
|
|
3336
4534
|
};
|
|
3337
4535
|
}
|
|
3338
4536
|
if (settings.reportFailure) {
|
|
@@ -3341,7 +4539,11 @@ async function runLocalAgentTurnForCli(options, settings) {
|
|
|
3341
4539
|
`
|
|
3342
4540
|
);
|
|
3343
4541
|
}
|
|
3344
|
-
return {
|
|
4542
|
+
return {
|
|
4543
|
+
exitCode: 1,
|
|
4544
|
+
localError: error,
|
|
4545
|
+
...savedDialogId ? { dialogId: savedDialogId } : {}
|
|
4546
|
+
};
|
|
3345
4547
|
}
|
|
3346
4548
|
}
|
|
3347
4549
|
async function runAgentTurn(options) {
|
|
@@ -3361,7 +4563,8 @@ async function runAgentTurn(options) {
|
|
|
3361
4563
|
exitCode: localResult.exitCode,
|
|
3362
4564
|
...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
|
|
3363
4565
|
...localResult.turnTokens ? { turnTokens: localResult.turnTokens } : {},
|
|
3364
|
-
...localResult.streamInterrupted ? { streamInterrupted: localResult.streamInterrupted } : {}
|
|
4566
|
+
...localResult.streamInterrupted ? { streamInterrupted: localResult.streamInterrupted } : {},
|
|
4567
|
+
...localResult.pendingToolName ? { pendingToolName: localResult.pendingToolName } : {}
|
|
3365
4568
|
};
|
|
3366
4569
|
}
|
|
3367
4570
|
if (isMissingLocalAgentConfigError(localResult.localError, options.agentKey)) {
|
|
@@ -3387,13 +4590,13 @@ async function runAgentTurn(options) {
|
|
|
3387
4590
|
}
|
|
3388
4591
|
}
|
|
3389
4592
|
const localErrorMessage = localResult.localError ? toErrorMessage(localResult.localError) : "local runtime failed";
|
|
3390
|
-
options.output.write(
|
|
3391
|
-
`[nolo] auto runtime: local run unavailable (${localErrorMessage}). Not falling back to server. Fix the local credential/config and retry, or use --server to run on the server explicitly.
|
|
3392
|
-
`
|
|
3393
|
-
);
|
|
4593
|
+
options.output.write(describeLocalRunFailure(localErrorMessage));
|
|
3394
4594
|
return {
|
|
3395
4595
|
exitCode: 1,
|
|
3396
|
-
...localResult.dialogId ? { dialogId: localResult.dialogId } : {}
|
|
4596
|
+
...localResult.dialogId ? { dialogId: localResult.dialogId } : {},
|
|
4597
|
+
// Keep localError so TUI can show balance/quota/dialog-preserved hints
|
|
4598
|
+
// instead of only the raw auto-runtime line.
|
|
4599
|
+
...localResult.localError ? { localError: localResult.localError } : {}
|
|
3397
4600
|
};
|
|
3398
4601
|
}
|
|
3399
4602
|
}
|
|
@@ -3415,196 +4618,6 @@ async function runAgentTurn(options) {
|
|
|
3415
4618
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
3416
4619
|
import { join as join2 } from "node:path";
|
|
3417
4620
|
|
|
3418
|
-
// packages/agent-runtime/quickChatIntentCore.ts
|
|
3419
|
-
var INTENT_MODEL = "deepseek-v4-flash";
|
|
3420
|
-
var INTENT_PROVIDER = "deepseek";
|
|
3421
|
-
var QUICK_CHAT_INTENT_TIMEOUT_MS = 4e3;
|
|
3422
|
-
var SHORT_GREETING_MAX_LENGTH = 20;
|
|
3423
|
-
var SHORT_GREETING_PATTERN = /^(?:hi|hello|hey|hiya|yo|sup|howdy|嗨|哈喽|哈囉|你好|您好|在吗|在嘛|喂|早上好|中午好|下午好|晚上好|拜拜|再见|谢谢|thanks|thx|ok|好的|收到|了解)[!.。,、~~]?$/iu;
|
|
3424
|
-
function isShortGreeting(text) {
|
|
3425
|
-
const trimmed = text.trim();
|
|
3426
|
-
if (!trimmed) return false;
|
|
3427
|
-
if (trimmed.length > SHORT_GREETING_MAX_LENGTH) return false;
|
|
3428
|
-
return SHORT_GREETING_PATTERN.test(trimmed);
|
|
3429
|
-
}
|
|
3430
|
-
var COMPLEXITY_SIMPLE_MAX_LENGTH = 80;
|
|
3431
|
-
var COMPLEXITY_MEDIUM_MAX_LENGTH = 500;
|
|
3432
|
-
var COMPLEXITY_KEYWORDS = /为什么|如何|分析|对比|比较|设计|架构|实现|原理|推导|评价|区别|关系|影响|优化|重构/;
|
|
3433
|
-
var COMPLEXITY_CODE_BLOCK = /```[\s\S]*```/;
|
|
3434
|
-
function estimateComplexity(text) {
|
|
3435
|
-
const trimmed = text.trim();
|
|
3436
|
-
const len = trimmed.length;
|
|
3437
|
-
if (len > COMPLEXITY_MEDIUM_MAX_LENGTH) return "complex";
|
|
3438
|
-
if (COMPLEXITY_CODE_BLOCK.test(trimmed)) return "complex";
|
|
3439
|
-
if (len > COMPLEXITY_SIMPLE_MAX_LENGTH) return "medium";
|
|
3440
|
-
if (COMPLEXITY_KEYWORDS.test(trimmed)) return "medium";
|
|
3441
|
-
return "simple";
|
|
3442
|
-
}
|
|
3443
|
-
var TIER_DESCRIPTIONS = {
|
|
3444
|
-
flash: "\u5FEB\u901F\u7B80\u5355\uFF1A\u95EE\u5019\u3001\u95F2\u804A\u3001\u5FEB\u901F\u95EE\u7B54\u3001\u7FFB\u8BD1\u3001\u77ED\u6587",
|
|
3445
|
-
balanced: "\u5E73\u8861\u63A8\u7406\uFF1A\u5206\u6790\u3001\u4E2D\u7B49\u957F\u5EA6\u5199\u4F5C\u3001\u4EE3\u7801\u3001\u63A8\u7406",
|
|
3446
|
-
quality: "\u9AD8\u8D28\u91CF\u6DF1\u5EA6\uFF1A\u590D\u6742\u63A8\u7406\u3001\u957F\u6587\u3001\u67B6\u6784\u8BBE\u8BA1\u3001\u6DF1\u5EA6\u5206\u6790"
|
|
3447
|
-
};
|
|
3448
|
-
function buildQuickChatIntentSystemPrompt(tierAgents) {
|
|
3449
|
-
const agentList = tierAgents.map((t2) => ` - "${t2.agentKey}"\uFF1A${t2.description}`).join("\n");
|
|
3450
|
-
return `\u4F60\u662F\u4E00\u4E2A\u610F\u56FE\u8DEF\u7531\u5668\u3002\u6839\u636E\u7528\u6237\u6D88\u606F\uFF0C\u5224\u65AD\u5E94\u8BE5\u4EA4\u7ED9\u54EA\u4E2A agent \u5904\u7406\u3002
|
|
3451
|
-
|
|
3452
|
-
\u53EF\u9009 agent \u5217\u8868\uFF08agentKey \u4E0E\u63CF\u8FF0\uFF09\uFF1A
|
|
3453
|
-
${agentList}
|
|
3454
|
-
|
|
3455
|
-
\u5224\u65AD\u539F\u5219\uFF08\u9ED8\u8BA4\u504F\u5411\u901A\u7528\u6863\u4F4D\uFF1B\u4E13\u804C agent \u5728\u660E\u786E\u5339\u914D\u65F6\u4F7F\u7528\uFF1B**\u7F16\u7801/\u672C\u5730\u4ED3\u5E93\u4EFB\u52A1\u8D70\u901A\u7528\u6863 + needsWorkspace=true**\uFF09\uFF1A
|
|
3456
|
-
- \u9ED8\u8BA4\u60C5\u51B5\u4E0B\uFF0C**\u9664\u975E\u7528\u6237\u660E\u786E\u8868\u8FBE\u8981\u5EFA\u5E94\u7528/\u5EFA Agent/\u63D0\u4EA4\u53CD\u9988/\u591A Agent \u7F16\u6392**\uFF0C\u5426\u5219\u9009\u901A\u7528\u6863\u4F4D\uFF08flash/balanced/quality\uFF09\uFF1A
|
|
3457
|
-
- \u7B80\u5355\u95EE\u5019\u3001\u95F2\u804A\u3001\u5FEB\u901F\u95EE\u7B54\u3001\u7FFB\u8BD1\u3001\u77ED\u6587 \u2192 \u9009 flash \u6863
|
|
3458
|
-
- \u9700\u8981\u63A8\u7406\u3001\u5206\u6790\u3001\u4E2D\u7B49\u957F\u5EA6\u5199\u4F5C\u3001\u666E\u901A\u4EE3\u7801\u89E3\u91CA/\u67B6\u6784\u95EE\u7B54 \u2192 \u9009 balanced \u6863
|
|
3459
|
-
- \u590D\u6742\u63A8\u7406\u3001\u957F\u6587\u3001\u67B6\u6784\u8BBE\u8BA1\u3001\u6DF1\u5EA6\u5206\u6790 \u2192 \u9009 quality \u6863
|
|
3460
|
-
- **\u660E\u786E\u7F16\u7801\u4EFB\u52A1\uFF08\u5B9E\u73B0\u529F\u80FD\u3001\u4FEE bug\u3001refactor\u3001\u5199/\u8865\u6D4B\u8BD5\u3001\u8DD1 build/tests/ci\uFF09\u6216\u67E5\u770B\u672C\u673A\u4ED3\u5E93/\u4EE3\u7801\u72B6\u6001\uFF08git/\u5206\u652F/commit/\u672C\u5730\u4E0E\u8FDC\u7A0B\u5DEE\u8DDD/\u672A\u63D0\u4EA4\u6539\u52A8\u7B49\uFF09** \u2192 \u9009 balanced \u6216 quality \u6863\uFF08\u6309\u590D\u6742\u5EA6\uFF1B**\u4E0D\u8981\u9009 flash**\uFF09\uFF0C\u4E14 needsWorkspace=true
|
|
3461
|
-
- \u4E13\u804C agent \u8DEF\u7531\u89C4\u5219\uFF08\u6709\u660E\u786E\u5339\u914D\u65F6\u4F7F\u7528\uFF09\uFF1A
|
|
3462
|
-
- \u8981\u63D0\u4EA4/\u8BB0\u5F55 bug\u3001\u4F53\u9A8C\u95EE\u9898\u3001\u6570\u636E\u5F02\u5E38\u3001\u4EA7\u54C1\u5EFA\u8BAE\uFF0C\u6216\u53E3\u8BED\u5982\u300C\u60F3\u53CD\u9988\u4E00\u4E9B\u95EE\u9898\u300D\u300C\u53CD\u9988\u4E00\u4E0B\u300D\u2192 \u9009\u610F\u89C1\u53CD\u9988\u4E13\u804C agent
|
|
3463
|
-
- \u8981\u65B0\u5EFA\u6216\u5B9A\u5236 AI/Agent/\u667A\u80FD\u4F53\u52A9\u624B\uFF08\u542B\u914D\u7F6E\u5DE5\u5177\u3001\u77E5\u8BC6\u3001\u786E\u8BA4\u521B\u5EFA\uFF09\u2192 \u9009\u521B\u5EFA Agent \u4E13\u804C agent
|
|
3464
|
-
- \u8981\u505A/\u6539/\u53D1\u5E03\u7F51\u7AD9\u3001\u7F51\u9875\u3001\u5C0F\u5E94\u7528\u3001\u9884\u7EA6\u9875\u3001\u535A\u5BA2\u3001\u770B\u677F \u2192 \u9009\u5E94\u7528\u6784\u5EFA\u4E13\u804C agent
|
|
3465
|
-
- \u8981\u6D3E\u591A\u4E2A agent\u3001\u591A agent \u5E76\u884C\u3001\u62C6\u6210\u4EFB\u52A1\u540E\u53F0\u6267\u884C\u3001\u591A\u4E2A agent review\u3001\u8BA9\u4E0D\u540C agent \u8BA8\u8BBA/\u4F1A\u5546 \u2192 \u9009\u591A Agent \u7F16\u6392\u4E13\u804C agent\uFF08\u663E\u5F0F multi-agent \u4F18\u5148\uFF09
|
|
3466
|
-
- **\u62FF\u4E0D\u51C6\u65F6**\uFF1A\u7EAF\u95F2\u804A\u9009 flash\uFF1B**\u82E5\u6CBE\u8FB9\u672C\u5730\u4ED3\u5E93/\u5F53\u524D\u4EE3\u7801\u72B6\u6001\uFF0C\u9009 balanced/quality + needsWorkspace=true**\u3002
|
|
3467
|
-
|
|
3468
|
-
\u540C\u65F6\u5224\u65AD\u672C\u8F6E\u662F\u5426\u9700\u8981\u6CE8\u5165\u300C\u5DE5\u4F5C\u533A\u53EA\u8BFB\u5DE5\u5177\u300D\uFF08listFiles/globFiles/searchFiles/readFile/execShell \u7B49\uFF09\uFF1A
|
|
3469
|
-
- needsWorkspace=true \u7684\u573A\u666F\uFF1A\u7528\u6237\u8981\u8BFB/\u6539/\u5206\u6790\u6587\u4EF6\u6216\u4EE3\u7801\u3001\u63D0\u5230\u4E86\u6587\u4EF6\u8DEF\u5F84/\u6269\u5C55\u540D\uFF08.md/.csv/.ts \u7B49\uFF09\u3001\u63D0\u5230\u5DE5\u4F5C\u533A/\u4EE3\u7801\u5E93/\u4ED3\u5E93/\u76EE\u5F55/git/\u5206\u652F\u3001\u8981\u770B\u5F53\u524D\u4EE3\u7801\u6216\u4ED3\u5E93\u72B6\u6001\u3001\u672C\u5730\u641C\u7D22/\u67E5\u770B\u4EE3\u7801\u3002
|
|
3470
|
-
- needsWorkspace=false \u7684\u573A\u666F\uFF1A\u901A\u7528\u77E5\u8BC6\u95EE\u7B54\uFF08\u5982\u300C\u5E7F\u4E1C\u7ECF\u6D4E\u6570\u636E\u300D\u300C\u5199\u4E00\u9996\u8BD7\u300D\uFF09\u3001\u7EAF\u95F2\u804A\u95EE\u5019\u3001\u7FFB\u8BD1\u3001\u4E0D\u6D89\u53CA\u672C\u5730\u6587\u4EF6/\u4ED3\u5E93\u3002
|
|
3471
|
-
- \u6F0F\u5224\uFF08\u7528\u6237\u8981\u6587\u4EF6\u800C\u6CA1\u5E26\u5DE5\u5177\uFF09\u6BD4\u8BEF\u5224\uFF08\u767D\u641C\u51E0\u8F6E\uFF09\u4EE3\u4EF7\u66F4\u9AD8\uFF0C\u5B81\u53EF\u504F\u5BBD\u5224 true\u3002
|
|
3472
|
-
|
|
3473
|
-
\u5728\u7ED9\u51FA agentKey \u4E4B\u524D\uFF0C\u5148\u5728\u5FC3\u91CC\u533A\u5206\u5019\u9009\u6863\u4F4D\u7684\u8FB9\u754C\u518D\u7ED9\u7F6E\u4FE1\u5EA6\uFF1Abalanced \u4E0E quality \u7684\u8FB9\u754C\u5728\u4E8E\u590D\u6742\u5EA6/\u7BC7\u5E45/\u662F\u5426\u9700\u8981\u6DF1\u5EA6\u5206\u6790\uFF0C\u62FF\u4E0D\u51C6\u5C31\u7ED9\u4F4E confidence\u3002
|
|
3474
|
-
|
|
3475
|
-
\u540C\u65F6\u5224\u65AD\u672C\u8F6E\u6D88\u606F\u662F\u5426\u9700\u8981\u6302\u8F7D\u5BF9\u8C61\u64CD\u4F5C\u6280\u80FD\uFF08skills \u6570\u7EC4\uFF0C\u672A\u547D\u4E2D\u7ED9 []\uFF09\uFF1A
|
|
3476
|
-
- \u7528\u6237\u8981\u65B0\u5EFA/\u6574\u7406/\u5F55\u5165/\u6279\u91CF\u5904\u7406\u8868\u683C\u6570\u636E\uFF08\u5EFA\u8868\u3001\u52A0\u884C\u3001\u6539\u5217\u3001\u6309\u6761\u4EF6\u6574\u7406\u6570\u636E\uFF09\u2192 skills \u542B "table"
|
|
3477
|
-
- \u7528\u6237\u8981\u5199/\u6DA6\u8272/\u6539\u5199/\u7EED\u5199/\u6392\u7248\u4E00\u7BC7\u6587\u6863\u6216\u6587\u7AE0 \u2192 skills \u542B "doc"
|
|
3478
|
-
- \u7528\u6237\u8981\u5199/\u6539/\u5B9E\u73B0/\u4FEE bug/refactor/\u8865\u6D4B\u8BD5/\u5BA1\u67E5\u5E76\u4FEE\u6539\u4EE3\u7801 \u2192 skills \u542B "code"\uFF08\u4EC5\u95EE\u901A\u7528\u77E5\u8BC6\u3001\u7EAF\u95F2\u804A\u3001\u53EA\u67E5\u770B git/\u4ED3\u5E93\u72B6\u6001\u800C\u4E0D\u4FEE\u6539\u4EE3\u7801\u65F6\u4E0D\u6302 "code"\uFF09
|
|
3479
|
-
- \u666E\u901A\u95EE\u7B54/\u7EAF\u95F2\u804A/\u5EFA\u5E94\u7528 \u2192 skills \u4E3A []
|
|
3480
|
-
|
|
3481
|
-
\u53EA\u8F93\u51FA JSON\uFF0C\u4E0D\u8981\u8F93\u51FA\u5176\u4ED6\u5185\u5BB9\uFF1A
|
|
3482
|
-
{"confidence": <0\u52301\u4E4B\u95F4\u7684\u5C0F\u6570\uFF0C\u8868\u793A\u4F60\u5BF9\u8FD9\u4E2A\u5206\u7C7B\u5224\u65AD\u7684\u628A\u63E1\u7A0B\u5EA6>, "agentKey": "<\u4ECE\u5217\u8868\u4E2D\u9009\u62E9\u7684 agentKey>", "needsWorkspace": <true \u6216 false>, "skills": <\u5B57\u7B26\u4E32\u6570\u7EC4\uFF0C\u5143\u7D20\u53EA\u80FD\u662F "table" | "doc" | "code"\uFF0C\u672A\u547D\u4E2D\u7ED9 []>}`;
|
|
3483
|
-
}
|
|
3484
|
-
function parseQuickChatIntentResult(content, tierAgents) {
|
|
3485
|
-
try {
|
|
3486
|
-
const parsed = JSON.parse(content.trim());
|
|
3487
|
-
if (typeof parsed !== "object" || parsed === null || !("agentKey" in parsed)) return null;
|
|
3488
|
-
const key = parsed.agentKey;
|
|
3489
|
-
if (typeof key !== "string") return null;
|
|
3490
|
-
if (!tierAgents.some((t2) => t2.agentKey === key)) return null;
|
|
3491
|
-
const rawNeedsWorkspace = parsed.needsWorkspace;
|
|
3492
|
-
const needsWorkspace = rawNeedsWorkspace === true;
|
|
3493
|
-
const rawConfidence = parsed.confidence;
|
|
3494
|
-
const confidence = typeof rawConfidence === "number" && Number.isFinite(rawConfidence) && rawConfidence >= 0 && rawConfidence <= 1 ? rawConfidence : void 0;
|
|
3495
|
-
const rawSkills = parsed.skills;
|
|
3496
|
-
let skills;
|
|
3497
|
-
if (Array.isArray(rawSkills)) {
|
|
3498
|
-
const filtered = [...new Set(rawSkills)].filter(
|
|
3499
|
-
(s) => s === "table" || s === "doc" || s === "code"
|
|
3500
|
-
);
|
|
3501
|
-
if (filtered.length > 0) skills = filtered;
|
|
3502
|
-
}
|
|
3503
|
-
return { agentKey: key, needsWorkspace, confidence, skills };
|
|
3504
|
-
} catch {
|
|
3505
|
-
return null;
|
|
3506
|
-
}
|
|
3507
|
-
}
|
|
3508
|
-
|
|
3509
|
-
// packages/cli/client/autoModelRouter.ts
|
|
3510
|
-
var CLI_AUTO_TIER_AGENT_KEYS = {
|
|
3511
|
-
flash: PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
|
|
3512
|
-
balanced: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
|
|
3513
|
-
quality: PUBLIC_GLM_52_AGENT_KEY
|
|
3514
|
-
};
|
|
3515
|
-
var CLI_IMAGE_AGENT_KEY = PUBLIC_KIMI_K26_IMAGE_AGENT_KEY;
|
|
3516
|
-
var CLI_AUTO_TIER_AGENT_KEY_TABLE = {
|
|
3517
|
-
[CLI_AUTO_TIER_AGENT_KEYS.flash]: true,
|
|
3518
|
-
[CLI_AUTO_TIER_AGENT_KEYS.balanced]: true,
|
|
3519
|
-
[CLI_AUTO_TIER_AGENT_KEYS.quality]: true
|
|
3520
|
-
};
|
|
3521
|
-
var buildRouteOptions = () => ["flash", "balanced", "quality"].map((tier) => ({
|
|
3522
|
-
tier,
|
|
3523
|
-
agentKey: CLI_AUTO_TIER_AGENT_KEYS[tier],
|
|
3524
|
-
description: TIER_DESCRIPTIONS[tier]
|
|
3525
|
-
}));
|
|
3526
|
-
var tierForAgentKey = (agentKey) => {
|
|
3527
|
-
for (const tier of ["flash", "balanced", "quality"]) {
|
|
3528
|
-
if (CLI_AUTO_TIER_AGENT_KEYS[tier] === agentKey) return tier;
|
|
3529
|
-
}
|
|
3530
|
-
return null;
|
|
3531
|
-
};
|
|
3532
|
-
function resolveCliAutoFallbackTier(text) {
|
|
3533
|
-
switch (estimateComplexity(text)) {
|
|
3534
|
-
case "complex":
|
|
3535
|
-
return "quality";
|
|
3536
|
-
case "medium":
|
|
3537
|
-
return "balanced";
|
|
3538
|
-
case "simple":
|
|
3539
|
-
default:
|
|
3540
|
-
return "flash";
|
|
3541
|
-
}
|
|
3542
|
-
}
|
|
3543
|
-
async function classifyCliAutoRoute(text, options) {
|
|
3544
|
-
const timeoutMs = options.timeoutMs ?? QUICK_CHAT_INTENT_TIMEOUT_MS;
|
|
3545
|
-
const fallbackTier = resolveCliAutoFallbackTier(text);
|
|
3546
|
-
const fallback = () => ({
|
|
3547
|
-
agentKey: CLI_AUTO_TIER_AGENT_KEYS[fallbackTier],
|
|
3548
|
-
tier: fallbackTier,
|
|
3549
|
-
classified: false
|
|
3550
|
-
});
|
|
3551
|
-
if (!text.trim()) return fallback();
|
|
3552
|
-
if (isShortGreeting(text)) {
|
|
3553
|
-
return {
|
|
3554
|
-
agentKey: CLI_AUTO_TIER_AGENT_KEYS.flash,
|
|
3555
|
-
tier: "flash",
|
|
3556
|
-
classified: true
|
|
3557
|
-
};
|
|
3558
|
-
}
|
|
3559
|
-
if (!options.authToken) return fallback();
|
|
3560
|
-
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
3561
|
-
const controller = new AbortController();
|
|
3562
|
-
const timeoutHandle = setTimeout(() => controller.abort(), timeoutMs);
|
|
3563
|
-
try {
|
|
3564
|
-
const routeOptions = buildRouteOptions();
|
|
3565
|
-
const messages = [
|
|
3566
|
-
{ role: "system", content: buildQuickChatIntentSystemPrompt(routeOptions) },
|
|
3567
|
-
{ role: "user", content: text }
|
|
3568
|
-
];
|
|
3569
|
-
const { url, init } = buildPlatformChatCompletionRequest({
|
|
3570
|
-
providerConfig: {
|
|
3571
|
-
serverUrl: options.serverUrl,
|
|
3572
|
-
authToken: options.authToken,
|
|
3573
|
-
agentKey: CLI_AUTO_TIER_AGENT_KEYS.flash,
|
|
3574
|
-
model: INTENT_MODEL,
|
|
3575
|
-
provider: INTENT_PROVIDER,
|
|
3576
|
-
endpoint: resolvePlatformChatCompletionsEndpoint(INTENT_PROVIDER) ?? "",
|
|
3577
|
-
requestOptions: {}
|
|
3578
|
-
},
|
|
3579
|
-
messages,
|
|
3580
|
-
stream: false
|
|
3581
|
-
});
|
|
3582
|
-
const response = await fetchImpl(url, {
|
|
3583
|
-
...init,
|
|
3584
|
-
signal: controller.signal
|
|
3585
|
-
});
|
|
3586
|
-
if (!response.ok) return fallback();
|
|
3587
|
-
const data = parsePlatformChatCompletionData(await response.text());
|
|
3588
|
-
const content = data?.choices?.[0]?.message?.content;
|
|
3589
|
-
if (typeof content !== "string" || !content.trim()) return fallback();
|
|
3590
|
-
const parsed = parseQuickChatIntentResult(content, routeOptions);
|
|
3591
|
-
if (!parsed) return fallback();
|
|
3592
|
-
const tier = tierForAgentKey(parsed.agentKey) ?? fallbackTier;
|
|
3593
|
-
return {
|
|
3594
|
-
agentKey: parsed.agentKey,
|
|
3595
|
-
tier,
|
|
3596
|
-
classified: true,
|
|
3597
|
-
confidence: parsed.confidence,
|
|
3598
|
-
needsWorkspace: parsed.needsWorkspace,
|
|
3599
|
-
skills: parsed.skills
|
|
3600
|
-
};
|
|
3601
|
-
} catch {
|
|
3602
|
-
return fallback();
|
|
3603
|
-
} finally {
|
|
3604
|
-
clearTimeout(timeoutHandle);
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
|
|
3608
4621
|
// packages/cli/agentRunPrompts.ts
|
|
3609
4622
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3610
4623
|
import { dirname, extname, isAbsolute, join, relative as relativePath, resolve, sep } from "node:path";
|
|
@@ -3948,16 +4961,16 @@ var buildCjkTokens = (text) => {
|
|
|
3948
4961
|
}
|
|
3949
4962
|
return tokens;
|
|
3950
4963
|
};
|
|
3951
|
-
var
|
|
4964
|
+
var tokenize2 = (text) => {
|
|
3952
4965
|
const normalized = text.toLowerCase();
|
|
3953
4966
|
const wordTokens = normalized.split(/[\s,.;:!?()[\]{}"'`,。!?:;、]+/).map((token) => token.trim()).filter((token) => token.length >= 2);
|
|
3954
4967
|
return [...wordTokens, ...buildCjkTokens(normalized)];
|
|
3955
4968
|
};
|
|
3956
4969
|
var keywordScore = (query, item) => {
|
|
3957
|
-
const queryTokens = new Set(
|
|
4970
|
+
const queryTokens = new Set(tokenize2(query));
|
|
3958
4971
|
if (queryTokens.size === 0) return 0;
|
|
3959
4972
|
const haystack = /* @__PURE__ */ new Set([
|
|
3960
|
-
...
|
|
4973
|
+
...tokenize2(item.content),
|
|
3961
4974
|
...(item.tags ?? []).map((tag) => tag.toLowerCase()),
|
|
3962
4975
|
item.patternKey?.toLowerCase() ?? ""
|
|
3963
4976
|
]);
|
|
@@ -4571,8 +5584,7 @@ ${mdContent}`);
|
|
|
4571
5584
|
traceTools: parsed.traceTools,
|
|
4572
5585
|
...parsed.eventsMode ? { eventsMode: parsed.eventsMode } : {},
|
|
4573
5586
|
...parsed.taskEvidence ? { taskEvidence: parsed.taskEvidence } : {},
|
|
4574
|
-
...extraContextBlocks.length > 0 ? { extraContextBlocks } : {}
|
|
4575
|
-
...contextBlockScopes.length > 0 ? { contextBlockScopes } : {}
|
|
5587
|
+
...contextBlockScopes.length > 0 ? { contextBlockScopes } : extraContextBlocks.length > 0 ? { extraContextBlocks } : {}
|
|
4576
5588
|
});
|
|
4577
5589
|
let result = await raceWithWatchdog(
|
|
4578
5590
|
runner({
|
|
@@ -4587,12 +5599,20 @@ ${mdContent}`);
|
|
|
4587
5599
|
`[nolo] quota exhausted on ${agentKey}, falling back to ${fallbackAgentKey}
|
|
4588
5600
|
`
|
|
4589
5601
|
);
|
|
4590
|
-
const fallbackResult = await raceWithWatchdog(
|
|
5602
|
+
const fallbackResult = await raceWithWatchdog(
|
|
5603
|
+
runner({
|
|
5604
|
+
...buildRunOptions(fallbackAgentKey),
|
|
5605
|
+
...result.dialogId ? { continueDialogId: result.dialogId } : {}
|
|
5606
|
+
})
|
|
5607
|
+
);
|
|
4591
5608
|
clearWatchdogs();
|
|
4592
5609
|
if (fallbackResult.exitCode === 0) {
|
|
4593
5610
|
result = fallbackResult;
|
|
4594
5611
|
} else {
|
|
4595
|
-
result =
|
|
5612
|
+
result = {
|
|
5613
|
+
...fallbackResult,
|
|
5614
|
+
...fallbackResult.dialogId || result.dialogId ? { dialogId: fallbackResult.dialogId ?? result.dialogId } : {}
|
|
5615
|
+
};
|
|
4596
5616
|
output.write(
|
|
4597
5617
|
`[nolo] fallback to ${fallbackAgentKey} also failed: ${fallbackResult.localError instanceof Error ? fallbackResult.localError.message : String(fallbackResult.localError ?? "unknown error")}
|
|
4598
5618
|
`
|
|
@@ -4682,12 +5702,43 @@ function isQuotaExhaustedError(error) {
|
|
|
4682
5702
|
if (typeof maybeStatusCode === "number" && maybeStatusCode === 429) return true;
|
|
4683
5703
|
return false;
|
|
4684
5704
|
}
|
|
5705
|
+
var BALANCE_ERROR_PATTERNS = [
|
|
5706
|
+
/UPSTREAM_402/i,
|
|
5707
|
+
/Insufficient Balance/i,
|
|
5708
|
+
/insufficient\s+balance/i,
|
|
5709
|
+
/余额不足/
|
|
5710
|
+
];
|
|
5711
|
+
function isBalanceExhaustedError(error) {
|
|
5712
|
+
if (!error) return false;
|
|
5713
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : String(error?.message ?? "");
|
|
5714
|
+
return BALANCE_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
5715
|
+
}
|
|
4685
5716
|
|
|
4686
5717
|
export {
|
|
5718
|
+
CLI_IMAGE_AGENT_KEY,
|
|
5719
|
+
CLI_AUTO_TIER_AGENT_KEY_TABLE,
|
|
5720
|
+
classifyCliAutoRoute,
|
|
5721
|
+
resolveAgentContextWindow,
|
|
4687
5722
|
formatTokenCount,
|
|
4688
5723
|
renderTokenStatus,
|
|
4689
5724
|
resolveCliColorEnabled,
|
|
4690
5725
|
dimCliText,
|
|
5726
|
+
parseCliLocale,
|
|
5727
|
+
setCliLocale,
|
|
5728
|
+
initCliLocale,
|
|
5729
|
+
t,
|
|
5730
|
+
ANSI_ESCAPE_REGEX,
|
|
5731
|
+
stripAnsi,
|
|
5732
|
+
applyTerminalOutputToText,
|
|
5733
|
+
displayWidth,
|
|
5734
|
+
visibleWidth,
|
|
5735
|
+
truncateAnsi,
|
|
5736
|
+
fitAnsiLine,
|
|
5737
|
+
countPhysicalLines,
|
|
5738
|
+
takeDisplayWidth,
|
|
5739
|
+
padOrTruncateToWidth,
|
|
5740
|
+
wrapTranscriptLine,
|
|
5741
|
+
wrapTextToLines,
|
|
4691
5742
|
THEME_PALETTES,
|
|
4692
5743
|
getActiveThemeName,
|
|
4693
5744
|
setActiveThemeName,
|
|
@@ -4696,22 +5747,24 @@ export {
|
|
|
4696
5747
|
getActiveDensity,
|
|
4697
5748
|
setActiveDensity,
|
|
4698
5749
|
resolveTuiBrightness,
|
|
5750
|
+
setActiveTerminalBaseHex,
|
|
4699
5751
|
surfaceBackgroundSequence,
|
|
4700
5752
|
themeColorSequence,
|
|
4701
5753
|
themeText,
|
|
4702
|
-
highlightMarkdown,
|
|
4703
5754
|
formatAssistantDisplay,
|
|
4704
5755
|
normalizeThinkingDisplayMode,
|
|
4705
|
-
parseCliLocale,
|
|
4706
|
-
getCliLocale,
|
|
4707
|
-
setCliLocale,
|
|
4708
|
-
initCliLocale,
|
|
4709
|
-
t,
|
|
4710
5756
|
normalizeToolDisplayMode,
|
|
5757
|
+
COLLAPSED_PASTE_PLACEHOLDER_RE,
|
|
5758
|
+
shouldCollapsePaste,
|
|
5759
|
+
createCollapsedPasteStore,
|
|
5760
|
+
allocateCollapsedPaste,
|
|
5761
|
+
releaseCollapsedPaste,
|
|
5762
|
+
clearCollapsedPasteStore,
|
|
5763
|
+
replaceCollapsedPastesWithReferences,
|
|
5764
|
+
releaseCollapsedPasteReferences,
|
|
5765
|
+
expandRangeToCollapsedPasteChips,
|
|
5766
|
+
findCollapsedPasteSpanAt,
|
|
4711
5767
|
runAgentTurn,
|
|
4712
|
-
CLI_IMAGE_AGENT_KEY,
|
|
4713
|
-
CLI_AUTO_TIER_AGENT_KEY_TABLE,
|
|
4714
|
-
classifyCliAutoRoute,
|
|
4715
5768
|
resolveWorkflowReference,
|
|
4716
5769
|
resolveSkillReference,
|
|
4717
5770
|
buildSkillContextBlocks,
|
|
@@ -4719,5 +5772,6 @@ export {
|
|
|
4719
5772
|
normalizeCliImageInput,
|
|
4720
5773
|
inspectLocalRunWorkspace,
|
|
4721
5774
|
runAgentRunCommand,
|
|
4722
|
-
isQuotaExhaustedError
|
|
5775
|
+
isQuotaExhaustedError,
|
|
5776
|
+
isBalanceExhaustedError
|
|
4723
5777
|
};
|