zencode-cli 0.2.3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/zencode.js +728 -662
- package/dist/bin/zencode.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/zencode.js
CHANGED
|
@@ -817,7 +817,16 @@ function formatToolDetail(toolName, params) {
|
|
|
817
817
|
}
|
|
818
818
|
async function confirmExecution(toolName, params) {
|
|
819
819
|
if (structuredConfirmHandler) {
|
|
820
|
-
|
|
820
|
+
const result = await new Promise((resolve10) => {
|
|
821
|
+
pendingConfirmResolver = resolve10;
|
|
822
|
+
structuredConfirmHandler(toolName, params).then((res) => {
|
|
823
|
+
if (pendingConfirmResolver === resolve10) {
|
|
824
|
+
pendingConfirmResolver = null;
|
|
825
|
+
resolve10(res);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
return result;
|
|
821
830
|
}
|
|
822
831
|
const detail = formatToolDetail(toolName, params);
|
|
823
832
|
const prompt = `
|
|
@@ -828,12 +837,13 @@ ${detail}
|
|
|
828
837
|
const approved = await globalConfirmHandler(`${chalk.yellow("?")} \u662F\u5426\u6267\u884C\uFF1F(${chalk.green("y")}/${chalk.red("N")}) `);
|
|
829
838
|
return { approved };
|
|
830
839
|
}
|
|
831
|
-
var globalConfirmHandler, structuredConfirmHandler;
|
|
840
|
+
var globalConfirmHandler, structuredConfirmHandler, pendingConfirmResolver;
|
|
832
841
|
var init_permission = __esm({
|
|
833
842
|
"src/tools/permission.ts"() {
|
|
834
843
|
"use strict";
|
|
835
844
|
globalConfirmHandler = async () => false;
|
|
836
845
|
structuredConfirmHandler = null;
|
|
846
|
+
pendingConfirmResolver = null;
|
|
837
847
|
}
|
|
838
848
|
});
|
|
839
849
|
|
|
@@ -990,21 +1000,32 @@ var init_agent = __esm({
|
|
|
990
1000
|
tools.length > 0 ? tools : void 0,
|
|
991
1001
|
callbacks
|
|
992
1002
|
);
|
|
1003
|
+
const validToolCalls = [];
|
|
1004
|
+
const invalidToolCalls = [];
|
|
1005
|
+
if (assistantMsg.tool_calls) {
|
|
1006
|
+
for (const toolCall of assistantMsg.tool_calls) {
|
|
1007
|
+
try {
|
|
1008
|
+
JSON.parse(toolCall.function.arguments);
|
|
1009
|
+
validToolCalls.push(toolCall);
|
|
1010
|
+
} catch {
|
|
1011
|
+
invalidToolCalls.push(toolCall);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
assistantMsg.tool_calls = validToolCalls.length > 0 ? validToolCalls : void 0;
|
|
993
1016
|
this.conversation.addAssistantMessage(assistantMsg);
|
|
994
|
-
|
|
1017
|
+
for (const toolCall of invalidToolCalls) {
|
|
1018
|
+
callbacks.onToolResult?.(toolCall.function.name, `\u53C2\u6570\u89E3\u6790\u5931\u8D25\uFF1A\u65E0\u6548\u7684 JSON \u5B57\u7B26\u4E32
|
|
1019
|
+
${toolCall.function.arguments}`, false);
|
|
1020
|
+
}
|
|
1021
|
+
if (validToolCalls.length === 0) {
|
|
995
1022
|
lastContent = assistantMsg.content || "";
|
|
996
1023
|
break;
|
|
997
1024
|
}
|
|
998
|
-
for (const toolCall of
|
|
1025
|
+
for (const toolCall of validToolCalls) {
|
|
999
1026
|
if (this.interrupted) break;
|
|
1000
1027
|
const toolName = toolCall.function.name;
|
|
1001
|
-
|
|
1002
|
-
try {
|
|
1003
|
-
params = JSON.parse(toolCall.function.arguments);
|
|
1004
|
-
} catch {
|
|
1005
|
-
this.conversation.addToolResult(toolCall.id, "\u53C2\u6570\u89E3\u6790\u5931\u8D25\uFF1A\u65E0\u6548\u7684 JSON");
|
|
1006
|
-
continue;
|
|
1007
|
-
}
|
|
1028
|
+
const params = JSON.parse(toolCall.function.arguments);
|
|
1008
1029
|
try {
|
|
1009
1030
|
if (toolName === "edit-file") {
|
|
1010
1031
|
const editPath = params["path"];
|
|
@@ -1110,6 +1131,8 @@ function buildCorePrompt() {
|
|
|
1110
1131
|
- \u4E0D\u8981\u6DFB\u52A0\u7528\u6237\u672A\u8981\u6C42\u7684\u6CE8\u91CA\u3001\u6587\u6863\u3001\u7C7B\u578B\u6CE8\u89E3
|
|
1111
1132
|
- \u4E0D\u8981\u5F15\u5165\u5B89\u5168\u6F0F\u6D1E\uFF08\u6CE8\u5165\u3001XSS\u3001SQL \u6CE8\u5165\u7B49 OWASP Top 10\uFF09
|
|
1112
1133
|
- \u5F15\u7528\u4EE3\u7801\u65F6\u4F7F\u7528 \`\u6587\u4EF6\u8DEF\u5F84:\u884C\u53F7\` \u683C\u5F0F\uFF08\u5982 \`src/app.ts:42\`\uFF09\uFF0C\u65B9\u4FBF\u7528\u6237\u8DF3\u8F6C
|
|
1134
|
+
- \u7EDD\u5BF9\u7981\u6B62\u4F7F\u7528 \`// ... existing code\`\u3001\`// TODO\` \u6216\u4EFB\u4F55\u5F62\u5F0F\u7684\u7701\u7565\u5360\u4F4D\u7B26\u3002\u5FC5\u987B\u63D0\u4F9B\u5B8C\u6574\u4E14\u53EF\u8FD0\u884C\u7684\u4EE3\u7801\u3002
|
|
1135
|
+
- \u6C38\u8FDC\u4E0D\u8981\u5047\u8BBE\u67D0\u4E2A\u7B2C\u4E09\u65B9\u5E93\u5DF2\u5B89\u88C5\u3002\u5728\u4F7F\u7528\u4EFB\u4F55\u975E Node.js \u5185\u7F6E\u6A21\u5757\u524D\uFF0C\u5FC5\u987B\u786E\u8BA4\u5176\u5728\u9879\u76EE\u4E2D\u5DF2\u914D\u7F6E\u3002
|
|
1113
1136
|
|
|
1114
1137
|
# \u4EA4\u4E92\u98CE\u683C
|
|
1115
1138
|
|
|
@@ -1142,7 +1165,8 @@ function buildPlanningPrompt() {
|
|
|
1142
1165
|
|
|
1143
1166
|
\u4EE3\u7801\u8D28\u91CF\uFF1A
|
|
1144
1167
|
- \u5982\u679C\u5220\u9664\u4E86\u4EE3\u7801\uFF0C\u5C31\u5F7B\u5E95\u5220\u9664\uFF0C\u4E0D\u8981\u7559\u6CE8\u91CA\u8BF4"\u5DF2\u79FB\u9664"\uFF0C\u4E0D\u8981\u4FDD\u7559\u672A\u4F7F\u7528\u7684\u517C\u5BB9\u6027\u53D8\u91CF
|
|
1145
|
-
- \u4E0D\u8981\u7559\u4E0BTODO\u7136\u540E\u653E\u7740\u4E0D\u7BA1
|
|
1168
|
+
- \u4E0D\u8981\u7559\u4E0BTODO\u7136\u540E\u653E\u7740\u4E0D\u7BA1
|
|
1169
|
+
- \u6267\u884C\u4FEE\u6539\u540E\u5FC5\u987B\u8FDB\u884C\u95ED\u73AF\u9A8C\u8BC1\u3002\u4E3B\u52A8\u68C0\u67E5\u4EE3\u7801\u903B\u8F91\uFF0C\u6216\u4F7F\u7528 bash \u8FD0\u884C\u6784\u5EFA\u3001Lint \u7B49\u547D\u4EE4\u786E\u4FDD\u4FEE\u6539\u6CA1\u6709\u5F15\u5165\u9519\u8BEF`;
|
|
1146
1170
|
}
|
|
1147
1171
|
var init_planning = __esm({
|
|
1148
1172
|
"src/core/prompt/layers/planning.ts"() {
|
|
@@ -1161,6 +1185,7 @@ function buildParallelPrompt() {
|
|
|
1161
1185
|
- \u9700\u8981\u641C\u7D22 2+ \u4E2A\u6A21\u5F0F \u2192 spawn-agents \u5E76\u884C\u641C\u7D22
|
|
1162
1186
|
- \u9700\u8981\u4E86\u89E3 2+ \u4E2A\u6A21\u5757 \u2192 spawn-agents \u5E76\u884C\u5206\u6790
|
|
1163
1187
|
- \u53EA\u6709 1 \u4E2A\u76EE\u6807 \u2192 \u76F4\u63A5\u7528\u5DE5\u5177\uFF0C\u65E0\u9700 spawn-agents
|
|
1188
|
+
- \u5FC5\u987B\u4E3A\u6BCF\u4E2A\u5B50 Agent \u5206\u914D\u660E\u786E\u4E14\u65E0\u91CD\u53E0\u7684\u76EE\u6807\uFF0C\u907F\u514D\u591A\u4E2A Agent \u91CD\u590D\u5904\u7406\u540C\u4E00\u5BF9\u8C61\u9020\u6210\u6D6A\u8D39
|
|
1164
1189
|
|
|
1165
1190
|
\u793A\u4F8B - \u7528\u6237\u8BF4"\u5E2E\u6211\u7406\u89E3\u8BA4\u8BC1\u6A21\u5757"\uFF1A
|
|
1166
1191
|
\u6B63\u786E\uFF1Aspawn-agents \u540C\u65F6\u8BFB auth controller\u3001auth service\u3001auth middleware\u3001auth types
|
|
@@ -1182,7 +1207,8 @@ function buildGitPrompt() {
|
|
|
1182
1207
|
|
|
1183
1208
|
\u63D0\u4EA4\u89C4\u8303\uFF1A
|
|
1184
1209
|
- \u53EA\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u65F6\u624D\u521B\u5EFA commit
|
|
1185
|
-
- \u7528 git diff \u67E5\
|
|
1210
|
+
- \u63D0\u4EA4\u524D\u5FC5\u987B\u7528 git status \u548C git diff --staged \u68C0\u67E5\u5373\u5C06\u63D0\u4EA4\u7684\u5185\u5BB9\uFF0C\u786E\u4FDD\u6CA1\u6709\u6DF7\u5165\u4E0D\u76F8\u5173\u6587\u4EF6\u6216\u8C03\u8BD5\u4EE3\u7801
|
|
1211
|
+
- \u5EFA\u8BAE\u9075\u5FAA Conventional Commits \u89C4\u8303\uFF08\u5982 feat: ..., fix: ...\uFF09
|
|
1186
1212
|
- commit message \u63CF\u8FF0"\u4E3A\u4EC0\u4E48"\u800C\u975E"\u6539\u4E86\u4EC0\u4E48"
|
|
1187
1213
|
|
|
1188
1214
|
\u5B89\u5168\u89C4\u5219\uFF1A
|
|
@@ -2152,6 +2178,26 @@ var init_dispatch = __esm({
|
|
|
2152
2178
|
}
|
|
2153
2179
|
});
|
|
2154
2180
|
|
|
2181
|
+
// src/cli/tui/stores/progressStore.ts
|
|
2182
|
+
import { EventEmitter } from "events";
|
|
2183
|
+
var ProgressStore, progressStore;
|
|
2184
|
+
var init_progressStore = __esm({
|
|
2185
|
+
"src/cli/tui/stores/progressStore.ts"() {
|
|
2186
|
+
"use strict";
|
|
2187
|
+
ProgressStore = class extends EventEmitter {
|
|
2188
|
+
current;
|
|
2189
|
+
update(progress) {
|
|
2190
|
+
this.current = progress;
|
|
2191
|
+
this.emit("change", progress);
|
|
2192
|
+
}
|
|
2193
|
+
get() {
|
|
2194
|
+
return this.current;
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
progressStore = new ProgressStore();
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
|
|
2155
2201
|
// src/cli/tui/bridge.ts
|
|
2156
2202
|
function gray(text) {
|
|
2157
2203
|
return `${ANSI_GRAY}${text}${ANSI_RESET}`;
|
|
@@ -2245,19 +2291,19 @@ function createThinkFilter() {
|
|
|
2245
2291
|
return result;
|
|
2246
2292
|
};
|
|
2247
2293
|
}
|
|
2248
|
-
function
|
|
2249
|
-
let
|
|
2294
|
+
function createActionBatcher(dispatch) {
|
|
2295
|
+
let pendingActions = /* @__PURE__ */ new Map();
|
|
2250
2296
|
let timer = null;
|
|
2251
2297
|
function flush() {
|
|
2252
|
-
if (
|
|
2253
|
-
const
|
|
2254
|
-
|
|
2255
|
-
dispatch({ type,
|
|
2298
|
+
if (pendingActions.size > 0) {
|
|
2299
|
+
const actions = Array.from(pendingActions.values());
|
|
2300
|
+
pendingActions.clear();
|
|
2301
|
+
dispatch({ type: "BATCH", actions });
|
|
2256
2302
|
}
|
|
2257
2303
|
}
|
|
2258
2304
|
function start() {
|
|
2259
2305
|
if (!timer) {
|
|
2260
|
-
timer = setInterval(flush,
|
|
2306
|
+
timer = setInterval(flush, 200);
|
|
2261
2307
|
}
|
|
2262
2308
|
}
|
|
2263
2309
|
function stop() {
|
|
@@ -2267,17 +2313,17 @@ function createTokenBatcher(dispatch, type) {
|
|
|
2267
2313
|
timer = null;
|
|
2268
2314
|
}
|
|
2269
2315
|
}
|
|
2270
|
-
function
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
clearInterval(timer);
|
|
2277
|
-
timer = null;
|
|
2316
|
+
function queue(key, action) {
|
|
2317
|
+
if (action.type === "APPEND_CONTENT" || action.type === "APPEND_THOUGHT") {
|
|
2318
|
+
const existing = pendingActions.get(key);
|
|
2319
|
+
if (existing) {
|
|
2320
|
+
action = { ...action, text: existing.text + action.text };
|
|
2321
|
+
}
|
|
2278
2322
|
}
|
|
2323
|
+
pendingActions.set(key, action);
|
|
2324
|
+
start();
|
|
2279
2325
|
}
|
|
2280
|
-
return {
|
|
2326
|
+
return { queue, stop, flush };
|
|
2281
2327
|
}
|
|
2282
2328
|
function extractCodeFromArgs(name, args) {
|
|
2283
2329
|
const field = name === "write-file" ? "content" : "new_string";
|
|
@@ -2297,98 +2343,84 @@ function registerConfirmToolId(toolName, id) {
|
|
|
2297
2343
|
activeToolIds.set(toolName, id);
|
|
2298
2344
|
}
|
|
2299
2345
|
function createBridgeCallbacks(dispatch) {
|
|
2300
|
-
const
|
|
2301
|
-
const thoughtBatcher = createTokenBatcher(dispatch, "APPEND_THOUGHT");
|
|
2346
|
+
const batcher = createActionBatcher(dispatch);
|
|
2302
2347
|
let inThink = false;
|
|
2303
2348
|
let tagBuffer = "";
|
|
2304
2349
|
activeToolIds = /* @__PURE__ */ new Map();
|
|
2305
2350
|
streamingToolIds = /* @__PURE__ */ new Map();
|
|
2306
|
-
|
|
2351
|
+
lastStreamingValues = /* @__PURE__ */ new Map();
|
|
2307
2352
|
toolCallCounter = 0;
|
|
2308
|
-
let streamingThrottleTimer = null;
|
|
2309
|
-
let pendingStreamingUpdate = null;
|
|
2310
|
-
function flushStreamingUpdate() {
|
|
2311
|
-
if (pendingStreamingUpdate) {
|
|
2312
|
-
pendingStreamingUpdate();
|
|
2313
|
-
pendingStreamingUpdate = null;
|
|
2314
|
-
}
|
|
2315
|
-
if (streamingThrottleTimer) {
|
|
2316
|
-
clearTimeout(streamingThrottleTimer);
|
|
2317
|
-
streamingThrottleTimer = null;
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
2353
|
return {
|
|
2321
2354
|
onContent: (text) => {
|
|
2355
|
+
let contentAcc = "";
|
|
2356
|
+
let thoughtAcc = "";
|
|
2322
2357
|
for (let i = 0; i < text.length; i++) {
|
|
2323
2358
|
const ch = text[i];
|
|
2324
2359
|
if (tagBuffer.length > 0 || ch === "<") {
|
|
2325
2360
|
tagBuffer += ch;
|
|
2326
2361
|
if (tagBuffer === "<think>") {
|
|
2327
|
-
|
|
2362
|
+
if (contentAcc) batcher.queue("content", { type: "APPEND_CONTENT", text: contentAcc });
|
|
2363
|
+
contentAcc = "";
|
|
2364
|
+
batcher.flush();
|
|
2328
2365
|
inThink = true;
|
|
2329
2366
|
tagBuffer = "";
|
|
2330
2367
|
continue;
|
|
2331
2368
|
} else if (tagBuffer === "</think>") {
|
|
2332
|
-
|
|
2369
|
+
if (thoughtAcc) batcher.queue("thought", { type: "APPEND_THOUGHT", text: thoughtAcc });
|
|
2370
|
+
thoughtAcc = "";
|
|
2371
|
+
batcher.flush();
|
|
2333
2372
|
inThink = false;
|
|
2334
2373
|
tagBuffer = "";
|
|
2335
2374
|
continue;
|
|
2336
2375
|
} else if (!"<think>".startsWith(tagBuffer) && !"</think>".startsWith(tagBuffer)) {
|
|
2337
|
-
if (inThink)
|
|
2338
|
-
|
|
2339
|
-
} else {
|
|
2340
|
-
contentBatcher.append(tagBuffer);
|
|
2341
|
-
}
|
|
2376
|
+
if (inThink) thoughtAcc += tagBuffer;
|
|
2377
|
+
else contentAcc += tagBuffer;
|
|
2342
2378
|
tagBuffer = "";
|
|
2343
2379
|
}
|
|
2344
2380
|
continue;
|
|
2345
2381
|
}
|
|
2346
|
-
if (inThink)
|
|
2347
|
-
|
|
2348
|
-
} else {
|
|
2349
|
-
contentBatcher.append(ch);
|
|
2350
|
-
}
|
|
2382
|
+
if (inThink) thoughtAcc += ch;
|
|
2383
|
+
else contentAcc += ch;
|
|
2351
2384
|
}
|
|
2385
|
+
if (thoughtAcc) batcher.queue("thought", { type: "APPEND_THOUGHT", text: thoughtAcc });
|
|
2386
|
+
if (contentAcc) batcher.queue("content", { type: "APPEND_CONTENT", text: contentAcc });
|
|
2352
2387
|
},
|
|
2353
2388
|
onToolCallStreaming: (index, name, accumulatedArgs) => {
|
|
2354
2389
|
if (!streamingToolIds.has(index)) {
|
|
2355
|
-
|
|
2356
|
-
thoughtBatcher.flush();
|
|
2390
|
+
batcher.flush();
|
|
2357
2391
|
const id2 = `tool-${++toolCallCounter}`;
|
|
2358
2392
|
streamingToolIds.set(index, id2);
|
|
2359
2393
|
activeToolIds.set(name, id2);
|
|
2360
|
-
|
|
2394
|
+
lastStreamingValues.set(id2, "0");
|
|
2395
|
+
batcher.queue(`tool-${id2}`, { type: "TOOL_STREAMING", id: id2, name, streamingContent: "0" });
|
|
2361
2396
|
}
|
|
2362
2397
|
const id = streamingToolIds.get(index);
|
|
2363
|
-
lastStreamingArgs.set(id, accumulatedArgs);
|
|
2364
2398
|
const lineCount = (accumulatedArgs.match(/\\n/g) || []).length;
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
streamingThrottleTimer = setTimeout(() => {
|
|
2370
|
-
flushStreamingUpdate();
|
|
2371
|
-
}, 80);
|
|
2399
|
+
const streamingContent = String(lineCount);
|
|
2400
|
+
if (lastStreamingValues.get(id) !== streamingContent) {
|
|
2401
|
+
lastStreamingValues.set(id, streamingContent);
|
|
2402
|
+
progressStore.update({ name, progress: `${streamingContent} lines` });
|
|
2372
2403
|
}
|
|
2373
2404
|
},
|
|
2374
2405
|
onToolExecuting: (name, params) => {
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
thoughtBatcher.flush();
|
|
2378
|
-
contentBatcher.pause();
|
|
2379
|
-
thoughtBatcher.pause();
|
|
2406
|
+
progressStore.update(void 0);
|
|
2407
|
+
batcher.flush();
|
|
2380
2408
|
const existingId = activeToolIds.get(name);
|
|
2381
2409
|
const id = existingId || `tool-${++toolCallCounter}`;
|
|
2382
2410
|
activeToolIds.set(name, id);
|
|
2411
|
+
lastStreamingValues.set(id, JSON.stringify(params));
|
|
2383
2412
|
dispatch({ type: "TOOL_EXECUTING", id, name, params });
|
|
2384
2413
|
},
|
|
2385
2414
|
onToolResult: (name, result, truncated) => {
|
|
2415
|
+
progressStore.update(void 0);
|
|
2416
|
+
batcher.flush();
|
|
2386
2417
|
const id = activeToolIds.get(name) || `tool-${++toolCallCounter}`;
|
|
2387
2418
|
const lines = result.split("\n");
|
|
2388
2419
|
const isWriteTool = name === "write-file" || name === "edit-file";
|
|
2389
2420
|
let summary;
|
|
2390
2421
|
if (isWriteTool) {
|
|
2391
|
-
const
|
|
2422
|
+
const stored = lastStreamingValues.get(id) || "";
|
|
2423
|
+
const code = extractCodeFromArgs(name, stored);
|
|
2392
2424
|
const codeLines = code ? code.split("\n").length : 0;
|
|
2393
2425
|
summary = codeLines > 0 ? `${codeLines} lines` : truncated ? "truncated" : `${lines.length} lines`;
|
|
2394
2426
|
} else {
|
|
@@ -2399,31 +2431,119 @@ function createBridgeCallbacks(dispatch) {
|
|
|
2399
2431
|
dispatch({ type: "TOOL_RESULT", id, resultSummary: summary, resultContent });
|
|
2400
2432
|
},
|
|
2401
2433
|
onDenied: (toolName, feedback) => {
|
|
2434
|
+
batcher.flush();
|
|
2402
2435
|
const id = activeToolIds.get(toolName) || `tool-${++toolCallCounter}`;
|
|
2403
2436
|
dispatch({ type: "TOOL_DENIED", id, feedback });
|
|
2404
2437
|
},
|
|
2405
2438
|
onError: (err) => {
|
|
2406
|
-
|
|
2407
|
-
thoughtBatcher.stop();
|
|
2439
|
+
batcher.stop();
|
|
2408
2440
|
dispatch({ type: "SET_ERROR", error: err.message });
|
|
2409
2441
|
},
|
|
2410
2442
|
_stopBatcher: () => {
|
|
2411
|
-
|
|
2412
|
-
thoughtBatcher.stop();
|
|
2443
|
+
batcher.stop();
|
|
2413
2444
|
}
|
|
2414
2445
|
};
|
|
2415
2446
|
}
|
|
2416
|
-
var
|
|
2447
|
+
var ANSI_GRAY, ANSI_RESET, toolCallCounter, activeToolIds, streamingToolIds, lastStreamingValues;
|
|
2417
2448
|
var init_bridge = __esm({
|
|
2418
2449
|
"src/cli/tui/bridge.ts"() {
|
|
2419
2450
|
"use strict";
|
|
2420
|
-
|
|
2451
|
+
init_progressStore();
|
|
2421
2452
|
ANSI_GRAY = "\x1B[90m";
|
|
2422
2453
|
ANSI_RESET = "\x1B[0m";
|
|
2423
2454
|
toolCallCounter = 0;
|
|
2424
2455
|
activeToolIds = /* @__PURE__ */ new Map();
|
|
2425
2456
|
streamingToolIds = /* @__PURE__ */ new Map();
|
|
2426
|
-
|
|
2457
|
+
lastStreamingValues = /* @__PURE__ */ new Map();
|
|
2458
|
+
}
|
|
2459
|
+
});
|
|
2460
|
+
|
|
2461
|
+
// src/cli/ui.ts
|
|
2462
|
+
import chalk2 from "chalk";
|
|
2463
|
+
import ora from "ora";
|
|
2464
|
+
import { Marked } from "marked";
|
|
2465
|
+
import * as _markedTerminal from "marked-terminal";
|
|
2466
|
+
import { createTwoFilesPatch } from "diff";
|
|
2467
|
+
function renderMarkdown(text) {
|
|
2468
|
+
const rendered = marked.parse(text);
|
|
2469
|
+
return rendered.replace(/\n+$/, "");
|
|
2470
|
+
}
|
|
2471
|
+
function printStream(text) {
|
|
2472
|
+
process.stdout.write(text);
|
|
2473
|
+
}
|
|
2474
|
+
function printToolCall(toolName, params) {
|
|
2475
|
+
let detail = "";
|
|
2476
|
+
if (toolName === "bash" && params["command"]) {
|
|
2477
|
+
detail = ` ${chalk2.dim(String(params["command"]).slice(0, 80))}`;
|
|
2478
|
+
} else if ((toolName === "read-file" || toolName === "write-file" || toolName === "edit-file") && params["path"]) {
|
|
2479
|
+
detail = ` ${chalk2.dim(String(params["path"]))}`;
|
|
2480
|
+
} else if (toolName === "glob" && params["pattern"]) {
|
|
2481
|
+
detail = ` ${chalk2.dim(String(params["pattern"]))}`;
|
|
2482
|
+
} else if (toolName === "grep" && params["pattern"]) {
|
|
2483
|
+
detail = ` ${chalk2.dim(String(params["pattern"]))}`;
|
|
2484
|
+
} else if (toolName === "spawn-agents" && params["tasks"]) {
|
|
2485
|
+
const tasks = params["tasks"];
|
|
2486
|
+
detail = ` ${chalk2.dim(`${tasks.length} \u4E2A\u5E76\u884C\u4EFB\u52A1`)}`;
|
|
2487
|
+
} else if (toolName === "todo" && params["action"]) {
|
|
2488
|
+
const action = String(params["action"]);
|
|
2489
|
+
const id = params["id"] ? ` [${params["id"]}]` : "";
|
|
2490
|
+
detail = ` ${chalk2.dim(`${action}${id}`)}`;
|
|
2491
|
+
}
|
|
2492
|
+
const icon = toolName === "spawn-agents" ? ">>" : toolName === "todo" ? "#" : ">";
|
|
2493
|
+
console.log(chalk2.yellow(` ${icon} ${toolName}`) + detail);
|
|
2494
|
+
}
|
|
2495
|
+
function printToolResult(toolName, result, truncated) {
|
|
2496
|
+
if (truncated) {
|
|
2497
|
+
console.log(chalk2.dim(` \u2713 ${toolName} (\u8F93\u51FA\u5DF2\u622A\u65AD)`));
|
|
2498
|
+
} else {
|
|
2499
|
+
const lines = result.split("\n").length;
|
|
2500
|
+
console.log(chalk2.dim(` \u2713 ${toolName} (${lines} \u884C)`));
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
function printError(message) {
|
|
2504
|
+
console.error(chalk2.red(`\u2717 ${message}`));
|
|
2505
|
+
}
|
|
2506
|
+
function printInfo(message) {
|
|
2507
|
+
console.log(chalk2.cyan(`\u2139 ${message}`));
|
|
2508
|
+
}
|
|
2509
|
+
function printWarning(message) {
|
|
2510
|
+
console.log(chalk2.yellow(`\u26A0 ${message}`));
|
|
2511
|
+
}
|
|
2512
|
+
function printSuccess(message) {
|
|
2513
|
+
console.log(chalk2.green(`\u2713 ${message}`));
|
|
2514
|
+
}
|
|
2515
|
+
function printWelcome(modelName) {
|
|
2516
|
+
console.log(chalk2.bold.cyan("\n ZenCode") + chalk2.dim(" - \u6781\u7B80 AI \u7F16\u7A0B\u52A9\u624B\n"));
|
|
2517
|
+
console.log(chalk2.dim(` \u6A21\u578B: ${modelName}`));
|
|
2518
|
+
console.log(chalk2.dim(` \u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u9000\u51FA
|
|
2519
|
+
`));
|
|
2520
|
+
}
|
|
2521
|
+
var markedTerminal2, marked;
|
|
2522
|
+
var init_ui = __esm({
|
|
2523
|
+
"src/cli/ui.ts"() {
|
|
2524
|
+
"use strict";
|
|
2525
|
+
markedTerminal2 = _markedTerminal.markedTerminal;
|
|
2526
|
+
marked = new Marked(markedTerminal2({
|
|
2527
|
+
reflowText: false,
|
|
2528
|
+
code: chalk2.cyan,
|
|
2529
|
+
codespan: chalk2.yellow,
|
|
2530
|
+
heading: chalk2.bold.magenta,
|
|
2531
|
+
hr: () => chalk2.dim("\u2500".repeat(Math.max(0, (process.stdout.columns || 80) - 12))),
|
|
2532
|
+
strong: chalk2.bold,
|
|
2533
|
+
em: chalk2.italic,
|
|
2534
|
+
link: chalk2.blue,
|
|
2535
|
+
href: chalk2.blue.underline
|
|
2536
|
+
}));
|
|
2537
|
+
marked.use({
|
|
2538
|
+
renderer: {
|
|
2539
|
+
text(token) {
|
|
2540
|
+
if (typeof token === "object" && token.tokens) {
|
|
2541
|
+
return this.parser.parseInline(token.tokens);
|
|
2542
|
+
}
|
|
2543
|
+
return typeof token === "string" ? token : token.text;
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
});
|
|
2427
2547
|
}
|
|
2428
2548
|
});
|
|
2429
2549
|
|
|
@@ -2501,19 +2621,26 @@ function updateLastAssistant(messages, updater) {
|
|
|
2501
2621
|
const result = [...messages];
|
|
2502
2622
|
for (let i = result.length - 1; i >= 0; i--) {
|
|
2503
2623
|
if (result[i].role === "assistant") {
|
|
2504
|
-
|
|
2624
|
+
const updated = updater(result[i]);
|
|
2625
|
+
if (updated === result[i]) return messages;
|
|
2626
|
+
result[i] = updated;
|
|
2505
2627
|
return result;
|
|
2506
2628
|
}
|
|
2507
2629
|
}
|
|
2508
2630
|
return result;
|
|
2509
2631
|
}
|
|
2510
2632
|
function updateToolInBlocks(blocks, toolId, updater) {
|
|
2511
|
-
|
|
2633
|
+
let changed = false;
|
|
2634
|
+
const newBlocks = blocks.map((b) => {
|
|
2512
2635
|
if (b.type === "tool" && b.toolCall.id === toolId) {
|
|
2513
|
-
|
|
2636
|
+
const updatedTc = updater(b.toolCall);
|
|
2637
|
+
if (updatedTc === b.toolCall) return b;
|
|
2638
|
+
changed = true;
|
|
2639
|
+
return { type: "tool", toolCall: updatedTc };
|
|
2514
2640
|
}
|
|
2515
2641
|
return b;
|
|
2516
2642
|
});
|
|
2643
|
+
return changed ? newBlocks : blocks;
|
|
2517
2644
|
}
|
|
2518
2645
|
function tuiReducer(state, action) {
|
|
2519
2646
|
switch (action.type) {
|
|
@@ -2545,186 +2672,190 @@ function tuiReducer(state, action) {
|
|
|
2545
2672
|
]
|
|
2546
2673
|
};
|
|
2547
2674
|
case "APPEND_CONTENT": {
|
|
2548
|
-
return
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
};
|
|
2675
|
+
if (!action.text) return state;
|
|
2676
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2677
|
+
const blocks = [...msg.blocks];
|
|
2678
|
+
const last = blocks[blocks.length - 1];
|
|
2679
|
+
if (last && last.type === "text") {
|
|
2680
|
+
blocks[blocks.length - 1] = { type: "text", text: last.text + action.text };
|
|
2681
|
+
} else {
|
|
2682
|
+
blocks.push({ type: "text", text: action.text });
|
|
2683
|
+
}
|
|
2684
|
+
return { ...msg, blocks };
|
|
2685
|
+
});
|
|
2686
|
+
if (newMessages2 === state.messages) return state;
|
|
2687
|
+
return { ...state, messages: newMessages2 };
|
|
2561
2688
|
}
|
|
2562
2689
|
case "APPEND_THOUGHT": {
|
|
2563
|
-
return
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
};
|
|
2690
|
+
if (!action.text) return state;
|
|
2691
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2692
|
+
const blocks = [...msg.blocks];
|
|
2693
|
+
const last = blocks[blocks.length - 1];
|
|
2694
|
+
if (last && last.type === "thought") {
|
|
2695
|
+
blocks[blocks.length - 1] = { type: "thought", text: last.text + action.text };
|
|
2696
|
+
} else {
|
|
2697
|
+
blocks.push({ type: "thought", text: action.text });
|
|
2698
|
+
}
|
|
2699
|
+
return { ...msg, blocks };
|
|
2700
|
+
});
|
|
2701
|
+
if (newMessages2 === state.messages) return state;
|
|
2702
|
+
return { ...state, messages: newMessages2 };
|
|
2576
2703
|
}
|
|
2577
2704
|
case "TOOL_EXECUTING": {
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
)
|
|
2584
|
-
|
|
2585
|
-
return {
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
id: action.id,
|
|
2602
|
-
name: action.name,
|
|
2603
|
-
params: action.params,
|
|
2604
|
-
status: "running"
|
|
2605
|
-
}
|
|
2705
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2706
|
+
const existingIdx = msg.blocks.findIndex(
|
|
2707
|
+
(b) => b.type === "tool" && b.toolCall.id === action.id
|
|
2708
|
+
);
|
|
2709
|
+
if (existingIdx >= 0) {
|
|
2710
|
+
const newBlocks = updateToolInBlocks(msg.blocks, action.id, (tc) => {
|
|
2711
|
+
if (tc.status === "running" && JSON.stringify(tc.params) === JSON.stringify(action.params)) return tc;
|
|
2712
|
+
return { ...tc, status: "running", params: action.params };
|
|
2713
|
+
});
|
|
2714
|
+
if (newBlocks === msg.blocks) return msg;
|
|
2715
|
+
return { ...msg, blocks: newBlocks };
|
|
2716
|
+
}
|
|
2717
|
+
return {
|
|
2718
|
+
...msg,
|
|
2719
|
+
blocks: [
|
|
2720
|
+
...msg.blocks,
|
|
2721
|
+
{
|
|
2722
|
+
type: "tool",
|
|
2723
|
+
toolCall: {
|
|
2724
|
+
id: action.id,
|
|
2725
|
+
name: action.name,
|
|
2726
|
+
params: action.params,
|
|
2727
|
+
status: "running"
|
|
2606
2728
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
}
|
|
2610
|
-
};
|
|
2729
|
+
}
|
|
2730
|
+
]
|
|
2731
|
+
};
|
|
2732
|
+
});
|
|
2733
|
+
if (newMessages2 === state.messages) return state;
|
|
2734
|
+
return { ...state, messages: newMessages2 };
|
|
2611
2735
|
}
|
|
2612
2736
|
case "TOOL_STREAMING": {
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
blocks: updateToolInBlocks(msg.blocks, action.id, (tc) => ({
|
|
2623
|
-
...tc,
|
|
2624
|
-
streamingContent: action.streamingContent
|
|
2625
|
-
}))
|
|
2626
|
-
};
|
|
2627
|
-
}
|
|
2737
|
+
const { id, streamingContent, name } = action;
|
|
2738
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2739
|
+
const existingBlock = msg.blocks.find(
|
|
2740
|
+
(b) => b.type === "tool" && b.toolCall.id === id
|
|
2741
|
+
);
|
|
2742
|
+
if (existingBlock && existingBlock.type === "tool" && existingBlock.toolCall.streamingContent === streamingContent) {
|
|
2743
|
+
return msg;
|
|
2744
|
+
}
|
|
2745
|
+
if (existingBlock) {
|
|
2628
2746
|
return {
|
|
2629
2747
|
...msg,
|
|
2630
|
-
blocks:
|
|
2631
|
-
...
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
toolCall: {
|
|
2635
|
-
id: action.id,
|
|
2636
|
-
name: action.name,
|
|
2637
|
-
params: {},
|
|
2638
|
-
status: "running",
|
|
2639
|
-
streamingContent: action.streamingContent
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
|
-
]
|
|
2748
|
+
blocks: updateToolInBlocks(msg.blocks, id, (tc) => ({
|
|
2749
|
+
...tc,
|
|
2750
|
+
streamingContent
|
|
2751
|
+
}))
|
|
2643
2752
|
};
|
|
2644
|
-
}
|
|
2645
|
-
|
|
2646
|
-
}
|
|
2647
|
-
case "TOOL_RESULT": {
|
|
2648
|
-
return {
|
|
2649
|
-
...state,
|
|
2650
|
-
messages: updateLastAssistant(state.messages, (msg) => ({
|
|
2651
|
-
...msg,
|
|
2652
|
-
blocks: updateToolInBlocks(msg.blocks, action.id, (tc) => ({
|
|
2653
|
-
...tc,
|
|
2654
|
-
status: "done",
|
|
2655
|
-
resultSummary: action.resultSummary,
|
|
2656
|
-
resultContent: action.resultContent
|
|
2657
|
-
}))
|
|
2658
|
-
}))
|
|
2659
|
-
};
|
|
2660
|
-
}
|
|
2661
|
-
case "TOOL_DENIED": {
|
|
2662
|
-
return {
|
|
2663
|
-
...state,
|
|
2664
|
-
messages: updateLastAssistant(state.messages, (msg) => ({
|
|
2665
|
-
...msg,
|
|
2666
|
-
blocks: updateToolInBlocks(msg.blocks, action.id, (tc) => ({
|
|
2667
|
-
...tc,
|
|
2668
|
-
status: "denied",
|
|
2669
|
-
denyFeedback: action.feedback
|
|
2670
|
-
}))
|
|
2671
|
-
}))
|
|
2672
|
-
};
|
|
2673
|
-
}
|
|
2674
|
-
case "TOOL_CONFIRMING": {
|
|
2675
|
-
return {
|
|
2676
|
-
...state,
|
|
2677
|
-
messages: updateLastAssistant(state.messages, (msg) => ({
|
|
2753
|
+
}
|
|
2754
|
+
return {
|
|
2678
2755
|
...msg,
|
|
2679
2756
|
blocks: [
|
|
2680
2757
|
...msg.blocks,
|
|
2681
2758
|
{
|
|
2682
2759
|
type: "tool",
|
|
2683
2760
|
toolCall: {
|
|
2684
|
-
id
|
|
2685
|
-
name
|
|
2686
|
-
params:
|
|
2687
|
-
status: "
|
|
2761
|
+
id,
|
|
2762
|
+
name,
|
|
2763
|
+
params: {},
|
|
2764
|
+
status: "running",
|
|
2765
|
+
streamingContent
|
|
2688
2766
|
}
|
|
2689
2767
|
}
|
|
2690
|
-
]
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2768
|
+
]
|
|
2769
|
+
};
|
|
2770
|
+
});
|
|
2771
|
+
if (newMessages2 === state.messages) {
|
|
2772
|
+
return state;
|
|
2773
|
+
}
|
|
2774
|
+
return { ...state, messages: newMessages2 };
|
|
2775
|
+
}
|
|
2776
|
+
case "TOOL_RESULT": {
|
|
2777
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2778
|
+
const newBlocks = updateToolInBlocks(msg.blocks, action.id, (tc) => {
|
|
2779
|
+
if (tc.status === "done" && tc.resultSummary === action.resultSummary) return tc;
|
|
2780
|
+
return { ...tc, status: "done", resultSummary: action.resultSummary, resultContent: action.resultContent };
|
|
2781
|
+
});
|
|
2782
|
+
if (newBlocks === msg.blocks) return msg;
|
|
2783
|
+
return { ...msg, blocks: newBlocks };
|
|
2784
|
+
});
|
|
2785
|
+
if (newMessages2 === state.messages) return state;
|
|
2786
|
+
return { ...state, messages: newMessages2 };
|
|
2787
|
+
}
|
|
2788
|
+
case "TOOL_DENIED": {
|
|
2789
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2790
|
+
const newBlocks = updateToolInBlocks(msg.blocks, action.id, (tc) => ({
|
|
2791
|
+
...tc,
|
|
2792
|
+
status: "denied",
|
|
2793
|
+
denyFeedback: action.feedback
|
|
2794
|
+
}));
|
|
2795
|
+
if (newBlocks === msg.blocks) return msg;
|
|
2796
|
+
return { ...msg, blocks: newBlocks };
|
|
2797
|
+
});
|
|
2798
|
+
if (newMessages2 === state.messages) return state;
|
|
2799
|
+
return { ...state, messages: newMessages2 };
|
|
2800
|
+
}
|
|
2801
|
+
case "TOOL_CONFIRMING": {
|
|
2802
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => ({
|
|
2803
|
+
...msg,
|
|
2804
|
+
blocks: [
|
|
2805
|
+
...msg.blocks,
|
|
2806
|
+
{
|
|
2807
|
+
type: "tool",
|
|
2808
|
+
toolCall: {
|
|
2809
|
+
id: action.id,
|
|
2810
|
+
name: action.name,
|
|
2811
|
+
params: action.params,
|
|
2812
|
+
status: "confirming"
|
|
2813
|
+
}
|
|
2695
2814
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2815
|
+
],
|
|
2816
|
+
confirmPending: {
|
|
2817
|
+
toolName: action.name,
|
|
2818
|
+
params: action.params,
|
|
2819
|
+
resolve: action.resolve
|
|
2820
|
+
}
|
|
2821
|
+
}));
|
|
2822
|
+
return { ...state, messages: newMessages2 };
|
|
2698
2823
|
}
|
|
2699
2824
|
case "CONFIRM_RESPONDED": {
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
};
|
|
2825
|
+
const newMessages2 = updateLastAssistant(state.messages, (msg) => {
|
|
2826
|
+
if (!msg.confirmPending) return msg;
|
|
2827
|
+
return { ...msg, confirmPending: void 0 };
|
|
2828
|
+
});
|
|
2829
|
+
if (newMessages2 === state.messages) return state;
|
|
2830
|
+
return { ...state, messages: newMessages2 };
|
|
2707
2831
|
}
|
|
2708
2832
|
case "FINISH_STREAMING":
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
};
|
|
2833
|
+
const newMessages = updateLastAssistant(state.messages, (msg) => {
|
|
2834
|
+
if (!msg.isStreaming) return msg;
|
|
2835
|
+
return { ...msg, isStreaming: false };
|
|
2836
|
+
});
|
|
2837
|
+
if (newMessages === state.messages) return state;
|
|
2838
|
+
return { ...state, messages: newMessages };
|
|
2716
2839
|
case "SET_RUNNING":
|
|
2840
|
+
if (state.isRunning === action.running) return state;
|
|
2717
2841
|
return { ...state, isRunning: action.running };
|
|
2718
2842
|
case "SET_ERROR":
|
|
2719
2843
|
return { ...state, error: action.error, isRunning: false };
|
|
2720
2844
|
case "CLEAR_ERROR":
|
|
2845
|
+
if (state.error === void 0) return state;
|
|
2721
2846
|
return { ...state, error: void 0 };
|
|
2722
2847
|
case "CLEAR_MESSAGES":
|
|
2848
|
+
if (state.messages.length === 0) return state;
|
|
2723
2849
|
return { ...state, messages: [] };
|
|
2724
2850
|
case "SET_TODO_PLAN":
|
|
2851
|
+
if (state.todoPlan === action.plan) return state;
|
|
2725
2852
|
return { ...state, todoPlan: action.plan };
|
|
2726
2853
|
case "SET_SUB_AGENT_PROGRESS":
|
|
2854
|
+
if (JSON.stringify(state.subAgentProgress) === JSON.stringify(action.progress)) return state;
|
|
2727
2855
|
return { ...state, subAgentProgress: action.progress };
|
|
2856
|
+
case "BATCH":
|
|
2857
|
+
const newState = action.actions.reduce((s, a) => tuiReducer(s, a), state);
|
|
2858
|
+
return newState === state ? state : newState;
|
|
2728
2859
|
default:
|
|
2729
2860
|
return state;
|
|
2730
2861
|
}
|
|
@@ -2738,6 +2869,7 @@ var init_state = __esm({
|
|
|
2738
2869
|
});
|
|
2739
2870
|
|
|
2740
2871
|
// src/cli/tui/components/ToolCallLine.tsx
|
|
2872
|
+
import React from "react";
|
|
2741
2873
|
import { Box, Text } from "ink";
|
|
2742
2874
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2743
2875
|
function getToolParamSummary(name, params) {
|
|
@@ -2780,70 +2912,81 @@ function truncateContent(text, maxLines) {
|
|
|
2780
2912
|
}
|
|
2781
2913
|
return result;
|
|
2782
2914
|
}
|
|
2783
|
-
|
|
2784
|
-
const { name, params, status, resultContent, denyFeedback } = toolCall;
|
|
2785
|
-
const summary = getToolParamSummary(name, params);
|
|
2786
|
-
let borderColor = "#504945";
|
|
2787
|
-
let titleColor = "#fabd2f";
|
|
2788
|
-
let statusColor = "#fabd2f";
|
|
2789
|
-
let statusText = "RUNNING";
|
|
2790
|
-
if (status === "done") {
|
|
2791
|
-
borderColor = "#b8bb26";
|
|
2792
|
-
titleColor = "#b8bb26";
|
|
2793
|
-
statusColor = "#b8bb26";
|
|
2794
|
-
statusText = "DONE";
|
|
2795
|
-
} else if (status === "denied") {
|
|
2796
|
-
borderColor = "#fb4934";
|
|
2797
|
-
titleColor = "#fb4934";
|
|
2798
|
-
statusColor = "#fb4934";
|
|
2799
|
-
statusText = "DENIED";
|
|
2800
|
-
} else if (status === "confirming") {
|
|
2801
|
-
borderColor = "#fe8019";
|
|
2802
|
-
titleColor = "#fe8019";
|
|
2803
|
-
statusColor = "#fe8019";
|
|
2804
|
-
statusText = "CONFIRM";
|
|
2805
|
-
}
|
|
2806
|
-
const contentLines = resultContent ? truncateContent(resultContent, 15) : [];
|
|
2807
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, marginBottom: 1, width: "100%", children: /* @__PURE__ */ jsxs(
|
|
2808
|
-
Box,
|
|
2809
|
-
{
|
|
2810
|
-
flexDirection: "column",
|
|
2811
|
-
borderStyle: "round",
|
|
2812
|
-
borderColor,
|
|
2813
|
-
paddingX: 1,
|
|
2814
|
-
width: "100%",
|
|
2815
|
-
children: [
|
|
2816
|
-
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2817
|
-
/* @__PURE__ */ jsx(Box, { backgroundColor: statusColor, width: 9, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { color: "#282828", bold: true, children: statusText }) }),
|
|
2818
|
-
/* @__PURE__ */ jsx(Text, { color: titleColor, bold: true, children: name.toUpperCase() }),
|
|
2819
|
-
/* @__PURE__ */ jsx(Text, { color: "#ebdbb2", dimColor: true, italic: true, wrap: "truncate-end", children: summary })
|
|
2820
|
-
] }),
|
|
2821
|
-
status === "done" && contentLines.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: contentLines.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "#ebdbb2", wrap: "truncate-end", children: line }, i)) }),
|
|
2822
|
-
status === "denied" && denyFeedback && /* @__PURE__ */ jsxs(Box, { gap: 1, marginTop: 0, children: [
|
|
2823
|
-
/* @__PURE__ */ jsx(Text, { color: "#fb4934", bold: true, children: "REASON:" }),
|
|
2824
|
-
/* @__PURE__ */ jsx(Text, { color: "#ebdbb2", children: denyFeedback })
|
|
2825
|
-
] }),
|
|
2826
|
-
status === "confirming" && /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(Text, { color: "#fe8019", italic: true, children: "Waiting for your permission..." }) })
|
|
2827
|
-
]
|
|
2828
|
-
}
|
|
2829
|
-
) });
|
|
2830
|
-
}
|
|
2915
|
+
var ToolCallLine;
|
|
2831
2916
|
var init_ToolCallLine = __esm({
|
|
2832
2917
|
"src/cli/tui/components/ToolCallLine.tsx"() {
|
|
2833
2918
|
"use strict";
|
|
2919
|
+
ToolCallLine = React.memo(function ToolCallLine2({ toolCall }) {
|
|
2920
|
+
const { name, params, status, resultContent, denyFeedback } = toolCall;
|
|
2921
|
+
const summary = getToolParamSummary(name, params);
|
|
2922
|
+
let borderColor = "#504945";
|
|
2923
|
+
let titleColor = "#fabd2f";
|
|
2924
|
+
let statusColor = "#fabd2f";
|
|
2925
|
+
let statusText = "RUNNING";
|
|
2926
|
+
if (status === "done") {
|
|
2927
|
+
borderColor = "#b8bb26";
|
|
2928
|
+
titleColor = "#b8bb26";
|
|
2929
|
+
statusColor = "#b8bb26";
|
|
2930
|
+
statusText = "DONE";
|
|
2931
|
+
} else if (status === "denied") {
|
|
2932
|
+
borderColor = "#fb4934";
|
|
2933
|
+
titleColor = "#fb4934";
|
|
2934
|
+
statusColor = "#fb4934";
|
|
2935
|
+
statusText = "DENIED";
|
|
2936
|
+
} else if (status === "confirming") {
|
|
2937
|
+
borderColor = "#fe8019";
|
|
2938
|
+
titleColor = "#fe8019";
|
|
2939
|
+
statusColor = "#fe8019";
|
|
2940
|
+
statusText = "CONFIRM";
|
|
2941
|
+
}
|
|
2942
|
+
const contentLines = resultContent ? truncateContent(resultContent, 15) : [];
|
|
2943
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, marginBottom: 1, width: "100%", children: /* @__PURE__ */ jsxs(
|
|
2944
|
+
Box,
|
|
2945
|
+
{
|
|
2946
|
+
flexDirection: "column",
|
|
2947
|
+
borderStyle: "round",
|
|
2948
|
+
borderColor,
|
|
2949
|
+
paddingX: 1,
|
|
2950
|
+
width: "100%",
|
|
2951
|
+
children: [
|
|
2952
|
+
/* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
2953
|
+
/* @__PURE__ */ jsx(Box, { backgroundColor: statusColor, width: 9, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { color: "#282828", bold: true, children: statusText }) }),
|
|
2954
|
+
/* @__PURE__ */ jsx(Text, { color: titleColor, bold: true, children: name.toUpperCase() }),
|
|
2955
|
+
/* @__PURE__ */ jsx(Text, { color: "#ebdbb2", dimColor: true, italic: true, wrap: "truncate-end", children: summary })
|
|
2956
|
+
] }),
|
|
2957
|
+
status === "done" && contentLines.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: contentLines.map((line, i) => /* @__PURE__ */ jsx(Text, { color: "#ebdbb2", wrap: "truncate-end", children: line }, i)) }),
|
|
2958
|
+
status === "denied" && denyFeedback && /* @__PURE__ */ jsxs(Box, { gap: 1, marginTop: 0, children: [
|
|
2959
|
+
/* @__PURE__ */ jsx(Text, { color: "#fb4934", bold: true, children: "REASON:" }),
|
|
2960
|
+
/* @__PURE__ */ jsx(Text, { color: "#ebdbb2", children: denyFeedback })
|
|
2961
|
+
] }),
|
|
2962
|
+
status === "confirming" && /* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(Text, { color: "#fe8019", italic: true, children: "Waiting for your permission..." }) })
|
|
2963
|
+
]
|
|
2964
|
+
}
|
|
2965
|
+
) });
|
|
2966
|
+
});
|
|
2834
2967
|
}
|
|
2835
2968
|
});
|
|
2836
2969
|
|
|
2837
2970
|
// src/cli/tui/components/MessageBubble.tsx
|
|
2838
|
-
import
|
|
2839
|
-
import { Box as Box2, Text as Text2 } from "ink";
|
|
2971
|
+
import React2, { useMemo } from "react";
|
|
2972
|
+
import { Box as Box2, Text as Text2, useStdout } from "ink";
|
|
2840
2973
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2841
|
-
var MessageBubble;
|
|
2974
|
+
var MemoizedMarkdown, MemoizedThought, MessageBubble;
|
|
2842
2975
|
var init_MessageBubble = __esm({
|
|
2843
2976
|
"src/cli/tui/components/MessageBubble.tsx"() {
|
|
2844
2977
|
"use strict";
|
|
2978
|
+
init_ui();
|
|
2845
2979
|
init_ToolCallLine();
|
|
2846
|
-
|
|
2980
|
+
MemoizedMarkdown = React2.memo(({ text }) => {
|
|
2981
|
+
const { stdout } = useStdout();
|
|
2982
|
+
const rendered = useMemo(() => renderMarkdown(text), [text, stdout.columns]);
|
|
2983
|
+
return /* @__PURE__ */ jsx2(Text2, { children: rendered });
|
|
2984
|
+
});
|
|
2985
|
+
MemoizedThought = React2.memo(({ text, isStreaming }) => {
|
|
2986
|
+
const displayText = isStreaming ? text : text.trim();
|
|
2987
|
+
return /* @__PURE__ */ jsx2(Text2, { color: "#928374", italic: true, children: displayText });
|
|
2988
|
+
});
|
|
2989
|
+
MessageBubble = React2.memo(function MessageBubble2({ message }) {
|
|
2847
2990
|
const { role, blocks, isStreaming } = message;
|
|
2848
2991
|
const isUser = role === "user";
|
|
2849
2992
|
const label = isUser ? "USER" : "AI";
|
|
@@ -2860,11 +3003,11 @@ var init_MessageBubble = __esm({
|
|
|
2860
3003
|
if (block.type === "text") {
|
|
2861
3004
|
const text = block.text.trim();
|
|
2862
3005
|
if (!text && !isStreaming) return null;
|
|
2863
|
-
return /* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, marginBottom: i < blocks.length - 1 ? 1 : 0, width: "100%", children: /* @__PURE__ */ jsx2(Text2, { color: contentColor, children: text }) }, `text-${i}`);
|
|
3006
|
+
return /* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, marginBottom: i < blocks.length - 1 ? 1 : 0, width: "100%", children: isUser ? /* @__PURE__ */ jsx2(Text2, { color: contentColor, children: text }) : /* @__PURE__ */ jsx2(MemoizedMarkdown, { text }) }, `text-${i}`);
|
|
2864
3007
|
} else if (block.type === "thought") {
|
|
2865
3008
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 0, width: "100%", children: [
|
|
2866
3009
|
/* @__PURE__ */ jsx2(Box2, { gap: 1, marginBottom: 0, children: /* @__PURE__ */ jsx2(Box2, { backgroundColor: "#504945", width: 9, justifyContent: "center", children: /* @__PURE__ */ jsx2(Text2, { color: "#a89984", bold: true, children: "THINK" }) }) }),
|
|
2867
|
-
/* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, marginBottom: 0, children: /* @__PURE__ */ jsx2(
|
|
3010
|
+
/* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, marginBottom: 0, children: /* @__PURE__ */ jsx2(MemoizedThought, { text: block.text, isStreaming }) })
|
|
2868
3011
|
] }, `thought-${i}`);
|
|
2869
3012
|
} else {
|
|
2870
3013
|
return /* @__PURE__ */ jsx2(Box2, { paddingLeft: 2, width: "100%", children: /* @__PURE__ */ jsx2(ToolCallLine, { toolCall: block.toolCall }) }, block.toolCall.id);
|
|
@@ -2877,25 +3020,88 @@ var init_MessageBubble = __esm({
|
|
|
2877
3020
|
}
|
|
2878
3021
|
});
|
|
2879
3022
|
|
|
3023
|
+
// src/cli/tui/components/Header.tsx
|
|
3024
|
+
import { Box as Box3, Text as Text3, useStdout as useStdout2 } from "ink";
|
|
3025
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
3026
|
+
function Header({ modelName }) {
|
|
3027
|
+
const { stdout } = useStdout2();
|
|
3028
|
+
const logo = [
|
|
3029
|
+
" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
3030
|
+
" \u255A\u2550\u2550\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
|
|
3031
|
+
" \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 ",
|
|
3032
|
+
" \u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D ",
|
|
3033
|
+
" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
3034
|
+
" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
3035
|
+
];
|
|
3036
|
+
const width = (stdout?.columns ?? 80) - 2;
|
|
3037
|
+
return /* @__PURE__ */ jsxs3(
|
|
3038
|
+
Box3,
|
|
3039
|
+
{
|
|
3040
|
+
flexDirection: "column",
|
|
3041
|
+
width,
|
|
3042
|
+
borderStyle: "round",
|
|
3043
|
+
borderColor: "#504945",
|
|
3044
|
+
paddingX: 1,
|
|
3045
|
+
marginTop: 0,
|
|
3046
|
+
marginBottom: 1,
|
|
3047
|
+
children: [
|
|
3048
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginBottom: 1, alignItems: "center", children: logo.map((line, i) => /* @__PURE__ */ jsx3(Text3, { color: "#fe8019", bold: true, children: line }, i)) }),
|
|
3049
|
+
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: "#3c3836", paddingTop: 0, children: [
|
|
3050
|
+
/* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
|
|
3051
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "#fabd2f", children: "ZEN CODE" }),
|
|
3052
|
+
/* @__PURE__ */ jsx3(Text3, { color: "#a89984", dimColor: true, children: "v0.4.1" })
|
|
3053
|
+
] }),
|
|
3054
|
+
/* @__PURE__ */ jsx3(Text3, { color: "#83a598", bold: true, children: modelName })
|
|
3055
|
+
] })
|
|
3056
|
+
]
|
|
3057
|
+
}
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
var init_Header = __esm({
|
|
3061
|
+
"src/cli/tui/components/Header.tsx"() {
|
|
3062
|
+
"use strict";
|
|
3063
|
+
}
|
|
3064
|
+
});
|
|
3065
|
+
|
|
2880
3066
|
// src/cli/tui/components/ChatArea.tsx
|
|
2881
|
-
import
|
|
2882
|
-
import { Box as
|
|
2883
|
-
import { jsx as
|
|
2884
|
-
var ChatArea;
|
|
3067
|
+
import React3, { useMemo as useMemo2 } from "react";
|
|
3068
|
+
import { Box as Box4, Static } from "ink";
|
|
3069
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3070
|
+
var HEADER_ITEM, ChatArea;
|
|
2885
3071
|
var init_ChatArea = __esm({
|
|
2886
3072
|
"src/cli/tui/components/ChatArea.tsx"() {
|
|
2887
3073
|
"use strict";
|
|
2888
3074
|
init_MessageBubble();
|
|
2889
|
-
|
|
2890
|
-
|
|
3075
|
+
init_Header();
|
|
3076
|
+
HEADER_ITEM = { id: "static-header", isHeader: true };
|
|
3077
|
+
ChatArea = React3.memo(function ChatArea2({ messages, modelName }) {
|
|
3078
|
+
const completedMessages = messages.filter((m) => !m.isStreaming);
|
|
3079
|
+
const activeMessages = messages.filter((m) => m.isStreaming);
|
|
3080
|
+
const completedCount = completedMessages.length;
|
|
3081
|
+
const lastCompletedId = completedMessages[completedMessages.length - 1]?.id;
|
|
3082
|
+
const staticItems = useMemo2(() => [
|
|
3083
|
+
HEADER_ITEM,
|
|
3084
|
+
...completedMessages
|
|
3085
|
+
], [completedCount, lastCompletedId]);
|
|
3086
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", width: "100%", children: [
|
|
3087
|
+
/* @__PURE__ */ jsx4(Static, { items: staticItems, children: (item) => {
|
|
3088
|
+
if (item.isHeader) {
|
|
3089
|
+
return /* @__PURE__ */ jsx4(Header, { modelName }, "header");
|
|
3090
|
+
}
|
|
3091
|
+
return /* @__PURE__ */ jsx4(MessageBubble, { message: item }, item.id);
|
|
3092
|
+
} }),
|
|
3093
|
+
activeMessages.map((msg) => /* @__PURE__ */ jsx4(MessageBubble, { message: msg }, msg.id))
|
|
3094
|
+
] });
|
|
3095
|
+
}, (prev, next) => {
|
|
3096
|
+
return prev.messages === next.messages && prev.modelName === next.modelName;
|
|
2891
3097
|
});
|
|
2892
3098
|
}
|
|
2893
3099
|
});
|
|
2894
3100
|
|
|
2895
3101
|
// src/cli/tui/components/InputArea.tsx
|
|
2896
|
-
import { useRef, useState } from "react";
|
|
2897
|
-
import { Box as
|
|
2898
|
-
import {
|
|
3102
|
+
import React4, { useRef, useState } from "react";
|
|
3103
|
+
import { Box as Box5, Text as Text4, useInput, useStdout as useStdout4 } from "ink";
|
|
3104
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2899
3105
|
function CleanTextInput({
|
|
2900
3106
|
onSubmit,
|
|
2901
3107
|
placeholder,
|
|
@@ -2905,6 +3111,7 @@ function CleanTextInput({
|
|
|
2905
3111
|
const [value, setValue] = useState("");
|
|
2906
3112
|
const [cursor, setCursor] = useState(0);
|
|
2907
3113
|
const lastCtrlCAtRef = useRef(0);
|
|
3114
|
+
const pastedTextsRef = useRef([]);
|
|
2908
3115
|
useInput((input, key) => {
|
|
2909
3116
|
if (onScroll) {
|
|
2910
3117
|
if (key.pageUp || key.upArrow && key.shift) {
|
|
@@ -2921,6 +3128,7 @@ function CleanTextInput({
|
|
|
2921
3128
|
setValue("");
|
|
2922
3129
|
setCursor(0);
|
|
2923
3130
|
lastCtrlCAtRef.current = 0;
|
|
3131
|
+
pastedTextsRef.current = [];
|
|
2924
3132
|
return;
|
|
2925
3133
|
}
|
|
2926
3134
|
const now = Date.now();
|
|
@@ -2934,12 +3142,18 @@ function CleanTextInput({
|
|
|
2934
3142
|
return;
|
|
2935
3143
|
}
|
|
2936
3144
|
if (key.return) {
|
|
2937
|
-
|
|
3145
|
+
let trimmed = value.trim();
|
|
2938
3146
|
if (trimmed) {
|
|
3147
|
+
const stored = pastedTextsRef.current;
|
|
3148
|
+
trimmed = trimmed.replace(/\[pasted text#(\d+)\]/g, (_match, numStr) => {
|
|
3149
|
+
const idx = parseInt(numStr, 10) - 1;
|
|
3150
|
+
return idx >= 0 && idx < stored.length ? stored[idx] : _match;
|
|
3151
|
+
});
|
|
2939
3152
|
onSubmit(trimmed);
|
|
2940
3153
|
}
|
|
2941
3154
|
setValue("");
|
|
2942
3155
|
setCursor(0);
|
|
3156
|
+
pastedTextsRef.current = [];
|
|
2943
3157
|
return;
|
|
2944
3158
|
}
|
|
2945
3159
|
if (key.backspace || key.delete) {
|
|
@@ -2970,6 +3184,16 @@ function CleanTextInput({
|
|
|
2970
3184
|
setCursor(0);
|
|
2971
3185
|
return;
|
|
2972
3186
|
}
|
|
3187
|
+
if (input.includes("\n") || input.includes("\r")) {
|
|
3188
|
+
const cleaned = input.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim();
|
|
3189
|
+
if (cleaned.length > 0) {
|
|
3190
|
+
pastedTextsRef.current.push(cleaned);
|
|
3191
|
+
const placeholder2 = `[pasted text#${pastedTextsRef.current.length}]`;
|
|
3192
|
+
setValue((prev) => prev.slice(0, cursor) + placeholder2 + prev.slice(cursor));
|
|
3193
|
+
setCursor((prev) => prev + placeholder2.length);
|
|
3194
|
+
}
|
|
3195
|
+
return;
|
|
3196
|
+
}
|
|
2973
3197
|
if (key.ctrl || key.meta || key.escape) return;
|
|
2974
3198
|
if (!input || input.length === 0) return;
|
|
2975
3199
|
if (input.includes("\x1B") || input.includes("\0")) return;
|
|
@@ -2985,94 +3209,119 @@ function CleanTextInput({
|
|
|
2985
3209
|
setCursor((prev) => prev + input.length);
|
|
2986
3210
|
});
|
|
2987
3211
|
if (value.length === 0) {
|
|
2988
|
-
return /* @__PURE__ */
|
|
2989
|
-
/* @__PURE__ */
|
|
2990
|
-
/* @__PURE__ */
|
|
3212
|
+
return /* @__PURE__ */ jsxs5(Text4, { wrap: "wrap", children: [
|
|
3213
|
+
/* @__PURE__ */ jsx5(Text4, { inverse: true, children: " " }),
|
|
3214
|
+
/* @__PURE__ */ jsx5(Text4, { dimColor: true, children: placeholder || "" })
|
|
2991
3215
|
] });
|
|
2992
3216
|
}
|
|
2993
3217
|
const before = value.slice(0, cursor);
|
|
2994
3218
|
const at = cursor < value.length ? value[cursor] : " ";
|
|
2995
3219
|
const after = cursor < value.length ? value.slice(cursor + 1) : "";
|
|
2996
|
-
return /* @__PURE__ */
|
|
2997
|
-
|
|
2998
|
-
/* @__PURE__ */
|
|
2999
|
-
|
|
3000
|
-
] });
|
|
3001
|
-
}
|
|
3002
|
-
function InputArea({ onSubmit, isRunning, onExitRequest, onScroll }) {
|
|
3003
|
-
return /* @__PURE__ */ jsxs3(Box4, { paddingX: 0, children: [
|
|
3004
|
-
/* @__PURE__ */ jsx4(Box4, { backgroundColor: isRunning ? "#504945" : "#b8bb26", paddingX: 1, marginRight: 1, children: /* @__PURE__ */ jsx4(Text3, { color: "#282828", bold: true, children: isRunning ? " WAIT " : " INPUT " }) }),
|
|
3005
|
-
/* @__PURE__ */ jsx4(Box4, { flexGrow: 1, children: isRunning ? /* @__PURE__ */ jsx4(Box4, { flexGrow: 1, onWheel: (event) => {
|
|
3006
|
-
}, children: /* @__PURE__ */ jsx4(Text3, { color: "#a89984", italic: true, children: "Thinking..." }) }) : /* @__PURE__ */ jsx4(
|
|
3007
|
-
CleanTextInput,
|
|
3008
|
-
{
|
|
3009
|
-
onSubmit,
|
|
3010
|
-
placeholder: "Type a message or /command...",
|
|
3011
|
-
onExitRequest,
|
|
3012
|
-
onScroll
|
|
3013
|
-
}
|
|
3014
|
-
) })
|
|
3220
|
+
return /* @__PURE__ */ jsxs5(Text4, { wrap: "wrap", children: [
|
|
3221
|
+
before,
|
|
3222
|
+
/* @__PURE__ */ jsx5(Text4, { inverse: true, children: at }),
|
|
3223
|
+
after
|
|
3015
3224
|
] });
|
|
3016
3225
|
}
|
|
3226
|
+
var InputArea;
|
|
3017
3227
|
var init_InputArea = __esm({
|
|
3018
3228
|
"src/cli/tui/components/InputArea.tsx"() {
|
|
3019
3229
|
"use strict";
|
|
3230
|
+
InputArea = React4.memo(function InputArea2({ onSubmit, isRunning, onExitRequest, onScroll }) {
|
|
3231
|
+
const { stdout } = useStdout4();
|
|
3232
|
+
const labelCols = 10;
|
|
3233
|
+
const textWidth = (stdout?.columns ?? 80) - 2 - labelCols;
|
|
3234
|
+
return /* @__PURE__ */ jsxs5(Box5, { paddingX: 0, children: [
|
|
3235
|
+
/* @__PURE__ */ jsx5(Box5, { backgroundColor: isRunning ? "#504945" : "#b8bb26", paddingX: 1, marginRight: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "#282828", bold: true, children: isRunning ? " WAIT " : " INPUT " }) }),
|
|
3236
|
+
/* @__PURE__ */ jsx5(Box5, { width: textWidth, children: isRunning ? /* @__PURE__ */ jsx5(Text4, { color: "#a89984", italic: true, children: "Thinking..." }) : /* @__PURE__ */ jsx5(
|
|
3237
|
+
CleanTextInput,
|
|
3238
|
+
{
|
|
3239
|
+
onSubmit,
|
|
3240
|
+
placeholder: "Type a message or /command...",
|
|
3241
|
+
onExitRequest,
|
|
3242
|
+
onScroll
|
|
3243
|
+
}
|
|
3244
|
+
) })
|
|
3245
|
+
] });
|
|
3246
|
+
});
|
|
3020
3247
|
}
|
|
3021
3248
|
});
|
|
3022
3249
|
|
|
3023
3250
|
// src/cli/tui/components/StatusBar.tsx
|
|
3024
|
-
import {
|
|
3025
|
-
import {
|
|
3251
|
+
import React5, { useEffect, useState as useState2 } from "react";
|
|
3252
|
+
import { Box as Box6, Text as Text5 } from "ink";
|
|
3253
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3026
3254
|
function formatTokens(n) {
|
|
3027
3255
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
3028
3256
|
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
3029
3257
|
return String(n);
|
|
3030
3258
|
}
|
|
3031
|
-
|
|
3032
|
-
const todoProgress = todoPlan ? `${todoPlan.items.filter((i) => i.status === "completed").length}/${todoPlan.items.length}` : null;
|
|
3033
|
-
return /* @__PURE__ */ jsxs4(Box5, { marginTop: 1, children: [
|
|
3034
|
-
/* @__PURE__ */ jsx5(Box5, { backgroundColor: "#3c3836", paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", bold: true, children: " ZENCODE " }) }),
|
|
3035
|
-
/* @__PURE__ */ jsxs4(Box5, { backgroundColor: "#504945", paddingX: 1, flexGrow: 1, children: [
|
|
3036
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: modelName }),
|
|
3037
|
-
isRunning && !subAgentProgress && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3038
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3039
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#8ec07c", children: "\u25CF thinking..." })
|
|
3040
|
-
] }),
|
|
3041
|
-
subAgentProgress && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3042
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3043
|
-
/* @__PURE__ */ jsxs4(Text4, { color: "#b8bb26", children: [
|
|
3044
|
-
"Agents: ",
|
|
3045
|
-
subAgentProgress.completed + subAgentProgress.failed,
|
|
3046
|
-
"/",
|
|
3047
|
-
subAgentProgress.total
|
|
3048
|
-
] }),
|
|
3049
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3050
|
-
/* @__PURE__ */ jsxs4(Text4, { color: "#83a598", children: [
|
|
3051
|
-
"tokens: ",
|
|
3052
|
-
formatTokens(subAgentProgress.tokens)
|
|
3053
|
-
] })
|
|
3054
|
-
] }),
|
|
3055
|
-
todoProgress && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
3056
|
-
/* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3057
|
-
/* @__PURE__ */ jsxs4(Text4, { color: "#fabd2f", children: [
|
|
3058
|
-
"Plan: ",
|
|
3059
|
-
todoProgress
|
|
3060
|
-
] })
|
|
3061
|
-
] })
|
|
3062
|
-
] }),
|
|
3063
|
-
/* @__PURE__ */ jsx5(Box5, { backgroundColor: "#3c3836", paddingX: 1, children: /* @__PURE__ */ jsx5(Text4, { color: "#ebdbb2", children: "/help" }) })
|
|
3064
|
-
] });
|
|
3065
|
-
}
|
|
3259
|
+
var StatusBar;
|
|
3066
3260
|
var init_StatusBar = __esm({
|
|
3067
3261
|
"src/cli/tui/components/StatusBar.tsx"() {
|
|
3068
3262
|
"use strict";
|
|
3263
|
+
init_progressStore();
|
|
3264
|
+
StatusBar = React5.memo(function StatusBar2({ isRunning, modelName, todoPlan, subAgentProgress }) {
|
|
3265
|
+
const [activeStreamingTool, setActiveStreamingTool] = useState2(progressStore.get());
|
|
3266
|
+
useEffect(() => {
|
|
3267
|
+
const handleUpdate = (progress) => {
|
|
3268
|
+
setActiveStreamingTool(progress);
|
|
3269
|
+
};
|
|
3270
|
+
progressStore.on("change", handleUpdate);
|
|
3271
|
+
return () => {
|
|
3272
|
+
progressStore.off("change", handleUpdate);
|
|
3273
|
+
};
|
|
3274
|
+
}, []);
|
|
3275
|
+
const todoProgress = todoPlan ? `${todoPlan.items.filter((i) => i.status === "completed").length}/${todoPlan.items.length}` : null;
|
|
3276
|
+
return /* @__PURE__ */ jsxs6(Box6, { marginTop: 1, height: 1, width: "100%", children: [
|
|
3277
|
+
/* @__PURE__ */ jsx6(Box6, { backgroundColor: "#3c3836", paddingX: 1, flexShrink: 0, children: /* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", bold: true, children: "ZENCODE" }) }),
|
|
3278
|
+
/* @__PURE__ */ jsxs6(Box6, { backgroundColor: "#504945", paddingX: 1, flexGrow: 1, flexBasis: 0, children: [
|
|
3279
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", wrap: "truncate-end", children: modelName }),
|
|
3280
|
+
isRunning && !subAgentProgress && !activeStreamingTool && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3281
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3282
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#8ec07c", children: "\u25CF thinking..." })
|
|
3283
|
+
] }),
|
|
3284
|
+
activeStreamingTool && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3285
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3286
|
+
/* @__PURE__ */ jsxs6(Text5, { color: "#fabd2f", wrap: "truncate-end", children: [
|
|
3287
|
+
"\u25CF ",
|
|
3288
|
+
activeStreamingTool.name,
|
|
3289
|
+
": ",
|
|
3290
|
+
activeStreamingTool.progress
|
|
3291
|
+
] })
|
|
3292
|
+
] }),
|
|
3293
|
+
subAgentProgress && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3294
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3295
|
+
/* @__PURE__ */ jsxs6(Text5, { color: "#b8bb26", children: [
|
|
3296
|
+
"Agents: ",
|
|
3297
|
+
subAgentProgress.completed + subAgentProgress.failed,
|
|
3298
|
+
"/",
|
|
3299
|
+
subAgentProgress.total
|
|
3300
|
+
] }),
|
|
3301
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3302
|
+
/* @__PURE__ */ jsxs6(Text5, { color: "#83a598", children: [
|
|
3303
|
+
"tokens: ",
|
|
3304
|
+
formatTokens(subAgentProgress.tokens)
|
|
3305
|
+
] })
|
|
3306
|
+
] }),
|
|
3307
|
+
todoProgress && /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
3308
|
+
/* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: " \u2502 " }),
|
|
3309
|
+
/* @__PURE__ */ jsxs6(Text5, { color: "#fabd2f", children: [
|
|
3310
|
+
"Plan: ",
|
|
3311
|
+
todoProgress
|
|
3312
|
+
] })
|
|
3313
|
+
] })
|
|
3314
|
+
] }),
|
|
3315
|
+
/* @__PURE__ */ jsx6(Box6, { backgroundColor: "#3c3836", paddingX: 1, flexShrink: 0, children: /* @__PURE__ */ jsx6(Text5, { color: "#ebdbb2", children: "/help" }) })
|
|
3316
|
+
] });
|
|
3317
|
+
});
|
|
3069
3318
|
}
|
|
3070
3319
|
});
|
|
3071
3320
|
|
|
3072
3321
|
// src/cli/tui/components/ConfirmPrompt.tsx
|
|
3073
|
-
import { useState as
|
|
3074
|
-
import { Box as
|
|
3075
|
-
import { Fragment as
|
|
3322
|
+
import { useState as useState3 } from "react";
|
|
3323
|
+
import { Box as Box7, Text as Text6, useInput as useInput2 } from "ink";
|
|
3324
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3076
3325
|
function getToolDetails(toolName, params) {
|
|
3077
3326
|
const lines = [];
|
|
3078
3327
|
let label = toolName;
|
|
@@ -3118,8 +3367,8 @@ function getToolDetails(toolName, params) {
|
|
|
3118
3367
|
return { lines, label };
|
|
3119
3368
|
}
|
|
3120
3369
|
function FeedbackInput({ onSubmit }) {
|
|
3121
|
-
const [value, setValue] =
|
|
3122
|
-
const [cursor, setCursor] =
|
|
3370
|
+
const [value, setValue] = useState3("");
|
|
3371
|
+
const [cursor, setCursor] = useState3(0);
|
|
3123
3372
|
useInput2((input, key) => {
|
|
3124
3373
|
if (key.return) {
|
|
3125
3374
|
onSubmit(value);
|
|
@@ -3158,23 +3407,23 @@ function FeedbackInput({ onSubmit }) {
|
|
|
3158
3407
|
setCursor((prev) => prev + input.length);
|
|
3159
3408
|
});
|
|
3160
3409
|
if (value.length === 0) {
|
|
3161
|
-
return /* @__PURE__ */
|
|
3162
|
-
/* @__PURE__ */
|
|
3163
|
-
/* @__PURE__ */
|
|
3410
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
3411
|
+
/* @__PURE__ */ jsx7(Text6, { inverse: true, children: " " }),
|
|
3412
|
+
/* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "\u8F93\u5165\u53CD\u9988\u6307\u4EE4\u7ED9 AI..." })
|
|
3164
3413
|
] });
|
|
3165
3414
|
}
|
|
3166
3415
|
const before = value.slice(0, cursor);
|
|
3167
3416
|
const at = cursor < value.length ? value[cursor] : " ";
|
|
3168
3417
|
const after = cursor < value.length ? value.slice(cursor + 1) : "";
|
|
3169
|
-
return /* @__PURE__ */
|
|
3170
|
-
/* @__PURE__ */
|
|
3171
|
-
/* @__PURE__ */
|
|
3172
|
-
/* @__PURE__ */
|
|
3418
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
3419
|
+
/* @__PURE__ */ jsx7(Text6, { children: before }),
|
|
3420
|
+
/* @__PURE__ */ jsx7(Text6, { inverse: true, children: at }),
|
|
3421
|
+
/* @__PURE__ */ jsx7(Text6, { children: after })
|
|
3173
3422
|
] });
|
|
3174
3423
|
}
|
|
3175
3424
|
function ConfirmPrompt({ confirm, onRespond }) {
|
|
3176
|
-
const [selected, setSelected] =
|
|
3177
|
-
const [feedbackMode, setFeedbackMode] =
|
|
3425
|
+
const [selected, setSelected] = useState3(0);
|
|
3426
|
+
const [feedbackMode, setFeedbackMode] = useState3(false);
|
|
3178
3427
|
useInput2((input, key) => {
|
|
3179
3428
|
if (feedbackMode) return;
|
|
3180
3429
|
if (key.leftArrow) {
|
|
@@ -3197,21 +3446,21 @@ function ConfirmPrompt({ confirm, onRespond }) {
|
|
|
3197
3446
|
}, { isActive: !feedbackMode });
|
|
3198
3447
|
const { lines, label } = getToolDetails(confirm.toolName, confirm.params);
|
|
3199
3448
|
if (feedbackMode) {
|
|
3200
|
-
return /* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3202
|
-
/* @__PURE__ */
|
|
3203
|
-
|
|
3449
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 0, marginY: 0, children: [
|
|
3450
|
+
/* @__PURE__ */ jsx7(Box7, { backgroundColor: "#fe8019", paddingX: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "#282828", bold: true, children: " FEEDBACK " }) }),
|
|
3451
|
+
/* @__PURE__ */ jsxs7(
|
|
3452
|
+
Box7,
|
|
3204
3453
|
{
|
|
3205
3454
|
flexDirection: "column",
|
|
3206
3455
|
borderStyle: "round",
|
|
3207
3456
|
borderColor: "#fe8019",
|
|
3208
3457
|
paddingX: 1,
|
|
3209
3458
|
children: [
|
|
3210
|
-
/* @__PURE__ */
|
|
3211
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
3212
|
-
/* @__PURE__ */
|
|
3213
|
-
/* @__PURE__ */
|
|
3214
|
-
/* @__PURE__ */
|
|
3459
|
+
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "#fabd2f", children: label }),
|
|
3460
|
+
lines.map((line, i) => /* @__PURE__ */ jsx7(Text6, { color: "#a89984", children: line }, i)),
|
|
3461
|
+
/* @__PURE__ */ jsxs7(Box7, { marginTop: 0, gap: 1, children: [
|
|
3462
|
+
/* @__PURE__ */ jsx7(Text6, { color: "#83a598", bold: true, children: "Reason: " }),
|
|
3463
|
+
/* @__PURE__ */ jsx7(
|
|
3215
3464
|
FeedbackInput,
|
|
3216
3465
|
{
|
|
3217
3466
|
onSubmit: (text) => {
|
|
@@ -3228,29 +3477,29 @@ function ConfirmPrompt({ confirm, onRespond }) {
|
|
|
3228
3477
|
]
|
|
3229
3478
|
}
|
|
3230
3479
|
),
|
|
3231
|
-
/* @__PURE__ */
|
|
3480
|
+
/* @__PURE__ */ jsx7(Box7, { paddingX: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "Enter to send \xB7 Esc to cancel" }) })
|
|
3232
3481
|
] });
|
|
3233
3482
|
}
|
|
3234
|
-
return /* @__PURE__ */
|
|
3235
|
-
/* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3237
|
-
|
|
3483
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingX: 0, marginY: 0, children: [
|
|
3484
|
+
/* @__PURE__ */ jsx7(Box7, { backgroundColor: "#fe8019", paddingX: 1, children: /* @__PURE__ */ jsx7(Text6, { color: "#282828", bold: true, children: " CONFIRMATION REQUIRED " }) }),
|
|
3485
|
+
/* @__PURE__ */ jsxs7(
|
|
3486
|
+
Box7,
|
|
3238
3487
|
{
|
|
3239
3488
|
flexDirection: "column",
|
|
3240
3489
|
borderStyle: "round",
|
|
3241
3490
|
borderColor: "#fe8019",
|
|
3242
3491
|
paddingX: 1,
|
|
3243
3492
|
children: [
|
|
3244
|
-
/* @__PURE__ */
|
|
3245
|
-
lines.map((line, i) => /* @__PURE__ */
|
|
3246
|
-
/* @__PURE__ */
|
|
3493
|
+
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "#fabd2f", children: label }),
|
|
3494
|
+
lines.map((line, i) => /* @__PURE__ */ jsx7(Text6, { color: "#a89984", children: line }, i)),
|
|
3495
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 0, gap: 2, justifyContent: "center", children: OPTIONS.map((opt, i) => {
|
|
3247
3496
|
const isSelected = i === selected;
|
|
3248
3497
|
const optColor = opt.key === "deny" ? "#fb4934" : opt.key === "allow" ? "#b8bb26" : "#8ec07c";
|
|
3249
|
-
return /* @__PURE__ */
|
|
3498
|
+
return /* @__PURE__ */ jsx7(Box7, { children: isSelected ? /* @__PURE__ */ jsxs7(Text6, { bold: true, backgroundColor: optColor, color: "#282828", children: [
|
|
3250
3499
|
" ",
|
|
3251
3500
|
opt.label,
|
|
3252
3501
|
" "
|
|
3253
|
-
] }) : /* @__PURE__ */
|
|
3502
|
+
] }) : /* @__PURE__ */ jsxs7(Text6, { color: optColor, children: [
|
|
3254
3503
|
" ",
|
|
3255
3504
|
opt.label,
|
|
3256
3505
|
" "
|
|
@@ -3259,7 +3508,7 @@ function ConfirmPrompt({ confirm, onRespond }) {
|
|
|
3259
3508
|
]
|
|
3260
3509
|
}
|
|
3261
3510
|
),
|
|
3262
|
-
/* @__PURE__ */
|
|
3511
|
+
/* @__PURE__ */ jsx7(Box7, { paddingX: 1, children: /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "\u2190 \u2192 select \xB7 Enter confirm \xB7 y/n shortcuts \xB7 Tab feedback" }) })
|
|
3263
3512
|
] });
|
|
3264
3513
|
}
|
|
3265
3514
|
var OPTIONS;
|
|
@@ -3275,16 +3524,17 @@ var init_ConfirmPrompt = __esm({
|
|
|
3275
3524
|
});
|
|
3276
3525
|
|
|
3277
3526
|
// src/cli/tui/components/TodoPanel.tsx
|
|
3278
|
-
import
|
|
3279
|
-
import {
|
|
3527
|
+
import React7 from "react";
|
|
3528
|
+
import { Box as Box8, Text as Text7 } from "ink";
|
|
3529
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3280
3530
|
function getStatusIcon(status) {
|
|
3281
3531
|
switch (status) {
|
|
3282
3532
|
case "completed":
|
|
3283
|
-
return "
|
|
3533
|
+
return "*";
|
|
3284
3534
|
case "in-progress":
|
|
3285
|
-
return "
|
|
3535
|
+
return ">";
|
|
3286
3536
|
default:
|
|
3287
|
-
return "
|
|
3537
|
+
return " ";
|
|
3288
3538
|
}
|
|
3289
3539
|
}
|
|
3290
3540
|
function getStatusColor(status) {
|
|
@@ -3297,100 +3547,89 @@ function getStatusColor(status) {
|
|
|
3297
3547
|
return "#928374";
|
|
3298
3548
|
}
|
|
3299
3549
|
}
|
|
3300
|
-
|
|
3301
|
-
const completed = plan.items.filter((i) => i.status === "completed").length;
|
|
3302
|
-
const total = plan.items.length;
|
|
3303
|
-
return /* @__PURE__ */ jsxs6(
|
|
3304
|
-
Box7,
|
|
3305
|
-
{
|
|
3306
|
-
flexDirection: "column",
|
|
3307
|
-
borderStyle: "round",
|
|
3308
|
-
borderColor: "#83a598",
|
|
3309
|
-
paddingX: 1,
|
|
3310
|
-
marginY: 1,
|
|
3311
|
-
children: [
|
|
3312
|
-
/* @__PURE__ */ jsxs6(Box7, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
3313
|
-
/* @__PURE__ */ jsx7(Text6, { bold: true, color: "#83a598", children: "\u{1F4CB} PROJECT PLAN" }),
|
|
3314
|
-
/* @__PURE__ */ jsxs6(Text6, { color: "#ebdbb2", children: [
|
|
3315
|
-
completed,
|
|
3316
|
-
"/",
|
|
3317
|
-
total,
|
|
3318
|
-
" tasks"
|
|
3319
|
-
] })
|
|
3320
|
-
] }),
|
|
3321
|
-
plan.items.map((item) => /* @__PURE__ */ jsxs6(Box7, { gap: 1, children: [
|
|
3322
|
-
/* @__PURE__ */ jsx7(Text6, { color: getStatusColor(item.status), children: getStatusIcon(item.status) }),
|
|
3323
|
-
/* @__PURE__ */ jsx7(
|
|
3324
|
-
Text6,
|
|
3325
|
-
{
|
|
3326
|
-
color: item.status === "completed" ? "#b8bb26" : item.status === "in-progress" ? "#fabd2f" : "#ebdbb2",
|
|
3327
|
-
dimColor: item.status === "pending",
|
|
3328
|
-
strikethrough: item.status === "completed",
|
|
3329
|
-
children: item.title
|
|
3330
|
-
}
|
|
3331
|
-
)
|
|
3332
|
-
] }, item.id))
|
|
3333
|
-
]
|
|
3334
|
-
}
|
|
3335
|
-
);
|
|
3336
|
-
}
|
|
3550
|
+
var TodoPanel;
|
|
3337
3551
|
var init_TodoPanel = __esm({
|
|
3338
3552
|
"src/cli/tui/components/TodoPanel.tsx"() {
|
|
3339
3553
|
"use strict";
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3554
|
+
TodoPanel = React7.memo(function TodoPanel2({ plan }) {
|
|
3555
|
+
const completed = plan.items.filter((i) => i.status === "completed").length;
|
|
3556
|
+
const total = plan.items.length;
|
|
3557
|
+
return /* @__PURE__ */ jsxs8(
|
|
3558
|
+
Box8,
|
|
3559
|
+
{
|
|
3560
|
+
flexDirection: "column",
|
|
3561
|
+
borderStyle: "round",
|
|
3562
|
+
borderColor: "#83a598",
|
|
3563
|
+
paddingX: 1,
|
|
3564
|
+
marginY: 0,
|
|
3565
|
+
width: "100%",
|
|
3566
|
+
children: [
|
|
3567
|
+
/* @__PURE__ */ jsxs8(Box8, { justifyContent: "space-between", marginBottom: 0, children: [
|
|
3568
|
+
/* @__PURE__ */ jsx8(Text7, { bold: true, color: "#83a598", children: "PROJECT PLAN" }),
|
|
3569
|
+
/* @__PURE__ */ jsxs8(Text7, { color: "#ebdbb2", children: [
|
|
3570
|
+
completed,
|
|
3571
|
+
"/",
|
|
3572
|
+
total,
|
|
3573
|
+
" tasks"
|
|
3574
|
+
] })
|
|
3575
|
+
] }),
|
|
3576
|
+
plan.items.map((item) => /* @__PURE__ */ jsxs8(Box8, { gap: 0, children: [
|
|
3577
|
+
/* @__PURE__ */ jsxs8(Text7, { color: getStatusColor(item.status), children: [
|
|
3578
|
+
"[",
|
|
3579
|
+
getStatusIcon(item.status),
|
|
3580
|
+
"]"
|
|
3581
|
+
] }),
|
|
3582
|
+
/* @__PURE__ */ jsx8(Text7, { children: " " }),
|
|
3583
|
+
/* @__PURE__ */ jsx8(
|
|
3584
|
+
Text7,
|
|
3585
|
+
{
|
|
3586
|
+
color: item.status === "completed" ? "#b8bb26" : item.status === "in-progress" ? "#fabd2f" : "#ebdbb2",
|
|
3587
|
+
dimColor: item.status === "pending",
|
|
3588
|
+
strikethrough: item.status === "completed",
|
|
3589
|
+
children: item.title
|
|
3590
|
+
}
|
|
3591
|
+
)
|
|
3592
|
+
] }, item.id))
|
|
3593
|
+
]
|
|
3594
|
+
}
|
|
3595
|
+
);
|
|
3596
|
+
}, (prev, next) => {
|
|
3597
|
+
return prev.plan === next.plan;
|
|
3598
|
+
});
|
|
3370
3599
|
}
|
|
3371
3600
|
});
|
|
3372
3601
|
|
|
3373
3602
|
// src/cli/tui/App.tsx
|
|
3374
|
-
import { useReducer, useCallback, useEffect, useRef as useRef2, useState as
|
|
3375
|
-
import { Box as Box9, Text as Text8, useInput as useInput3, useStdout } from "ink";
|
|
3376
|
-
import { jsx as jsx9, jsxs as
|
|
3603
|
+
import { useReducer, useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState4 } from "react";
|
|
3604
|
+
import { Box as Box9, Text as Text8, useInput as useInput3, useStdout as useStdout5 } from "ink";
|
|
3605
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3377
3606
|
function App({ config, client, agent, registry, todoStore, subAgentTracker, agentRegistry, skillRegistry }) {
|
|
3378
|
-
const { stdout } =
|
|
3379
|
-
const [,
|
|
3380
|
-
|
|
3607
|
+
const { stdout } = useStdout5();
|
|
3608
|
+
const [resetKey, setResetKey] = useState4(0);
|
|
3609
|
+
useEffect2(() => {
|
|
3610
|
+
let timer;
|
|
3611
|
+
let lastCols = stdout.columns;
|
|
3612
|
+
let lastRows = stdout.rows;
|
|
3381
3613
|
const onResize = () => {
|
|
3382
|
-
|
|
3614
|
+
if (stdout.columns === lastCols && stdout.rows === lastRows) return;
|
|
3615
|
+
lastCols = stdout.columns;
|
|
3616
|
+
lastRows = stdout.rows;
|
|
3617
|
+
clearTimeout(timer);
|
|
3618
|
+
timer = setTimeout(() => {
|
|
3619
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
3620
|
+
setResetKey((prev) => prev + 1);
|
|
3621
|
+
}, 100);
|
|
3383
3622
|
};
|
|
3384
3623
|
stdout.on("resize", onResize);
|
|
3385
3624
|
return () => {
|
|
3386
3625
|
stdout.off("resize", onResize);
|
|
3626
|
+
clearTimeout(timer);
|
|
3387
3627
|
};
|
|
3388
3628
|
}, [stdout]);
|
|
3389
3629
|
const [state, dispatch] = useReducer(
|
|
3390
3630
|
tuiReducer,
|
|
3391
3631
|
createInitialState(config.model)
|
|
3392
3632
|
);
|
|
3393
|
-
const [resetKey, setResetKey] = useState3(0);
|
|
3394
3633
|
const currentCallbacksRef = useRef2(null);
|
|
3395
3634
|
const agentRef = useRef2(agent);
|
|
3396
3635
|
const todoStoreRef = useRef2(todoStore);
|
|
@@ -3398,12 +3637,12 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3398
3637
|
agentRef.current = agent;
|
|
3399
3638
|
todoStoreRef.current = todoStore;
|
|
3400
3639
|
subAgentTrackerRef.current = subAgentTracker;
|
|
3401
|
-
|
|
3640
|
+
useEffect2(() => {
|
|
3402
3641
|
return todoStoreRef.current.subscribe((plan) => {
|
|
3403
3642
|
dispatch({ type: "SET_TODO_PLAN", plan });
|
|
3404
3643
|
});
|
|
3405
3644
|
}, []);
|
|
3406
|
-
|
|
3645
|
+
useEffect2(() => {
|
|
3407
3646
|
let timer = null;
|
|
3408
3647
|
let latest = null;
|
|
3409
3648
|
const unsub = subAgentTrackerRef.current.subscribe((progress) => {
|
|
@@ -3433,7 +3672,7 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3433
3672
|
(found, msg) => found || msg.confirmPending,
|
|
3434
3673
|
void 0
|
|
3435
3674
|
);
|
|
3436
|
-
|
|
3675
|
+
useEffect2(() => {
|
|
3437
3676
|
setStructuredConfirmHandler((toolName, params) => {
|
|
3438
3677
|
return new Promise((resolve10) => {
|
|
3439
3678
|
const id = `confirm-${Date.now()}`;
|
|
@@ -3493,7 +3732,7 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3493
3732
|
await runAgent(expandedPrompt);
|
|
3494
3733
|
return;
|
|
3495
3734
|
}
|
|
3496
|
-
|
|
3735
|
+
handleSlashCommand(text, {
|
|
3497
3736
|
config,
|
|
3498
3737
|
agent: agentRef.current,
|
|
3499
3738
|
registry,
|
|
@@ -3536,9 +3775,10 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3536
3775
|
return;
|
|
3537
3776
|
}
|
|
3538
3777
|
if (input === "c" && key.ctrl) {
|
|
3539
|
-
if (state.isRunning) {
|
|
3778
|
+
if (state.isRunning || confirmPending) {
|
|
3540
3779
|
agentRef.current.interrupt();
|
|
3541
3780
|
currentCallbacksRef.current?._stopBatcher?.();
|
|
3781
|
+
dispatch({ type: "CONFIRM_RESPONDED", id: "" });
|
|
3542
3782
|
dispatch({ type: "SET_RUNNING", running: false });
|
|
3543
3783
|
dispatch({ type: "FINISH_STREAMING" });
|
|
3544
3784
|
return;
|
|
@@ -3548,18 +3788,21 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3548
3788
|
process.exit(0);
|
|
3549
3789
|
}
|
|
3550
3790
|
});
|
|
3551
|
-
return /* @__PURE__ */
|
|
3552
|
-
/* @__PURE__ */
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3791
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, width: "100%", children: [
|
|
3792
|
+
/* @__PURE__ */ jsx9(
|
|
3793
|
+
ChatArea,
|
|
3794
|
+
{
|
|
3795
|
+
messages: state.messages,
|
|
3796
|
+
modelName: state.modelName
|
|
3797
|
+
}
|
|
3798
|
+
),
|
|
3799
|
+
state.error && /* @__PURE__ */ jsxs9(Box9, { borderStyle: "round", borderColor: "#fb4934", paddingX: 1, marginBottom: 0, children: [
|
|
3557
3800
|
/* @__PURE__ */ jsx9(Text8, { color: "#fb4934", bold: true, children: "ERROR: " }),
|
|
3558
3801
|
/* @__PURE__ */ jsx9(Text8, { color: "#fb4934", children: state.error })
|
|
3559
3802
|
] }),
|
|
3560
3803
|
confirmPending && /* @__PURE__ */ jsx9(ConfirmPrompt, { confirm: confirmPending, onRespond: handleConfirmResponse }),
|
|
3561
3804
|
state.todoPlan && /* @__PURE__ */ jsx9(TodoPanel, { plan: state.todoPlan }),
|
|
3562
|
-
/* @__PURE__ */ jsx9(Box9, { marginTop:
|
|
3805
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 0, children: /* @__PURE__ */ jsx9(
|
|
3563
3806
|
InputArea,
|
|
3564
3807
|
{
|
|
3565
3808
|
onSubmit: handleSubmit,
|
|
@@ -3567,7 +3810,7 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3567
3810
|
onExitRequest: () => process.exit(0)
|
|
3568
3811
|
}
|
|
3569
3812
|
) }),
|
|
3570
|
-
/* @__PURE__ */ jsx9(
|
|
3813
|
+
/* @__PURE__ */ jsx9(
|
|
3571
3814
|
StatusBar,
|
|
3572
3815
|
{
|
|
3573
3816
|
isRunning: state.isRunning,
|
|
@@ -3575,125 +3818,9 @@ function App({ config, client, agent, registry, todoStore, subAgentTracker, agen
|
|
|
3575
3818
|
todoPlan: state.todoPlan,
|
|
3576
3819
|
subAgentProgress: state.subAgentProgress
|
|
3577
3820
|
}
|
|
3578
|
-
)
|
|
3821
|
+
)
|
|
3579
3822
|
] }, resetKey);
|
|
3580
3823
|
}
|
|
3581
|
-
function handleSlashCommand2(input, ctx) {
|
|
3582
|
-
const { config, agent, registry, dispatch, setResetKey, client, todoStore, subAgentTracker, agentRegistry, skillRegistry } = ctx;
|
|
3583
|
-
const parts = input.trim().split(/\s+/);
|
|
3584
|
-
const command = parts[0];
|
|
3585
|
-
switch (command) {
|
|
3586
|
-
case "/help":
|
|
3587
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3588
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3589
|
-
{
|
|
3590
|
-
let helpText = `\u53EF\u7528\u547D\u4EE4:
|
|
3591
|
-
/help \u663E\u793A\u6B64\u5E2E\u52A9\u4FE1\u606F
|
|
3592
|
-
/skills \u5217\u51FA\u6240\u6709\u53EF\u7528\u6280\u80FD
|
|
3593
|
-
/agents \u5217\u51FA\u6240\u6709\u53EF\u7528\u5B50 Agent
|
|
3594
|
-
/parallel \u5207\u6362\u5E76\u884C\u5B50 Agent \u529F\u80FD on/off
|
|
3595
|
-
/todo \u5207\u6362 todo \u8BA1\u5212\u529F\u80FD on/off
|
|
3596
|
-
/clear \u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2
|
|
3597
|
-
/info \u663E\u793A\u5F53\u524D\u914D\u7F6E
|
|
3598
|
-
Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42 / \u9000\u51FA
|
|
3599
|
-
Ctrl+D \u9000\u51FA`;
|
|
3600
|
-
const skills = skillRegistry.list();
|
|
3601
|
-
if (skills.length > 0) {
|
|
3602
|
-
helpText += `
|
|
3603
|
-
|
|
3604
|
-
\u53EF\u7528\u6280\u80FD:
|
|
3605
|
-
${skills.map((s) => ` /${s.name} ${s.description}`).join("\n")}`;
|
|
3606
|
-
}
|
|
3607
|
-
dispatch({ type: "APPEND_CONTENT", text: helpText });
|
|
3608
|
-
}
|
|
3609
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3610
|
-
break;
|
|
3611
|
-
case "/skills": {
|
|
3612
|
-
const skills = skillRegistry.list();
|
|
3613
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3614
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3615
|
-
if (skills.length === 0) {
|
|
3616
|
-
dispatch({ type: "APPEND_CONTENT", text: "\u6682\u65E0\u53EF\u7528\u6280\u80FD\u3002\u5728 ~/.zencode/skills/ \u6216 .zencode/skills/ \u653E\u7F6E YAML \u6587\u4EF6\u6DFB\u52A0\u6280\u80FD\u3002" });
|
|
3617
|
-
} else {
|
|
3618
|
-
const lines = skills.map((s) => ` /${s.name}: ${s.description}`);
|
|
3619
|
-
dispatch({ type: "APPEND_CONTENT", text: `\u53EF\u7528\u6280\u80FD (${skills.length}):
|
|
3620
|
-
${lines.join("\n")}` });
|
|
3621
|
-
}
|
|
3622
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3623
|
-
break;
|
|
3624
|
-
}
|
|
3625
|
-
case "/agents": {
|
|
3626
|
-
const agents = agentRegistry.list();
|
|
3627
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3628
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3629
|
-
if (agents.length === 0) {
|
|
3630
|
-
dispatch({ type: "APPEND_CONTENT", text: "\u6682\u65E0\u53EF\u7528\u5B50 Agent\u3002" });
|
|
3631
|
-
} else {
|
|
3632
|
-
const lines = agents.map((a) => ` ${a.name}: ${a.description} [tools: ${a.tools.join(", ")}]`);
|
|
3633
|
-
dispatch({ type: "APPEND_CONTENT", text: `\u53EF\u7528\u5B50 Agent (${agents.length}):
|
|
3634
|
-
${lines.join("\n")}` });
|
|
3635
|
-
}
|
|
3636
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3637
|
-
break;
|
|
3638
|
-
}
|
|
3639
|
-
case "/clear":
|
|
3640
|
-
agent.getConversation().clear();
|
|
3641
|
-
dispatch({ type: "CLEAR_MESSAGES" });
|
|
3642
|
-
setResetKey((prev) => prev + 1);
|
|
3643
|
-
break;
|
|
3644
|
-
case "/parallel": {
|
|
3645
|
-
const current = config.features.parallel_agents;
|
|
3646
|
-
const next = current === "on" ? "off" : "on";
|
|
3647
|
-
config.features.parallel_agents = next;
|
|
3648
|
-
if (next === "off") {
|
|
3649
|
-
registry.unregister("spawn-agents");
|
|
3650
|
-
} else if (!registry.has("spawn-agents")) {
|
|
3651
|
-
registry.register(createSpawnAgentsTool(client, registry, config, subAgentTracker));
|
|
3652
|
-
}
|
|
3653
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3654
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3655
|
-
dispatch({ type: "APPEND_CONTENT", text: `\u5E76\u884C\u5B50 Agent \u529F\u80FD\u5DF2${next === "on" ? "\u5F00\u542F" : "\u5173\u95ED"}` });
|
|
3656
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3657
|
-
break;
|
|
3658
|
-
}
|
|
3659
|
-
case "/todo": {
|
|
3660
|
-
const current = config.features.todo;
|
|
3661
|
-
const next = current === "on" ? "off" : "on";
|
|
3662
|
-
config.features.todo = next;
|
|
3663
|
-
if (next === "off") {
|
|
3664
|
-
registry.unregister("todo");
|
|
3665
|
-
} else if (!registry.has("todo")) {
|
|
3666
|
-
registry.register(createTodoTool(todoStore));
|
|
3667
|
-
}
|
|
3668
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3669
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3670
|
-
dispatch({ type: "APPEND_CONTENT", text: `Todo \u8BA1\u5212\u529F\u80FD\u5DF2${next === "on" ? "\u5F00\u542F" : "\u5173\u95ED"}` });
|
|
3671
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3672
|
-
break;
|
|
3673
|
-
}
|
|
3674
|
-
case "/info":
|
|
3675
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3676
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3677
|
-
dispatch({
|
|
3678
|
-
type: "APPEND_CONTENT",
|
|
3679
|
-
text: `\u6A21\u578B: ${config.model}
|
|
3680
|
-
\u57FA\u7840 URL: ${config.base_url}
|
|
3681
|
-
\u5B50 Agent: ${agentRegistry.listNames().join(", ") || "\u65E0"}
|
|
3682
|
-
\u6280\u80FD: ${skillRegistry.listNames().map((n) => "/" + n).join(", ") || "\u65E0"}`
|
|
3683
|
-
});
|
|
3684
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3685
|
-
break;
|
|
3686
|
-
default:
|
|
3687
|
-
dispatch({ type: "ADD_USER_MESSAGE", text: input });
|
|
3688
|
-
dispatch({ type: "START_ASSISTANT" });
|
|
3689
|
-
dispatch({
|
|
3690
|
-
type: "APPEND_CONTENT",
|
|
3691
|
-
text: `\u672A\u77E5\u547D\u4EE4: ${command}\u3002\u8F93\u5165 /help \u67E5\u770B\u5E2E\u52A9\u3002`
|
|
3692
|
-
});
|
|
3693
|
-
dispatch({ type: "FINISH_STREAMING" });
|
|
3694
|
-
break;
|
|
3695
|
-
}
|
|
3696
|
-
}
|
|
3697
3824
|
var init_App = __esm({
|
|
3698
3825
|
"src/cli/tui/App.tsx"() {
|
|
3699
3826
|
"use strict";
|
|
@@ -3701,14 +3828,11 @@ var init_App = __esm({
|
|
|
3701
3828
|
init_permission();
|
|
3702
3829
|
init_state();
|
|
3703
3830
|
init_bridge();
|
|
3704
|
-
init_spawn_agents();
|
|
3705
|
-
init_todo();
|
|
3706
3831
|
init_ChatArea();
|
|
3707
3832
|
init_InputArea();
|
|
3708
3833
|
init_StatusBar();
|
|
3709
3834
|
init_ConfirmPrompt();
|
|
3710
3835
|
init_TodoPanel();
|
|
3711
|
-
init_Header();
|
|
3712
3836
|
}
|
|
3713
3837
|
});
|
|
3714
3838
|
|
|
@@ -3902,69 +4026,9 @@ init_spawn_agents();
|
|
|
3902
4026
|
init_todo();
|
|
3903
4027
|
init_dispatch();
|
|
3904
4028
|
init_bridge();
|
|
4029
|
+
init_ui();
|
|
3905
4030
|
import * as readline from "readline";
|
|
3906
|
-
|
|
3907
|
-
// src/cli/ui.ts
|
|
3908
|
-
import chalk2 from "chalk";
|
|
3909
|
-
import ora from "ora";
|
|
3910
|
-
import { marked } from "marked";
|
|
3911
|
-
import * as _markedTerminal from "marked-terminal";
|
|
3912
|
-
import { createTwoFilesPatch } from "diff";
|
|
3913
|
-
var markedTerminal2 = _markedTerminal.markedTerminal;
|
|
3914
|
-
marked.use(markedTerminal2());
|
|
3915
|
-
function printStream(text) {
|
|
3916
|
-
process.stdout.write(text);
|
|
3917
|
-
}
|
|
3918
|
-
function printToolCall(toolName, params) {
|
|
3919
|
-
let detail = "";
|
|
3920
|
-
if (toolName === "bash" && params["command"]) {
|
|
3921
|
-
detail = ` ${chalk2.dim(String(params["command"]).slice(0, 80))}`;
|
|
3922
|
-
} else if ((toolName === "read-file" || toolName === "write-file" || toolName === "edit-file") && params["path"]) {
|
|
3923
|
-
detail = ` ${chalk2.dim(String(params["path"]))}`;
|
|
3924
|
-
} else if (toolName === "glob" && params["pattern"]) {
|
|
3925
|
-
detail = ` ${chalk2.dim(String(params["pattern"]))}`;
|
|
3926
|
-
} else if (toolName === "grep" && params["pattern"]) {
|
|
3927
|
-
detail = ` ${chalk2.dim(String(params["pattern"]))}`;
|
|
3928
|
-
} else if (toolName === "spawn-agents" && params["tasks"]) {
|
|
3929
|
-
const tasks = params["tasks"];
|
|
3930
|
-
detail = ` ${chalk2.dim(`${tasks.length} \u4E2A\u5E76\u884C\u4EFB\u52A1`)}`;
|
|
3931
|
-
} else if (toolName === "todo" && params["action"]) {
|
|
3932
|
-
const action = String(params["action"]);
|
|
3933
|
-
const id = params["id"] ? ` [${params["id"]}]` : "";
|
|
3934
|
-
detail = ` ${chalk2.dim(`${action}${id}`)}`;
|
|
3935
|
-
}
|
|
3936
|
-
const icon = toolName === "spawn-agents" ? "\u26A1" : toolName === "todo" ? "\u{1F4CB}" : "\u2699";
|
|
3937
|
-
console.log(chalk2.yellow(` ${icon} ${toolName}`) + detail);
|
|
3938
|
-
}
|
|
3939
|
-
function printToolResult(toolName, result, truncated) {
|
|
3940
|
-
if (truncated) {
|
|
3941
|
-
console.log(chalk2.dim(` \u2713 ${toolName} (\u8F93\u51FA\u5DF2\u622A\u65AD)`));
|
|
3942
|
-
} else {
|
|
3943
|
-
const lines = result.split("\n").length;
|
|
3944
|
-
console.log(chalk2.dim(` \u2713 ${toolName} (${lines} \u884C)`));
|
|
3945
|
-
}
|
|
3946
|
-
}
|
|
3947
|
-
function printError(message) {
|
|
3948
|
-
console.error(chalk2.red(`\u2717 ${message}`));
|
|
3949
|
-
}
|
|
3950
|
-
function printInfo(message) {
|
|
3951
|
-
console.log(chalk2.cyan(`\u2139 ${message}`));
|
|
3952
|
-
}
|
|
3953
|
-
function printWarning(message) {
|
|
3954
|
-
console.log(chalk2.yellow(`\u26A0 ${message}`));
|
|
3955
|
-
}
|
|
3956
|
-
function printSuccess(message) {
|
|
3957
|
-
console.log(chalk2.green(`\u2713 ${message}`));
|
|
3958
|
-
}
|
|
3959
|
-
function printWelcome(modelName) {
|
|
3960
|
-
console.log(chalk2.bold.cyan("\n ZenCode") + chalk2.dim(" - \u6781\u7B80 AI \u7F16\u7A0B\u52A9\u624B\n"));
|
|
3961
|
-
console.log(chalk2.dim(` \u6A21\u578B: ${modelName}`));
|
|
3962
|
-
console.log(chalk2.dim(` \u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u9000\u51FA
|
|
3963
|
-
`));
|
|
3964
|
-
}
|
|
3965
|
-
|
|
3966
|
-
// src/cli/repl.ts
|
|
3967
|
-
function handleSlashCommand(input, context) {
|
|
4031
|
+
function handleSlashCommand2(input, context) {
|
|
3968
4032
|
const parts = input.trim().split(/\s+/);
|
|
3969
4033
|
const command = parts[0];
|
|
3970
4034
|
switch (command) {
|
|
@@ -4156,7 +4220,7 @@ async function startRepl(options) {
|
|
|
4156
4220
|
rl.prompt();
|
|
4157
4221
|
return;
|
|
4158
4222
|
}
|
|
4159
|
-
const handled =
|
|
4223
|
+
const handled = handleSlashCommand2(input, {
|
|
4160
4224
|
config,
|
|
4161
4225
|
registry,
|
|
4162
4226
|
client,
|
|
@@ -4232,6 +4296,7 @@ init_spawn_agents();
|
|
|
4232
4296
|
init_todo();
|
|
4233
4297
|
init_dispatch();
|
|
4234
4298
|
init_bridge();
|
|
4299
|
+
init_ui();
|
|
4235
4300
|
async function runOnce(prompt, config) {
|
|
4236
4301
|
const agentRegistry = new SubAgentConfigRegistry();
|
|
4237
4302
|
for (const agentConfig of loadAllAgentConfigs()) {
|
|
@@ -4295,7 +4360,7 @@ async function runOnce(prompt, config) {
|
|
|
4295
4360
|
}
|
|
4296
4361
|
function createCli() {
|
|
4297
4362
|
const program2 = new Command();
|
|
4298
|
-
program2.name("zencode").description("\u6781\u7B80 CLI AI \u7F16\u7A0B\u5DE5\u5177").version("0.
|
|
4363
|
+
program2.name("zencode").description("\u6781\u7B80 CLI AI \u7F16\u7A0B\u5DE5\u5177").version("0.4.1").option("-m, --model <model>", "\u6307\u5B9A\u6A21\u578B\u540D\u79F0").option("-k, --api-key <key>", "API \u5BC6\u94A5").option("-u, --base-url <url>", "API \u57FA\u7840 URL").option("--simple", "\u4F7F\u7528\u7B80\u5355 REPL \u6A21\u5F0F\uFF08\u975E\u5168\u5C4F TUI\uFF09").argument("[prompt...]", "\u76F4\u63A5\u6267\u884C\u7684\u63D0\u793A\u8BCD\uFF08\u975E\u4EA4\u4E92\u5F0F\uFF09").action(async (promptParts, opts) => {
|
|
4299
4364
|
const config = loadConfig(opts);
|
|
4300
4365
|
if (!config.api_key) {
|
|
4301
4366
|
printError("\u672A\u8BBE\u7F6E API \u5BC6\u94A5\u3002\u8BF7\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u4E4B\u4E00\u8BBE\u7F6E\uFF1A");
|
|
@@ -4311,6 +4376,7 @@ function createCli() {
|
|
|
4311
4376
|
await startRepl({ config });
|
|
4312
4377
|
} else {
|
|
4313
4378
|
const { startTui: startTui2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
|
|
4379
|
+
process.stdout.write("\x1Bc");
|
|
4314
4380
|
await startTui2({ config });
|
|
4315
4381
|
}
|
|
4316
4382
|
});
|