jinzd-ai-cli 0.4.180 → 0.4.182
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/{batch-OJJI6TKB.js → batch-ZBKVDSMZ.js} +2 -2
- package/dist/{chunk-ZUUXMR6Z.js → chunk-4NPR3MFZ.js} +1 -1
- package/dist/{chunk-2TWARH5X.js → chunk-5LK7H45B.js} +331 -22
- package/dist/{chunk-FQHEXIYP.js → chunk-C6UJBTZO.js} +2 -2
- package/dist/{chunk-KRU4DFRH.js → chunk-ISO5KVEJ.js} +1 -1
- package/dist/{chunk-WY2DDJTH.js → chunk-LWZ6P73G.js} +1 -1
- package/dist/{chunk-H7TXZO6D.js → chunk-QUYLXQRU.js} +1 -1
- package/dist/{chunk-YDI22R3P.js → chunk-RUUJHLEV.js} +1 -1
- package/dist/{chunk-7WFMYFHC.js → chunk-XI7EUUL7.js} +3 -3
- package/dist/{chunk-2UGK2RXK.js → chunk-YDIR3MXD.js} +1 -1
- package/dist/{ci-EBN6VQ2Z.js → ci-6WGF6ID6.js} +3 -3
- package/dist/{constants-FGPUBYCX.js → constants-JI7VPTMJ.js} +1 -1
- package/dist/{doctor-cli-C54OKMG2.js → doctor-cli-KSB3MLFV.js} +5 -5
- package/dist/electron-server.js +380 -182
- package/dist/{hub-YVNTGDKW.js → hub-DGEYFJPP.js} +1 -1
- package/dist/index.js +223 -323
- package/dist/{run-tests-QFTKAWW6.js → run-tests-GFOHEIWM.js} +2 -2
- package/dist/{run-tests-BUII3HBU.js → run-tests-ZP5TPFTK.js} +1 -1
- package/dist/{server-KT6GRCM7.js → server-2CBNRT2W.js} +77 -167
- package/dist/{server-I6Y5TP2Z.js → server-TXA5VTOS.js} +4 -4
- package/dist/{task-orchestrator-6RLY5JAL.js → task-orchestrator-4T457G22.js} +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
saveDevState,
|
|
19
19
|
sessionHasMeaningfulContent,
|
|
20
20
|
setupProxy
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-C6UJBTZO.js";
|
|
22
22
|
import {
|
|
23
23
|
ToolExecutor,
|
|
24
24
|
ToolRegistry,
|
|
@@ -37,10 +37,10 @@ import {
|
|
|
37
37
|
spawnAgentContext,
|
|
38
38
|
theme,
|
|
39
39
|
undoStack
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-XI7EUUL7.js";
|
|
41
41
|
import "./chunk-HDSKW7Q3.js";
|
|
42
42
|
import "./chunk-ZWVIDFGY.js";
|
|
43
|
-
import "./chunk-
|
|
43
|
+
import "./chunk-QUYLXQRU.js";
|
|
44
44
|
import {
|
|
45
45
|
SessionManager,
|
|
46
46
|
getContentText
|
|
@@ -49,15 +49,25 @@ import {
|
|
|
49
49
|
getConfigDirUsage,
|
|
50
50
|
listRecentCrashes,
|
|
51
51
|
writeCrashLog
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-4NPR3MFZ.js";
|
|
53
53
|
import {
|
|
54
|
+
BudgetWarner,
|
|
54
55
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
56
|
+
ContextPressureMonitor,
|
|
57
|
+
EmptyResponseGuard,
|
|
58
|
+
FreeRoundTracker,
|
|
55
59
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
56
60
|
ProviderRegistry,
|
|
57
61
|
TEE_FINAL_USER_NUDGE,
|
|
58
62
|
TOOL_CALL_REMINDER,
|
|
63
|
+
ThinkTagFilter,
|
|
64
|
+
accumulateUsage,
|
|
59
65
|
buildPhantomCorrectionMessage,
|
|
66
|
+
buildRoundBudgetHint,
|
|
67
|
+
buildRoundsExhaustedPrompt,
|
|
68
|
+
buildUserStopMessage,
|
|
60
69
|
buildWriteRoundReminder,
|
|
70
|
+
consumeToolCallStream,
|
|
61
71
|
detectMetaNarration,
|
|
62
72
|
detectPseudoToolCalls,
|
|
63
73
|
detectsHallucinatedFileOp,
|
|
@@ -67,18 +77,19 @@ import {
|
|
|
67
77
|
hadPreviousWriteToolCalls,
|
|
68
78
|
looksLikeDocumentBody,
|
|
69
79
|
stripPseudoToolCalls,
|
|
70
|
-
stripToolCallReminder
|
|
71
|
-
|
|
80
|
+
stripToolCallReminder,
|
|
81
|
+
summarizeRecentTools
|
|
82
|
+
} from "./chunk-5LK7H45B.js";
|
|
72
83
|
import {
|
|
73
84
|
getStatsSnapshot,
|
|
74
85
|
getTopFailingTools,
|
|
75
86
|
getTopUsedTools,
|
|
76
87
|
installFlushOnExit
|
|
77
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-LWZ6P73G.js";
|
|
78
89
|
import "./chunk-HIU2SH4V.js";
|
|
79
90
|
import {
|
|
80
91
|
ConfigManager
|
|
81
|
-
} from "./chunk-
|
|
92
|
+
} from "./chunk-YDIR3MXD.js";
|
|
82
93
|
import {
|
|
83
94
|
AuthError,
|
|
84
95
|
ProviderError,
|
|
@@ -105,7 +116,7 @@ import {
|
|
|
105
116
|
SKILLS_DIR_NAME,
|
|
106
117
|
VERSION,
|
|
107
118
|
buildUserIdentityPrompt
|
|
108
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-ISO5KVEJ.js";
|
|
109
120
|
import {
|
|
110
121
|
formatGitContextForPrompt,
|
|
111
122
|
getGitContext,
|
|
@@ -208,13 +219,6 @@ function isInterruptedSession(messages) {
|
|
|
208
219
|
import chalk from "chalk";
|
|
209
220
|
import { createWriteStream, mkdirSync } from "fs";
|
|
210
221
|
import { dirname } from "path";
|
|
211
|
-
function partialTagTail(s, tag) {
|
|
212
|
-
const max = Math.min(s.length, tag.length - 1);
|
|
213
|
-
for (let k = max; k > 0; k--) {
|
|
214
|
-
if (s.endsWith(tag.slice(0, k))) return k;
|
|
215
|
-
}
|
|
216
|
-
return 0;
|
|
217
|
-
}
|
|
218
222
|
function fmtContextWindow(tokens) {
|
|
219
223
|
if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
|
|
220
224
|
if (tokens >= 1e3) return `${Math.round(tokens / 1024)}K`;
|
|
@@ -495,48 +499,15 @@ var Renderer = class {
|
|
|
495
499
|
}
|
|
496
500
|
let fullContent = "";
|
|
497
501
|
let usage;
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (!inThinking) {
|
|
505
|
-
const open = thinkBuf.indexOf("<think>");
|
|
506
|
-
if (open === -1) {
|
|
507
|
-
const keep = partialTagTail(thinkBuf, "<think>");
|
|
508
|
-
out += thinkBuf.slice(0, thinkBuf.length - keep);
|
|
509
|
-
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
510
|
-
break;
|
|
511
|
-
}
|
|
512
|
-
out += thinkBuf.slice(0, open);
|
|
513
|
-
thinkBuf = thinkBuf.slice(open + "<think>".length);
|
|
514
|
-
inThinking = true;
|
|
515
|
-
} else {
|
|
516
|
-
const close = thinkBuf.indexOf("</think>");
|
|
517
|
-
if (close === -1) {
|
|
518
|
-
const keep = partialTagTail(thinkBuf, "</think>");
|
|
519
|
-
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
thinkBuf = thinkBuf.slice(close + "</think>".length);
|
|
523
|
-
inThinking = false;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
if (out) {
|
|
527
|
-
process.stdout.write(out);
|
|
528
|
-
if (fileStream) fileStream.write(out);
|
|
529
|
-
fullContent += out;
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
|
-
const flushTail = () => {
|
|
533
|
-
if (!inThinking && thinkBuf) {
|
|
534
|
-
process.stdout.write(thinkBuf);
|
|
535
|
-
if (fileStream) fileStream.write(thinkBuf);
|
|
536
|
-
fullContent += thinkBuf;
|
|
537
|
-
thinkBuf = "";
|
|
538
|
-
}
|
|
502
|
+
const thinkFilter = new ThinkTagFilter();
|
|
503
|
+
const writeVisible = (visible) => {
|
|
504
|
+
if (!visible) return;
|
|
505
|
+
process.stdout.write(visible);
|
|
506
|
+
if (fileStream) fileStream.write(visible);
|
|
507
|
+
fullContent += visible;
|
|
539
508
|
};
|
|
509
|
+
const emitText = (raw) => writeVisible(thinkFilter.push(raw));
|
|
510
|
+
const flushTail = () => writeVisible(thinkFilter.flush());
|
|
540
511
|
let interrupted = false;
|
|
541
512
|
let streamErr = null;
|
|
542
513
|
try {
|
|
@@ -1016,6 +987,61 @@ function copyToClipboard(text) {
|
|
|
1016
987
|
}
|
|
1017
988
|
}
|
|
1018
989
|
}
|
|
990
|
+
var SESSION_PAGE_SIZE = 20;
|
|
991
|
+
function oneLinePreview(s, max) {
|
|
992
|
+
const flat = s.replace(/\s+/g, " ").trim();
|
|
993
|
+
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
994
|
+
}
|
|
995
|
+
function renderTranscriptMessage(msg, renderer) {
|
|
996
|
+
if (msg.role === "user") {
|
|
997
|
+
const text = getContentText(msg.content);
|
|
998
|
+
console.log(theme.success("You: ") + (text.includes("\n") ? "\n" + text : text));
|
|
999
|
+
console.log();
|
|
1000
|
+
} else if (msg.role === "assistant") {
|
|
1001
|
+
const text = getContentText(msg.content);
|
|
1002
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
1003
|
+
if (text.trim()) {
|
|
1004
|
+
console.log(theme.dim(`Assistant: ${oneLinePreview(text, 100)}`));
|
|
1005
|
+
}
|
|
1006
|
+
for (const tc of msg.toolCalls) {
|
|
1007
|
+
console.log(theme.dim(` \u2699 ${tc.name} ${oneLinePreview(JSON.stringify(tc.arguments ?? {}), 80)}`));
|
|
1008
|
+
}
|
|
1009
|
+
} else if (text.trim()) {
|
|
1010
|
+
renderer.renderResponse(text);
|
|
1011
|
+
console.log();
|
|
1012
|
+
}
|
|
1013
|
+
} else if (msg.role === "tool") {
|
|
1014
|
+
const preview = oneLinePreview(getContentText(msg.content), 80);
|
|
1015
|
+
const paint = msg.isError ? theme.error : theme.dim;
|
|
1016
|
+
console.log(paint(` \u2192 ${msg.toolName ?? "tool"}: ${preview}`));
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
function renderTranscriptPage(messages, renderer, requestedPage) {
|
|
1020
|
+
const total = messages.length;
|
|
1021
|
+
if (total === 0) {
|
|
1022
|
+
renderer.printInfo("Session has no messages yet.");
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const totalPages = Math.max(1, Math.ceil(total / SESSION_PAGE_SIZE));
|
|
1026
|
+
let page = requestedPage === void 0 || !Number.isFinite(requestedPage) ? totalPages : requestedPage;
|
|
1027
|
+
if (page < 1) page = 1;
|
|
1028
|
+
if (page > totalPages) page = totalPages;
|
|
1029
|
+
const start = (page - 1) * SESSION_PAGE_SIZE;
|
|
1030
|
+
const slice = messages.slice(start, start + SESSION_PAGE_SIZE);
|
|
1031
|
+
console.log();
|
|
1032
|
+
console.log(theme.info(` \u2500\u2500 Transcript page ${page}/${totalPages} (messages ${start + 1}\u2013${start + slice.length} of ${total}) \u2500\u2500`));
|
|
1033
|
+
console.log();
|
|
1034
|
+
for (const msg of slice) {
|
|
1035
|
+
renderTranscriptMessage(msg, renderer);
|
|
1036
|
+
}
|
|
1037
|
+
const hints = [];
|
|
1038
|
+
if (page > 1) hints.push(`/session page ${page - 1} = earlier`);
|
|
1039
|
+
if (page < totalPages) hints.push(`/session page ${page + 1} = later`);
|
|
1040
|
+
if (hints.length > 0) {
|
|
1041
|
+
console.log(theme.dim(` \u2500\u2500 ${hints.join(" \xB7 ")} \u2500\u2500`));
|
|
1042
|
+
}
|
|
1043
|
+
console.log();
|
|
1044
|
+
}
|
|
1019
1045
|
var CommandRegistry = class {
|
|
1020
1046
|
commands = /* @__PURE__ */ new Map();
|
|
1021
1047
|
register(command) {
|
|
@@ -1089,7 +1115,7 @@ function createDefaultCommands() {
|
|
|
1089
1115
|
rows: [
|
|
1090
1116
|
["/clear", "Clear conversation history"],
|
|
1091
1117
|
["/compact [instruction]", "Summarize & compress history"],
|
|
1092
|
-
["/session new|list|load
|
|
1118
|
+
["/session new|list|load|show|page|remove", "Manage saved sessions (show = transcript + continue)"],
|
|
1093
1119
|
["/checkpoint [save|restore|delete] <name>", "Session checkpoints"],
|
|
1094
1120
|
["/fork [checkpoint]", "Fork session from checkpoint or current"],
|
|
1095
1121
|
["/branch [list|new|switch|delete|rename|diff|cherry-pick]", "Conversation branches"],
|
|
@@ -1363,8 +1389,8 @@ No commands match "${filter}".
|
|
|
1363
1389
|
{
|
|
1364
1390
|
name: "session",
|
|
1365
1391
|
description: "Session management",
|
|
1366
|
-
usage: "/session new|list|load <id>",
|
|
1367
|
-
execute(args, ctx) {
|
|
1392
|
+
usage: "/session new|list|load <id>|show <id> [page]|page <n>|remove <id>",
|
|
1393
|
+
async execute(args, ctx) {
|
|
1368
1394
|
const sub = args[0];
|
|
1369
1395
|
if (sub === "new") {
|
|
1370
1396
|
const provider = ctx.getCurrentProvider();
|
|
@@ -1391,10 +1417,10 @@ No commands match "${filter}".
|
|
|
1391
1417
|
s.title ?? "(untitled)"
|
|
1392
1418
|
])
|
|
1393
1419
|
);
|
|
1394
|
-
} else if (sub === "load") {
|
|
1420
|
+
} else if (sub === "load" || sub === "show") {
|
|
1395
1421
|
const id = args[1];
|
|
1396
1422
|
if (!id) {
|
|
1397
|
-
ctx.renderer.renderError(
|
|
1423
|
+
ctx.renderer.renderError(`Usage: /session ${sub} <id>${sub === "show" ? " [page]" : ""}`);
|
|
1398
1424
|
return;
|
|
1399
1425
|
}
|
|
1400
1426
|
const sessions = ctx.sessions.listSessions();
|
|
@@ -1416,8 +1442,70 @@ No commands match "${filter}".
|
|
|
1416
1442
|
ctx.renderer.printSuccess(
|
|
1417
1443
|
`Loaded session ${match.id.slice(0, 8)}: ${match.title ?? "(untitled)"}`
|
|
1418
1444
|
);
|
|
1445
|
+
if (sub === "show") {
|
|
1446
|
+
const pageArg = args[2] !== void 0 ? Number.parseInt(args[2], 10) : void 0;
|
|
1447
|
+
const cur = ctx.sessions.current;
|
|
1448
|
+
if (cur) renderTranscriptPage(cur.messages, ctx.renderer, pageArg);
|
|
1449
|
+
}
|
|
1450
|
+
} else if (sub === "page") {
|
|
1451
|
+
const cur = ctx.sessions.current;
|
|
1452
|
+
if (!cur) {
|
|
1453
|
+
ctx.renderer.renderError("No active session. Use /session show <id> first.");
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
const n = Number.parseInt(args[1] ?? "", 10);
|
|
1457
|
+
if (Number.isNaN(n)) {
|
|
1458
|
+
ctx.renderer.renderError("Usage: /session page <n>");
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
renderTranscriptPage(cur.messages, ctx.renderer, n);
|
|
1462
|
+
} else if (sub === "remove" || sub === "delete") {
|
|
1463
|
+
const id = args[1];
|
|
1464
|
+
if (!id) {
|
|
1465
|
+
ctx.renderer.renderError("Usage: /session remove <id>");
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
const sessions = ctx.sessions.listSessions();
|
|
1469
|
+
const matches2 = sessions.filter((s) => s.id.startsWith(id));
|
|
1470
|
+
if (matches2.length === 0) {
|
|
1471
|
+
ctx.renderer.renderError(`Session '${id}' not found.`);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
if (matches2.length > 1) {
|
|
1475
|
+
ctx.renderer.renderError(`Ambiguous prefix '${id}' matches ${matches2.length} sessions \u2014 be more specific:`);
|
|
1476
|
+
for (const m of matches2.slice(0, 10)) {
|
|
1477
|
+
console.log(theme.dim(` ${m.id.slice(0, 12)} ${String(m.messageCount).padStart(4)} msgs ${m.updated.toLocaleDateString()} ${m.title ?? "(untitled)"}`));
|
|
1478
|
+
}
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
const match = matches2[0];
|
|
1482
|
+
const isCurrent = ctx.sessions.current?.id === match.id;
|
|
1483
|
+
console.log();
|
|
1484
|
+
console.log(theme.warning(" About to permanently delete session (no undo):"));
|
|
1485
|
+
console.log(` ${theme.info(match.id.slice(0, 12))} ${match.provider}/${match.model} ${match.messageCount} messages ${match.updated.toLocaleDateString()}`);
|
|
1486
|
+
console.log(` ${match.title ?? "(untitled)"}${isCurrent ? theme.warning(" \u2190 current session") : ""}`);
|
|
1487
|
+
console.log();
|
|
1488
|
+
const choice = await ctx.select("Delete this session?", [
|
|
1489
|
+
{ label: "No \u2014 keep it", value: "no" },
|
|
1490
|
+
{ label: "Yes \u2014 delete permanently", value: "yes", hint: "unlinks the history file" }
|
|
1491
|
+
]);
|
|
1492
|
+
if (choice !== "yes") {
|
|
1493
|
+
ctx.renderer.printInfo("Cancelled \u2014 session kept.");
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (!ctx.sessions.deleteSession(match.id)) {
|
|
1497
|
+
ctx.renderer.renderError("Delete failed \u2014 session file not found on disk.");
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
ctx.renderer.printSuccess(`Deleted session ${match.id.slice(0, 8)}: ${match.title ?? "(untitled)"}`);
|
|
1501
|
+
if (isCurrent) {
|
|
1502
|
+
ctx.sessions.createSession(ctx.getCurrentProvider(), ctx.getCurrentModel());
|
|
1503
|
+
ctx.resetSessionTokenUsage();
|
|
1504
|
+
ctx.clearDevState();
|
|
1505
|
+
ctx.renderer.printInfo("Current session was deleted \u2014 started a fresh session.");
|
|
1506
|
+
}
|
|
1419
1507
|
} else {
|
|
1420
|
-
ctx.renderer.renderError("Usage: /session new|list|load <id>");
|
|
1508
|
+
ctx.renderer.renderError("Usage: /session new|list|load <id>|show <id> [page]|page <n>|remove <id>");
|
|
1421
1509
|
}
|
|
1422
1510
|
}
|
|
1423
1511
|
},
|
|
@@ -1786,7 +1874,7 @@ No tools match "${filter}".
|
|
|
1786
1874
|
const { join: join6 } = await import("path");
|
|
1787
1875
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1788
1876
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1789
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1877
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-JI7VPTMJ.js");
|
|
1790
1878
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1791
1879
|
const cwd = process.cwd();
|
|
1792
1880
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2847,7 +2935,7 @@ ${hint}` : "")
|
|
|
2847
2935
|
usage: "/test [command|filter]",
|
|
2848
2936
|
async execute(args, ctx) {
|
|
2849
2937
|
try {
|
|
2850
|
-
const { executeTests } = await import("./run-tests-
|
|
2938
|
+
const { executeTests } = await import("./run-tests-GFOHEIWM.js");
|
|
2851
2939
|
const argStr = args.join(" ").trim();
|
|
2852
2940
|
let testArgs = {};
|
|
2853
2941
|
if (argStr) {
|
|
@@ -4694,17 +4782,8 @@ ${content}
|
|
|
4694
4782
|
parts.push(...imageParts);
|
|
4695
4783
|
return { parts, hasImage: imageParts.length > 0, refs };
|
|
4696
4784
|
}
|
|
4697
|
-
var FREE_ROUND_TOOLS = /* @__PURE__ */ new Set(["write_todos"]);
|
|
4698
|
-
var MAX_CONSECUTIVE_FREE_ROUNDS = 3;
|
|
4699
4785
|
var MAX_REPEATED_TOOL_CALLS = 2;
|
|
4700
4786
|
var DEFAULT_AUTO_PAUSE_INTERVAL = 50;
|
|
4701
|
-
function partialTagTail2(s, tag) {
|
|
4702
|
-
const max = Math.min(s.length, tag.length - 1);
|
|
4703
|
-
for (let k = max; k > 0; k--) {
|
|
4704
|
-
if (s.endsWith(tag.slice(0, k))) return k;
|
|
4705
|
-
}
|
|
4706
|
-
return 0;
|
|
4707
|
-
}
|
|
4708
4787
|
function fmtTokens(n) {
|
|
4709
4788
|
if (n >= 1e6) return `${Math.round(n / 1e5) / 10}M`;
|
|
4710
4789
|
if (n >= 1e3) return `${Math.round(n / 1024)}K`;
|
|
@@ -6407,14 +6486,12 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6407
6486
|
/**
|
|
6408
6487
|
* 消费流式工具调用事件生成器,实时渲染文本内容和工具名称,
|
|
6409
6488
|
* 累积完整工具调用参数后返回结构化结果。
|
|
6489
|
+
*
|
|
6490
|
+
* v0.4.181: 累积与决策(<think> 折叠 / 截断 JSON 修复 / done 守卫 /
|
|
6491
|
+
* index 键累积)委托给 core/agent-loop 的统一消费器(与 Web 端同一实现),
|
|
6492
|
+
* 此处只保留终端呈现(spinner / theme 渲染)。
|
|
6410
6493
|
*/
|
|
6411
6494
|
async consumeToolStream(stream, spinner) {
|
|
6412
|
-
const textParts = [];
|
|
6413
|
-
const toolCallAccumulators = /* @__PURE__ */ new Map();
|
|
6414
|
-
let usage;
|
|
6415
|
-
let rawContent;
|
|
6416
|
-
let reasoningContent;
|
|
6417
|
-
let finishReason;
|
|
6418
6495
|
let spinnerStopped = false;
|
|
6419
6496
|
const stopSpinner = () => {
|
|
6420
6497
|
if (!spinnerStopped) {
|
|
@@ -6422,135 +6499,36 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6422
6499
|
spinnerStopped = true;
|
|
6423
6500
|
}
|
|
6424
6501
|
};
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
let thinkBuf = "";
|
|
6428
|
-
const emitText = (raw) => {
|
|
6429
|
-
thinkBuf += raw;
|
|
6430
|
-
let out = "";
|
|
6431
|
-
while (thinkBuf.length > 0) {
|
|
6432
|
-
if (!inThink) {
|
|
6433
|
-
const open = thinkBuf.indexOf("<think>");
|
|
6434
|
-
if (open === -1) {
|
|
6435
|
-
const keep = partialTagTail2(thinkBuf, "<think>");
|
|
6436
|
-
out += thinkBuf.slice(0, thinkBuf.length - keep);
|
|
6437
|
-
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
6438
|
-
break;
|
|
6439
|
-
}
|
|
6440
|
-
out += thinkBuf.slice(0, open);
|
|
6441
|
-
thinkBuf = thinkBuf.slice(open + "<think>".length);
|
|
6442
|
-
inThink = true;
|
|
6443
|
-
thinkShown = true;
|
|
6444
|
-
} else {
|
|
6445
|
-
const close = thinkBuf.indexOf("</think>");
|
|
6446
|
-
if (close === -1) {
|
|
6447
|
-
const keep = partialTagTail2(thinkBuf, "</think>");
|
|
6448
|
-
thinkBuf = thinkBuf.slice(thinkBuf.length - keep);
|
|
6449
|
-
break;
|
|
6450
|
-
}
|
|
6451
|
-
thinkBuf = thinkBuf.slice(close + "</think>".length);
|
|
6452
|
-
inThink = false;
|
|
6453
|
-
}
|
|
6454
|
-
}
|
|
6455
|
-
if (out) {
|
|
6456
|
-
process.stdout.write(out);
|
|
6457
|
-
textParts.push(out);
|
|
6458
|
-
}
|
|
6459
|
-
};
|
|
6460
|
-
try {
|
|
6461
|
-
for await (const event of stream) {
|
|
6462
|
-
switch (event.type) {
|
|
6463
|
-
case "text_delta":
|
|
6464
|
-
stopSpinner();
|
|
6465
|
-
emitText(event.delta);
|
|
6466
|
-
break;
|
|
6467
|
-
case "thinking_start":
|
|
6468
|
-
stopSpinner();
|
|
6469
|
-
process.stdout.write(theme.dim("<think>"));
|
|
6470
|
-
break;
|
|
6471
|
-
case "thinking_delta":
|
|
6472
|
-
break;
|
|
6473
|
-
case "thinking_end":
|
|
6474
|
-
process.stdout.write(theme.dim("</think>"));
|
|
6475
|
-
break;
|
|
6476
|
-
case "tool_call_start":
|
|
6477
|
-
stopSpinner();
|
|
6478
|
-
process.stdout.write(
|
|
6479
|
-
theme.dim(`
|
|
6480
|
-
\u2699 Streaming: `) + theme.toolCall(event.name) + theme.dim("...\n")
|
|
6481
|
-
);
|
|
6482
|
-
toolCallAccumulators.set(event.index, {
|
|
6483
|
-
id: event.id,
|
|
6484
|
-
name: event.name,
|
|
6485
|
-
arguments: ""
|
|
6486
|
-
});
|
|
6487
|
-
break;
|
|
6488
|
-
case "tool_call_delta": {
|
|
6489
|
-
const acc = toolCallAccumulators.get(event.index);
|
|
6490
|
-
if (acc) {
|
|
6491
|
-
acc.arguments += event.argumentsDelta;
|
|
6492
|
-
}
|
|
6493
|
-
break;
|
|
6494
|
-
}
|
|
6495
|
-
case "tool_call_end":
|
|
6496
|
-
break;
|
|
6497
|
-
case "done":
|
|
6498
|
-
if (event.usage) usage = event.usage;
|
|
6499
|
-
if (event.rawContent) rawContent = event.rawContent;
|
|
6500
|
-
if (event.reasoningContent) reasoningContent = event.reasoningContent;
|
|
6501
|
-
if (event.finishReason) finishReason = event.finishReason;
|
|
6502
|
-
break;
|
|
6503
|
-
}
|
|
6504
|
-
}
|
|
6505
|
-
} catch (err) {
|
|
6506
|
-
if (err instanceof Error && (err.name === "AbortError" || err.message.includes("aborted"))) {
|
|
6502
|
+
const result = await consumeToolCallStream(stream, {
|
|
6503
|
+
onText: (visible) => {
|
|
6507
6504
|
stopSpinner();
|
|
6508
|
-
process.stdout.write(
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
}
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
try {
|
|
6529
|
-
parsedArgs = JSON.parse(acc.arguments || "{}");
|
|
6530
|
-
} catch {
|
|
6531
|
-
const truncated = acc.arguments.trimEnd();
|
|
6532
|
-
const lastComma = truncated.lastIndexOf(",");
|
|
6533
|
-
const fixed = lastComma > 0 ? truncated.slice(0, lastComma) + "}" : truncated.slice(0, truncated.indexOf("{") + 1) + "}";
|
|
6534
|
-
try {
|
|
6535
|
-
parsedArgs = JSON.parse(fixed);
|
|
6536
|
-
} catch {
|
|
6537
|
-
parsedArgs = {};
|
|
6538
|
-
}
|
|
6505
|
+
process.stdout.write(visible);
|
|
6506
|
+
},
|
|
6507
|
+
onThinkingStart: () => {
|
|
6508
|
+
stopSpinner();
|
|
6509
|
+
process.stdout.write(theme.dim("<think>"));
|
|
6510
|
+
},
|
|
6511
|
+
// thinking_delta 内容折叠,不显示详情(与现有行为一致)
|
|
6512
|
+
onThinkingEnd: () => {
|
|
6513
|
+
process.stdout.write(theme.dim("</think>"));
|
|
6514
|
+
},
|
|
6515
|
+
onToolCallStart: (_index, _id, name) => {
|
|
6516
|
+
stopSpinner();
|
|
6517
|
+
process.stdout.write(
|
|
6518
|
+
theme.dim(`
|
|
6519
|
+
\u2699 Streaming: `) + theme.toolCall(name) + theme.dim("...\n")
|
|
6520
|
+
);
|
|
6521
|
+
},
|
|
6522
|
+
onWarn: (message) => {
|
|
6523
|
+
process.stderr.write(`[warn] ${message}
|
|
6524
|
+
`);
|
|
6539
6525
|
}
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
});
|
|
6526
|
+
});
|
|
6527
|
+
if (result.aborted) {
|
|
6528
|
+
stopSpinner();
|
|
6529
|
+
process.stdout.write(theme.dim("\n[interrupted]\n"));
|
|
6545
6530
|
}
|
|
6546
|
-
return
|
|
6547
|
-
textContent: textParts.join(""),
|
|
6548
|
-
toolCalls,
|
|
6549
|
-
usage,
|
|
6550
|
-
rawContent,
|
|
6551
|
-
reasoningContent,
|
|
6552
|
-
finishReason
|
|
6553
|
-
};
|
|
6531
|
+
return result;
|
|
6554
6532
|
}
|
|
6555
6533
|
async handleChatWithTools(provider, messages, modelOverride) {
|
|
6556
6534
|
const session = this.sessions.current;
|
|
@@ -6592,25 +6570,7 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6592
6570
|
const autoPauseIntervalRaw = this.config.get("autoPauseInterval");
|
|
6593
6571
|
const autoPauseInterval = typeof autoPauseIntervalRaw === "number" ? autoPauseIntervalRaw : DEFAULT_AUTO_PAUSE_INTERVAL;
|
|
6594
6572
|
const { stable: toolStable, volatile: toolVolatile } = this.buildCurrentSystemPrompt();
|
|
6595
|
-
const
|
|
6596
|
-
- Every ${autoPauseInterval} rounds the user will be asked whether to continue \u2014 use this as a natural checkpoint to report progress.` : "";
|
|
6597
|
-
const roundBudgetHint = this.planMode ? `
|
|
6598
|
-
|
|
6599
|
-
[Tool Round Budget \u2014 Plan Mode]
|
|
6600
|
-
You have a maximum of ${maxToolRounds} tool call rounds. You are in READ-ONLY Plan Mode:
|
|
6601
|
-
- Only use: read_file, list_dir, grep_files, glob_files, ask_user, write_todos
|
|
6602
|
-
- Do NOT attempt to call bash, write_file, edit_file \u2014 they are disabled
|
|
6603
|
-
- Do NOT write shell commands or code blocks as a substitute for tool calls
|
|
6604
|
-
- Do NOT read the same file more than once
|
|
6605
|
-
- Call write_todos ONCE to present your plan, then give a text summary
|
|
6606
|
-
- If the user asks you to execute anything, respond: "Please type /plan execute to switch to execute mode."${pauseHint}` : `
|
|
6607
|
-
|
|
6608
|
-
[Tool Round Budget]
|
|
6609
|
-
You have a maximum of ${maxToolRounds} tool call rounds for this task. Plan efficiently:
|
|
6610
|
-
- Prefer batch operations (e.g. global find-and-replace) over repetitive single edits.
|
|
6611
|
-
- Do NOT read the same file more than once \u2014 use the content from previous reads.
|
|
6612
|
-
- Prioritize the most critical tasks first in case rounds run out.
|
|
6613
|
-
- When remaining rounds are low, focus on completing the current task and summarizing.${pauseHint}`;
|
|
6573
|
+
const roundBudgetHint = buildRoundBudgetHint({ maxToolRounds, autoPauseInterval, planMode: this.planMode });
|
|
6614
6574
|
const systemPrompt = toolStable + TOOL_CALL_REMINDER + roundBudgetHint + (mcpBudgetNote ? `
|
|
6615
6575
|
|
|
6616
6576
|
${mcpBudgetNote}` : "");
|
|
@@ -6620,22 +6580,15 @@ ${mcpBudgetNote}` : "");
|
|
|
6620
6580
|
const spinner = this.renderer.showSpinner("Thinking...");
|
|
6621
6581
|
const roundUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
6622
6582
|
const supportsStreamingTools = useStreaming && typeof provider.chatWithToolsStream === "function";
|
|
6623
|
-
let consecutiveFreeRounds = 0;
|
|
6624
6583
|
let lastToolCallSignature = "";
|
|
6625
6584
|
let repeatedToolCallCount = 0;
|
|
6626
|
-
let emptyResponseRetries = 0;
|
|
6627
|
-
let warnedCtx80 = false;
|
|
6628
6585
|
const roundToolHistory = [];
|
|
6586
|
+
const budgetWarner = new BudgetWarner(maxToolRounds);
|
|
6587
|
+
const emptyGuard = new EmptyResponseGuard();
|
|
6588
|
+
const ctxMonitor = new ContextPressureMonitor();
|
|
6589
|
+
const freeRounds = new FreeRoundTracker();
|
|
6629
6590
|
this.setupInterjectionListener();
|
|
6630
6591
|
try {
|
|
6631
|
-
const warnNoteAt = Math.max(10, Math.floor(maxToolRounds * 0.2));
|
|
6632
|
-
const warnLowAt = Math.max(5, Math.floor(maxToolRounds * 0.1));
|
|
6633
|
-
const warnCriticalAt = Math.max(3, Math.floor(maxToolRounds * 0.05));
|
|
6634
|
-
const warnLowEff = Math.min(warnLowAt, warnNoteAt - 1);
|
|
6635
|
-
const warnCriticalEff = Math.min(warnCriticalAt, warnLowEff - 1);
|
|
6636
|
-
let warnedNote = false;
|
|
6637
|
-
let warnedLow = false;
|
|
6638
|
-
let warnedCritical = false;
|
|
6639
6592
|
for (let round = 0; round < maxToolRounds; round++) {
|
|
6640
6593
|
this.toolExecutor.setRoundInfo(round + 1, maxToolRounds);
|
|
6641
6594
|
if (this.toolExecutor.pendingSlashCommand) {
|
|
@@ -6652,29 +6605,14 @@ ${mcpBudgetNote}` : "");
|
|
|
6652
6605
|
`));
|
|
6653
6606
|
extraMessages.push({ role: "user", content: cmd });
|
|
6654
6607
|
}
|
|
6655
|
-
const
|
|
6656
|
-
if (
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
});
|
|
6662
|
-
process.stdout.write(theme.error(` \u{1F6A8} Critical: ${roundsLeft} rounds remaining
|
|
6663
|
-
`));
|
|
6664
|
-
} else if (!warnedLow && roundsLeft <= warnLowEff) {
|
|
6665
|
-
warnedLow = true;
|
|
6666
|
-
extraMessages.push({
|
|
6667
|
-
role: "user",
|
|
6668
|
-
content: `\u26A0\uFE0F Budget warning: Only ${roundsLeft} tool rounds remaining. Prioritize completing the most critical task. Use efficient approaches (batch edits, fewer reads). If you cannot finish everything, summarize what's done and what remains.`
|
|
6669
|
-
});
|
|
6670
|
-
process.stdout.write(theme.warning(` \u26A0\uFE0F Low budget: ${roundsLeft} rounds remaining
|
|
6608
|
+
const budgetWarning = budgetWarner.check(maxToolRounds - round);
|
|
6609
|
+
if (budgetWarning) {
|
|
6610
|
+
extraMessages.push({ role: "user", content: budgetWarning.injectMessage });
|
|
6611
|
+
if (budgetWarning.displayMessage) {
|
|
6612
|
+
const paint = budgetWarning.level === "critical" ? theme.error : theme.warning;
|
|
6613
|
+
process.stdout.write(paint(` ${budgetWarning.displayMessage}
|
|
6671
6614
|
`));
|
|
6672
|
-
|
|
6673
|
-
warnedNote = true;
|
|
6674
|
-
extraMessages.push({
|
|
6675
|
-
role: "user",
|
|
6676
|
-
content: `\u{1F4CA} Budget note: ${roundsLeft} tool rounds remaining out of ${maxToolRounds}. Plan your remaining work efficiently \u2014 use batch operations (e.g., replaceAll) when possible.`
|
|
6677
|
-
});
|
|
6615
|
+
}
|
|
6678
6616
|
}
|
|
6679
6617
|
if (this._userInterjection) {
|
|
6680
6618
|
const msg = this._userInterjection;
|
|
@@ -6686,13 +6624,13 @@ ${mcpBudgetNote}` : "");
|
|
|
6686
6624
|
const ctxWindow = this.getContextWindowSize();
|
|
6687
6625
|
if (ctxWindow > 0) {
|
|
6688
6626
|
const reqTokens = this.estimateRequestTokens(systemPrompt, extraMessages);
|
|
6689
|
-
const
|
|
6690
|
-
if (
|
|
6627
|
+
const pressure = ctxMonitor.check(reqTokens, ctxWindow);
|
|
6628
|
+
if (pressure.action === "abort") {
|
|
6691
6629
|
spinner.stop();
|
|
6692
6630
|
process.stderr.write(
|
|
6693
6631
|
theme.error(
|
|
6694
6632
|
`
|
|
6695
|
-
\u26A0 Context at ${Math.round(
|
|
6633
|
+
\u26A0 Context at ${Math.round(pressure.ratio * 100)}% of ${fmtTokens(ctxWindow)} \u2014 aborting agentic loop before API rejection.
|
|
6696
6634
|
`
|
|
6697
6635
|
)
|
|
6698
6636
|
);
|
|
@@ -6712,20 +6650,16 @@ ${mcpBudgetNote}` : "");
|
|
|
6712
6650
|
}
|
|
6713
6651
|
}
|
|
6714
6652
|
return;
|
|
6715
|
-
} else if (
|
|
6716
|
-
warnedCtx80 = true;
|
|
6653
|
+
} else if (pressure.action === "warn") {
|
|
6717
6654
|
spinner.stop();
|
|
6718
6655
|
process.stdout.write(
|
|
6719
6656
|
theme.warning(
|
|
6720
6657
|
`
|
|
6721
|
-
\u26A0 Context at ${Math.round(
|
|
6658
|
+
\u26A0 Context at ${Math.round(pressure.ratio * 100)}% of ${fmtTokens(ctxWindow)} \u2014 asking AI to wrap up.
|
|
6722
6659
|
`
|
|
6723
6660
|
)
|
|
6724
6661
|
);
|
|
6725
|
-
extraMessages.push({
|
|
6726
|
-
role: "user",
|
|
6727
|
-
content: `\u26A0\uFE0F Context pressure: ~${Math.round(reqRatio * 100)}% of the ${fmtTokens(ctxWindow)} context window is used. Avoid reading more files or running broad scans. Finish the current critical step, then produce a final summary. Every unnecessary tool call now risks breaking the conversation.`
|
|
6728
|
-
});
|
|
6662
|
+
extraMessages.push({ role: "user", content: pressure.injectMessage });
|
|
6729
6663
|
spinner.start(`Thinking... (round ${round + 1}/${maxToolRounds})`);
|
|
6730
6664
|
}
|
|
6731
6665
|
}
|
|
@@ -6797,12 +6731,7 @@ ${mcpBudgetNote}` : "");
|
|
|
6797
6731
|
(p, m) => p.chatWithTools({ ...chatRequest, model: m }, toolDefs)
|
|
6798
6732
|
);
|
|
6799
6733
|
}
|
|
6800
|
-
|
|
6801
|
-
roundUsage.inputTokens += result.usage.inputTokens;
|
|
6802
|
-
roundUsage.outputTokens += result.usage.outputTokens;
|
|
6803
|
-
roundUsage.cacheCreationTokens += result.usage.cacheCreationTokens ?? 0;
|
|
6804
|
-
roundUsage.cacheReadTokens += result.usage.cacheReadTokens ?? 0;
|
|
6805
|
-
}
|
|
6734
|
+
accumulateUsage(roundUsage, result.usage);
|
|
6806
6735
|
if ("content" in result) {
|
|
6807
6736
|
const hasWriteTools = toolDefs.some((t) => t.name === "write_file" || t.name === "edit_file");
|
|
6808
6737
|
const alreadyWrote = hadPreviousWriteToolCalls(extraMessages);
|
|
@@ -6831,32 +6760,25 @@ ${mcpBudgetNote}` : "");
|
|
|
6831
6760
|
}
|
|
6832
6761
|
if (!result.content || result.content.trim() === "") {
|
|
6833
6762
|
const fr = "finishReason" in result ? result.finishReason : void 0;
|
|
6834
|
-
const
|
|
6835
|
-
if (
|
|
6836
|
-
emptyResponseRetries++;
|
|
6763
|
+
const decision = emptyGuard.onEmpty(round < maxToolRounds - 1, fr);
|
|
6764
|
+
if (decision.action === "nudge") {
|
|
6837
6765
|
spinner.stop();
|
|
6838
6766
|
if (alreadyRendered) process.stdout.write("\n");
|
|
6839
|
-
process.stderr.write(
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
);
|
|
6843
|
-
extraMessages.push({
|
|
6844
|
-
role: "user",
|
|
6845
|
-
content: "Your previous response was empty \u2014 no text and no tool calls. This usually means the context window is nearly full. Please either: (1) continue the task by calling the next tool you need, or (2) give a concise final text summary of what has been accomplished so far and what remains. Do NOT repeat earlier long outputs."
|
|
6846
|
-
});
|
|
6767
|
+
process.stderr.write(theme.warning(`${decision.displayMessage}
|
|
6768
|
+
`));
|
|
6769
|
+
extraMessages.push({ role: "user", content: decision.injectMessage });
|
|
6847
6770
|
spinner.start(`Retrying... (round ${round + 2}/${maxToolRounds})`);
|
|
6848
6771
|
continue;
|
|
6849
6772
|
}
|
|
6850
6773
|
spinner.stop();
|
|
6851
6774
|
if (alreadyRendered) process.stdout.write("\n");
|
|
6852
|
-
const frHint = fr === "length" ? "Output token limit hit \u2014 try /compact to reduce context, raise maxTokens, or /model to switch." : fr === "content_filter" ? "Content was blocked by the provider filter." : "Context window may be exhausted or max_tokens too low.";
|
|
6853
6775
|
process.stderr.write(
|
|
6854
6776
|
theme.error(`
|
|
6855
|
-
|
|
6777
|
+
${decision.displayMessage}
|
|
6856
6778
|
`)
|
|
6857
6779
|
);
|
|
6858
6780
|
process.stderr.write(
|
|
6859
|
-
theme.dim(` ${
|
|
6781
|
+
theme.dim(` ${decision.hint}
|
|
6860
6782
|
Try: /compact, /clear, or /model to switch.
|
|
6861
6783
|
|
|
6862
6784
|
`)
|
|
@@ -6870,7 +6792,7 @@ ${mcpBudgetNote}` : "");
|
|
|
6870
6792
|
}
|
|
6871
6793
|
return;
|
|
6872
6794
|
}
|
|
6873
|
-
|
|
6795
|
+
emptyGuard.onNonEmpty();
|
|
6874
6796
|
spinner.stop();
|
|
6875
6797
|
const finalContent = result.content;
|
|
6876
6798
|
if (!alreadyRendered) {
|
|
@@ -7181,14 +7103,8 @@ ${systemPromptVolatile}` : systemPrompt;
|
|
|
7181
7103
|
});
|
|
7182
7104
|
}
|
|
7183
7105
|
}
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
consecutiveFreeRounds++;
|
|
7187
|
-
if (consecutiveFreeRounds <= MAX_CONSECUTIVE_FREE_ROUNDS) {
|
|
7188
|
-
round--;
|
|
7189
|
-
}
|
|
7190
|
-
} else {
|
|
7191
|
-
consecutiveFreeRounds = 0;
|
|
7106
|
+
if (freeRounds.apply(result.toolCalls.map((tc) => tc.name))) {
|
|
7107
|
+
round--;
|
|
7192
7108
|
}
|
|
7193
7109
|
const currentSignature = result.toolCalls.map((tc) => `${tc.name}:${JSON.stringify(tc.arguments)}`).join("|");
|
|
7194
7110
|
if (currentSignature === lastToolCallSignature) {
|
|
@@ -7226,15 +7142,8 @@ ${systemPromptVolatile}` : systemPrompt;
|
|
|
7226
7142
|
process.stdout.write("\n");
|
|
7227
7143
|
process.stdout.write(theme.warning(`\u23F8 Auto-pause: ${effectiveRound}/${maxToolRounds} rounds used, ${remaining} remaining
|
|
7228
7144
|
`));
|
|
7229
|
-
const
|
|
7230
|
-
if (
|
|
7231
|
-
const toolCounts = /* @__PURE__ */ new Map();
|
|
7232
|
-
for (const rh of recentHistory) {
|
|
7233
|
-
for (const t of rh.tools) {
|
|
7234
|
-
toolCounts.set(t, (toolCounts.get(t) || 0) + 1);
|
|
7235
|
-
}
|
|
7236
|
-
}
|
|
7237
|
-
const summary = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).map(([name, count]) => count > 1 ? `${name}\xD7${count}` : name).join(", ");
|
|
7145
|
+
const summary = summarizeRecentTools(roundToolHistory, autoPauseInterval);
|
|
7146
|
+
if (summary) {
|
|
7238
7147
|
process.stdout.write(theme.dim(` Tools used: ${summary}
|
|
7239
7148
|
`));
|
|
7240
7149
|
}
|
|
@@ -7253,10 +7162,7 @@ ${systemPromptVolatile}` : systemPrompt;
|
|
|
7253
7162
|
this.setupInterjectionListener();
|
|
7254
7163
|
if (pauseResponse === "n" || pauseResponse === "N" || pauseResponse === "\x1B") {
|
|
7255
7164
|
process.stdout.write(theme.warning("\u26A1 Stopped by user at auto-pause checkpoint\n"));
|
|
7256
|
-
extraMessages.push({
|
|
7257
|
-
role: "user",
|
|
7258
|
-
content: `The user has stopped the task at round ${effectiveRound}/${maxToolRounds}. Do not call any more tools. Summarize what has been completed and what remains.`
|
|
7259
|
-
});
|
|
7165
|
+
extraMessages.push({ role: "user", content: buildUserStopMessage(effectiveRound, maxToolRounds) });
|
|
7260
7166
|
break;
|
|
7261
7167
|
} else if (pauseResponse && pauseResponse !== "y" && pauseResponse !== "Y" && pauseResponse !== "") {
|
|
7262
7168
|
process.stdout.write(theme.warning(`\u26A1 Redirect: "${pauseResponse}"
|
|
@@ -7276,13 +7182,7 @@ ${systemPromptVolatile}` : systemPrompt;
|
|
|
7276
7182
|
spinner.start("Generating summary...");
|
|
7277
7183
|
const summaryExtra = [
|
|
7278
7184
|
...extraMessages,
|
|
7279
|
-
{
|
|
7280
|
-
role: "user",
|
|
7281
|
-
content: `You have used all ${maxToolRounds} tool call rounds. Do not call any more tools. Summarize in text:
|
|
7282
|
-
1. What work has been completed so far
|
|
7283
|
-
2. What tasks remain unfinished
|
|
7284
|
-
3. What the user can do next (e.g. send another request to continue)`
|
|
7285
|
-
}
|
|
7185
|
+
{ role: "user", content: buildRoundsExhaustedPrompt(maxToolRounds) }
|
|
7286
7186
|
];
|
|
7287
7187
|
const summaryResult = await provider.chatWithTools(
|
|
7288
7188
|
{
|
|
@@ -7633,7 +7533,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7633
7533
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7634
7534
|
process.exit(1);
|
|
7635
7535
|
}
|
|
7636
|
-
const { startWebServer } = await import("./server-
|
|
7536
|
+
const { startWebServer } = await import("./server-2CBNRT2W.js");
|
|
7637
7537
|
await startWebServer({ port, host: options.host });
|
|
7638
7538
|
});
|
|
7639
7539
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -7800,12 +7700,12 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7800
7700
|
console.log(footer + "\n");
|
|
7801
7701
|
});
|
|
7802
7702
|
program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
|
|
7803
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7703
|
+
const { runDoctorCli } = await import("./doctor-cli-KSB3MLFV.js");
|
|
7804
7704
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7805
7705
|
});
|
|
7806
7706
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
7807
7707
|
try {
|
|
7808
|
-
const batch = await import("./batch-
|
|
7708
|
+
const batch = await import("./batch-ZBKVDSMZ.js");
|
|
7809
7709
|
switch (action) {
|
|
7810
7710
|
case "submit":
|
|
7811
7711
|
if (!arg) {
|
|
@@ -7848,7 +7748,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7848
7748
|
}
|
|
7849
7749
|
});
|
|
7850
7750
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
7851
|
-
const { startMcpServer } = await import("./server-
|
|
7751
|
+
const { startMcpServer } = await import("./server-TXA5VTOS.js");
|
|
7852
7752
|
await startMcpServer({
|
|
7853
7753
|
allowDestructive: !!options.allowDestructive,
|
|
7854
7754
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7857,7 +7757,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7857
7757
|
});
|
|
7858
7758
|
});
|
|
7859
7759
|
program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).option("--base <ref>", "Base ref for `git diff <ref>...HEAD` (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").action(async (options) => {
|
|
7860
|
-
const { runCi } = await import("./ci-
|
|
7760
|
+
const { runCi } = await import("./ci-6WGF6ID6.js");
|
|
7861
7761
|
const result = await runCi({
|
|
7862
7762
|
pr: options.pr,
|
|
7863
7763
|
base: options.base,
|
|
@@ -8002,7 +7902,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
8002
7902
|
}),
|
|
8003
7903
|
config.get("customProviders")
|
|
8004
7904
|
);
|
|
8005
|
-
const { startHub } = await import("./hub-
|
|
7905
|
+
const { startHub } = await import("./hub-DGEYFJPP.js");
|
|
8006
7906
|
await startHub(
|
|
8007
7907
|
{
|
|
8008
7908
|
topic: topic ?? "",
|