dskcode 0.1.30 → 0.1.33
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/{chunk-UV4IWYHZ.js → chunk-LWOBXEMJ.js} +9 -9
- package/dist/{chunk-UV4IWYHZ.js.map → chunk-LWOBXEMJ.js.map} +1 -1
- package/dist/deepseek-WFSVA5UQ.js +9 -0
- package/dist/index.js +1766 -793
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/deepseek-PGX76BK5.js +0 -7
- /package/dist/{deepseek-PGX76BK5.js.map → deepseek-WFSVA5UQ.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
estimateTokens,
|
|
8
8
|
getModelMeta,
|
|
9
9
|
isSupportedModel
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-LWOBXEMJ.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/index.tsx
|
|
13
13
|
import { Command } from "commander";
|
|
@@ -805,7 +805,7 @@ var LOGO_LINES = [
|
|
|
805
805
|
];
|
|
806
806
|
|
|
807
807
|
// src/ui/ChatSession.tsx
|
|
808
|
-
import { Box as
|
|
808
|
+
import { Box as Box10, Text as Text11, useInput, Static } from "ink";
|
|
809
809
|
import TextInput from "ink-text-input";
|
|
810
810
|
import { useEffect as useEffect4, useState as useState4, useCallback as useCallback2, useMemo, useRef as useRef3 } from "react";
|
|
811
811
|
|
|
@@ -838,7 +838,7 @@ function useDoubleCtrlC(onExit) {
|
|
|
838
838
|
}
|
|
839
839
|
|
|
840
840
|
// src/ui/ChatSession.tsx
|
|
841
|
-
import
|
|
841
|
+
import InkSpinner3 from "ink-spinner";
|
|
842
842
|
|
|
843
843
|
// src/ui/AssistantMessage.tsx
|
|
844
844
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
@@ -1175,21 +1175,20 @@ function formatArgsSummary(args) {
|
|
|
1175
1175
|
return ` ${truncated}`;
|
|
1176
1176
|
}
|
|
1177
1177
|
}
|
|
1178
|
-
function ToolCallBlock({ call
|
|
1178
|
+
function ToolCallBlock({ call }) {
|
|
1179
1179
|
const argsDisplay = formatArgsSummary(call.arguments);
|
|
1180
1180
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: [
|
|
1181
1181
|
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
1182
|
-
/* @__PURE__ */ jsxs3(Text4, {
|
|
1182
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
1183
1183
|
"\u{1F4E6} ",
|
|
1184
1184
|
call.name
|
|
1185
1185
|
] }),
|
|
1186
|
-
/* @__PURE__ */ jsxs3(Text4, {
|
|
1186
|
+
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
1187
1187
|
" ",
|
|
1188
1188
|
"\u2500".repeat(Math.max(1, 30 - call.name.length))
|
|
1189
1189
|
] })
|
|
1190
1190
|
] }),
|
|
1191
|
-
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, {
|
|
1192
|
-
showPendingHint && /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text4, { color: "yellow", children: "\u23F3 \u7B49\u5F85\u6267\u884C" }) })
|
|
1191
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay }) })
|
|
1193
1192
|
] });
|
|
1194
1193
|
}
|
|
1195
1194
|
|
|
@@ -1278,6 +1277,226 @@ function formatUsageSummary(usage) {
|
|
|
1278
1277
|
|
|
1279
1278
|
// src/ui/HighlightedText.tsx
|
|
1280
1279
|
import { Box as Box4, Text as Text5 } from "ink";
|
|
1280
|
+
|
|
1281
|
+
// src/ui/table-layout.ts
|
|
1282
|
+
var TABLE_MIN_COL_WIDTH = 3;
|
|
1283
|
+
var DEFAULT_TERM_WIDTH = 80;
|
|
1284
|
+
var TABLE_MARGIN = 2;
|
|
1285
|
+
function cpWidth(cp2) {
|
|
1286
|
+
if (cp2 >= 4352 && cp2 <= 4447 || // Hangul Jamo
|
|
1287
|
+
cp2 === 9001 || cp2 === 9002 || cp2 >= 11904 && cp2 <= 42191 || // CJK Radicals ~ Yi
|
|
1288
|
+
cp2 >= 43360 && cp2 <= 43391 || // Hangul Extended
|
|
1289
|
+
cp2 >= 44032 && cp2 <= 55215 || // Hangul Syllables
|
|
1290
|
+
cp2 >= 63744 && cp2 <= 64255 || // CJK Compat
|
|
1291
|
+
cp2 >= 65040 && cp2 <= 65055 || // Vertical forms
|
|
1292
|
+
cp2 >= 65281 && cp2 <= 65376 || // Fullwidth ASCII / 标点
|
|
1293
|
+
cp2 >= 65504 && cp2 <= 65510 || // Fullwidth signs
|
|
1294
|
+
cp2 >= 126976 && cp2 <= 131071 || // Emoji / Symbols
|
|
1295
|
+
cp2 >= 12288 && cp2 <= 12351 || // CJK Symbols & Punctuation(含「、。·」等)
|
|
1296
|
+
cp2 >= 131072 && cp2 <= 196607) {
|
|
1297
|
+
return 2;
|
|
1298
|
+
}
|
|
1299
|
+
if (cp2 < 32 || cp2 >= 127 && cp2 < 160) return 0;
|
|
1300
|
+
return 1;
|
|
1301
|
+
}
|
|
1302
|
+
function visualWidth(text) {
|
|
1303
|
+
let w = 0;
|
|
1304
|
+
for (const ch of text) {
|
|
1305
|
+
const cp2 = ch.codePointAt(0);
|
|
1306
|
+
if (cp2 === void 0) continue;
|
|
1307
|
+
if (cp2 === 8205) continue;
|
|
1308
|
+
if (cp2 >= 65024 && cp2 <= 65039) continue;
|
|
1309
|
+
w += cpWidth(cp2);
|
|
1310
|
+
}
|
|
1311
|
+
return w;
|
|
1312
|
+
}
|
|
1313
|
+
function* iterateChars(text) {
|
|
1314
|
+
for (const ch of text) {
|
|
1315
|
+
const cp2 = ch.codePointAt(0);
|
|
1316
|
+
if (cp2 === void 0) continue;
|
|
1317
|
+
if (cp2 === 8205) continue;
|
|
1318
|
+
if (cp2 >= 65024 && cp2 <= 65039) continue;
|
|
1319
|
+
yield { ch, width: cpWidth(cp2) };
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
function wrapByWidth(text, maxWidth) {
|
|
1323
|
+
if (maxWidth <= 0) return [text];
|
|
1324
|
+
const out = [];
|
|
1325
|
+
for (const para of text.split("\n")) {
|
|
1326
|
+
if (para.length === 0) {
|
|
1327
|
+
out.push("");
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
const wrapped = wrapOneLine(para, maxWidth);
|
|
1331
|
+
for (const w of wrapped) out.push(w);
|
|
1332
|
+
}
|
|
1333
|
+
return out.length === 0 ? [""] : out;
|
|
1334
|
+
}
|
|
1335
|
+
function wrapOneLine(text, maxWidth) {
|
|
1336
|
+
if (visualWidth(text) <= maxWidth) return [text];
|
|
1337
|
+
const lines = [];
|
|
1338
|
+
let current = "";
|
|
1339
|
+
let currentW = 0;
|
|
1340
|
+
let breakCandidate = -1;
|
|
1341
|
+
let breakCandidateW = 0;
|
|
1342
|
+
for (const { ch, width } of iterateChars(text)) {
|
|
1343
|
+
if (ch === " " || ch === " ") {
|
|
1344
|
+
breakCandidate = current.length;
|
|
1345
|
+
breakCandidateW = currentW + width;
|
|
1346
|
+
current += ch;
|
|
1347
|
+
currentW += width;
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
if (currentW + width > maxWidth) {
|
|
1351
|
+
if (breakCandidate > 0) {
|
|
1352
|
+
const split = current.slice(0, breakCandidate).replace(/[ \t]+$/, "");
|
|
1353
|
+
lines.push(split);
|
|
1354
|
+
const rest = current.slice(breakCandidate).replace(/^[ \t]+/, "");
|
|
1355
|
+
current = rest + ch;
|
|
1356
|
+
currentW = visualWidth(current);
|
|
1357
|
+
breakCandidate = -1;
|
|
1358
|
+
breakCandidateW = 0;
|
|
1359
|
+
} else {
|
|
1360
|
+
lines.push(current);
|
|
1361
|
+
current = ch;
|
|
1362
|
+
currentW = width;
|
|
1363
|
+
}
|
|
1364
|
+
} else {
|
|
1365
|
+
current += ch;
|
|
1366
|
+
currentW += width;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
if (current.length > 0) lines.push(current);
|
|
1370
|
+
return lines;
|
|
1371
|
+
}
|
|
1372
|
+
function wrapRowCells(cells, colWidths, alignments) {
|
|
1373
|
+
return cells.map((cell, ci) => {
|
|
1374
|
+
const w = colWidths[ci] ?? TABLE_MIN_COL_WIDTH;
|
|
1375
|
+
const lines = wrapByWidth(cell, w);
|
|
1376
|
+
return lines.map((l) => padToWidth(l, w, alignments[ci] ?? "left"));
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
function padToWidth(text, targetWidth, align = "left") {
|
|
1380
|
+
const vw = visualWidth(text);
|
|
1381
|
+
const delta = targetWidth - vw;
|
|
1382
|
+
if (delta <= 0) return text;
|
|
1383
|
+
const leftPad = align === "right" ? delta : align === "center" ? Math.floor(delta / 2) : 0;
|
|
1384
|
+
const rightPad = delta - leftPad;
|
|
1385
|
+
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
|
1386
|
+
}
|
|
1387
|
+
function parseTableCells(line) {
|
|
1388
|
+
const t = line.trim();
|
|
1389
|
+
if (!t.startsWith("|") || !t.endsWith("|")) return [];
|
|
1390
|
+
const inner = t.slice(1, t.length - 1);
|
|
1391
|
+
return inner.split("|").map((c) => c.trim());
|
|
1392
|
+
}
|
|
1393
|
+
function parseAlignments(sepLine) {
|
|
1394
|
+
return parseTableCells(sepLine).map((c) => {
|
|
1395
|
+
const l = c.startsWith(":");
|
|
1396
|
+
const r = c.endsWith(":");
|
|
1397
|
+
if (l && r) return "center";
|
|
1398
|
+
if (r) return "right";
|
|
1399
|
+
return "left";
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
function layoutTable(text, options = {}) {
|
|
1403
|
+
const termWidth = options.termWidth ?? DEFAULT_TERM_WIDTH;
|
|
1404
|
+
const outerMargin = options.outerMargin ?? 0;
|
|
1405
|
+
const usable = Math.max(termWidth - outerMargin, 20);
|
|
1406
|
+
const rawLines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
1407
|
+
if (rawLines.length < 2) {
|
|
1408
|
+
return { lines: rawLines, colWidths: [], totalWidth: 0 };
|
|
1409
|
+
}
|
|
1410
|
+
let sepIdx = -1;
|
|
1411
|
+
for (let k = 0; k < rawLines.length; k++) {
|
|
1412
|
+
const t = (rawLines[k] ?? "").trim();
|
|
1413
|
+
if (/^\|[-: |]+\|$/.test(t) && t.includes("-")) {
|
|
1414
|
+
sepIdx = k;
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
if (sepIdx === -1) {
|
|
1419
|
+
return { lines: rawLines, colWidths: [], totalWidth: 0 };
|
|
1420
|
+
}
|
|
1421
|
+
const headerCells = parseTableCells(rawLines.slice(0, sepIdx).join(""));
|
|
1422
|
+
const alignments = parseAlignments(rawLines[sepIdx] ?? "");
|
|
1423
|
+
const dataRows = rawLines.slice(sepIdx + 1).map(parseTableCells);
|
|
1424
|
+
const colCount = headerCells.length;
|
|
1425
|
+
if (colCount === 0) {
|
|
1426
|
+
return { lines: rawLines, colWidths: [], totalWidth: 0 };
|
|
1427
|
+
}
|
|
1428
|
+
const colMaxWidths = [];
|
|
1429
|
+
for (let ci = 0; ci < colCount; ci++) {
|
|
1430
|
+
let max = visualWidth(headerCells[ci] ?? "");
|
|
1431
|
+
for (const row of dataRows) {
|
|
1432
|
+
const w = visualWidth(row[ci] ?? "");
|
|
1433
|
+
if (w > max) max = w;
|
|
1434
|
+
}
|
|
1435
|
+
colMaxWidths.push(Math.max(max, TABLE_MIN_COL_WIDTH));
|
|
1436
|
+
}
|
|
1437
|
+
const margin = TABLE_MARGIN;
|
|
1438
|
+
const totalMinWidth = colMaxWidths.reduce((s, w) => s + w + margin, 1);
|
|
1439
|
+
let colWidths;
|
|
1440
|
+
if (totalMinWidth <= usable) {
|
|
1441
|
+
colWidths = colMaxWidths;
|
|
1442
|
+
} else {
|
|
1443
|
+
const available = usable - 1 - margin * colCount;
|
|
1444
|
+
const sum = colMaxWidths.reduce((s, w) => s + w, 0);
|
|
1445
|
+
colWidths = colMaxWidths.map(
|
|
1446
|
+
(w) => Math.max(TABLE_MIN_COL_WIDTH, Math.floor(w / sum * available))
|
|
1447
|
+
);
|
|
1448
|
+
let total = colWidths.reduce((s, w) => s + w + margin, 1);
|
|
1449
|
+
while (total > usable && colWidths.length > 0) {
|
|
1450
|
+
const last = colWidths.length - 1;
|
|
1451
|
+
const cur = colWidths[last] ?? TABLE_MIN_COL_WIDTH;
|
|
1452
|
+
if (cur <= TABLE_MIN_COL_WIDTH) break;
|
|
1453
|
+
colWidths[last] = cur - 1;
|
|
1454
|
+
total = colWidths.reduce((s, w) => s + w + margin, 1);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
const H = "\u2500";
|
|
1458
|
+
const makeSep = (l, m, r) => l + colWidths.map((w) => H.repeat(w + margin)).join(m) + r;
|
|
1459
|
+
const topBorder = makeSep("\u250C", "\u252C", "\u2510");
|
|
1460
|
+
const midBorder = makeSep("\u251C", "\u253C", "\u2524");
|
|
1461
|
+
const botBorder = makeSep("\u2514", "\u2534", "\u2518");
|
|
1462
|
+
function buildRow(cells) {
|
|
1463
|
+
const wrapped = wrapRowCells(cells, colWidths, alignments);
|
|
1464
|
+
const rowHeight = Math.max(1, ...wrapped.map((lines2) => lines2.length));
|
|
1465
|
+
const lines = [];
|
|
1466
|
+
for (let li = 0; li < rowHeight; li++) {
|
|
1467
|
+
let row = "\u2502";
|
|
1468
|
+
for (let ci = 0; ci < colCount; ci++) {
|
|
1469
|
+
const cellLines = wrapped[ci] ?? [];
|
|
1470
|
+
const segment = cellLines[li] ?? " ".repeat(colWidths[ci] ?? TABLE_MIN_COL_WIDTH);
|
|
1471
|
+
row += " " + segment + " ";
|
|
1472
|
+
if (ci < colCount - 1) row += "\u2502";
|
|
1473
|
+
}
|
|
1474
|
+
row += "\u2502";
|
|
1475
|
+
lines.push(row);
|
|
1476
|
+
}
|
|
1477
|
+
return lines;
|
|
1478
|
+
}
|
|
1479
|
+
const headerRow = buildRow(headerCells);
|
|
1480
|
+
const dataRowsOut = dataRows.map(buildRow);
|
|
1481
|
+
const totalWidth = colWidths.reduce((s, w) => s + w + margin, 1);
|
|
1482
|
+
return {
|
|
1483
|
+
lines: [
|
|
1484
|
+
topBorder,
|
|
1485
|
+
...headerRow,
|
|
1486
|
+
midBorder,
|
|
1487
|
+
...dataRowsOut.flat(),
|
|
1488
|
+
botBorder
|
|
1489
|
+
],
|
|
1490
|
+
colWidths,
|
|
1491
|
+
totalWidth
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function detectTermWidth() {
|
|
1495
|
+
const c = process.stdout?.columns;
|
|
1496
|
+
return typeof c === "number" && c > 0 ? c : void 0;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// src/ui/HighlightedText.tsx
|
|
1281
1500
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1282
1501
|
function parseCodeBlocks(text) {
|
|
1283
1502
|
const segments = [];
|
|
@@ -1450,111 +1669,19 @@ function CodeBlockRenderer({ code }) {
|
|
|
1450
1669
|
})
|
|
1451
1670
|
] });
|
|
1452
1671
|
}
|
|
1453
|
-
var TABLE_MAX_WIDTH = 90;
|
|
1454
|
-
var TABLE_MIN_COL_WIDTH = 3;
|
|
1455
|
-
function charWidth(ch) {
|
|
1456
|
-
const cp2 = ch.codePointAt(0);
|
|
1457
|
-
if (cp2 === void 0) return 0;
|
|
1458
|
-
if (cp2 >= 4352 && cp2 <= 4447 || // Hangul Jamo
|
|
1459
|
-
cp2 === 9001 || cp2 === 9002 || cp2 >= 11904 && cp2 <= 42191 || // CJK Radicals ~ Yi
|
|
1460
|
-
cp2 >= 43360 && cp2 <= 43391 || // Hangul Extended
|
|
1461
|
-
cp2 >= 44032 && cp2 <= 55215 || // Hangul Syllables
|
|
1462
|
-
cp2 >= 63744 && cp2 <= 64255 || // CJK Compat
|
|
1463
|
-
cp2 >= 65040 && cp2 <= 65055 || // Vertical forms
|
|
1464
|
-
cp2 >= 65281 && cp2 <= 65376 || // Fullwidth
|
|
1465
|
-
cp2 >= 65504 && cp2 <= 65510 || cp2 >= 126976 && cp2 <= 131071) {
|
|
1466
|
-
return 2;
|
|
1467
|
-
}
|
|
1468
|
-
return 1;
|
|
1469
|
-
}
|
|
1470
|
-
function visualWidth(text) {
|
|
1471
|
-
let w = 0;
|
|
1472
|
-
for (const ch of text) {
|
|
1473
|
-
w += charWidth(ch);
|
|
1474
|
-
}
|
|
1475
|
-
return w;
|
|
1476
|
-
}
|
|
1477
|
-
function padToWidth(text, targetWidth, align) {
|
|
1478
|
-
const vw = visualWidth(text);
|
|
1479
|
-
const delta = targetWidth - vw;
|
|
1480
|
-
if (delta <= 0) return text;
|
|
1481
|
-
const leftPad = align === "right" ? delta : align === "center" ? Math.floor(delta / 2) : 0;
|
|
1482
|
-
const rightPad = delta - leftPad;
|
|
1483
|
-
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
|
1484
|
-
}
|
|
1485
|
-
function parseTableCells(line) {
|
|
1486
|
-
const t = line.trim();
|
|
1487
|
-
const inner = t.slice(1, t.length - 1);
|
|
1488
|
-
return inner.split("|").map((c) => c.trim());
|
|
1489
|
-
}
|
|
1490
|
-
function parseAlignments(sepLine) {
|
|
1491
|
-
const cells = parseTableCells(sepLine);
|
|
1492
|
-
return cells.map((c) => {
|
|
1493
|
-
const l = c.startsWith(":");
|
|
1494
|
-
const r = c.endsWith(":");
|
|
1495
|
-
if (l && r) return "center";
|
|
1496
|
-
if (r) return "right";
|
|
1497
|
-
return "left";
|
|
1498
|
-
});
|
|
1499
|
-
}
|
|
1500
1672
|
function TableRenderer({ text }) {
|
|
1501
|
-
const
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
const alignments = parseAlignments(rawLines[sepIdx]);
|
|
1514
|
-
const dataRows = rawLines.slice(sepIdx + 1).map(parseTableCells);
|
|
1515
|
-
const colCount = headerCells.length;
|
|
1516
|
-
const colMaxWidths = headerCells.map((_, ci) => {
|
|
1517
|
-
let max = visualWidth(headerCells[ci] ?? "");
|
|
1518
|
-
for (const row of dataRows) {
|
|
1519
|
-
const w = visualWidth(row[ci] ?? "");
|
|
1520
|
-
if (w > max) max = w;
|
|
1521
|
-
}
|
|
1522
|
-
return Math.max(max, TABLE_MIN_COL_WIDTH);
|
|
1523
|
-
});
|
|
1524
|
-
const margin = 2;
|
|
1525
|
-
const totalMinWidth = colMaxWidths.reduce((s, w) => s + w + margin, 1);
|
|
1526
|
-
let colWidths;
|
|
1527
|
-
if (totalMinWidth <= TABLE_MAX_WIDTH) {
|
|
1528
|
-
colWidths = colMaxWidths;
|
|
1529
|
-
} else {
|
|
1530
|
-
const available = TABLE_MAX_WIDTH - 1 - margin * colCount;
|
|
1531
|
-
const sum = colMaxWidths.reduce((s, w) => s + w, 0);
|
|
1532
|
-
colWidths = colMaxWidths.map((w) => Math.max(TABLE_MIN_COL_WIDTH, Math.floor(w / sum * available)));
|
|
1533
|
-
}
|
|
1534
|
-
const H = "\u2500";
|
|
1535
|
-
const makeSep = (l, m, r) => l + colWidths.map((w) => H.repeat(w + margin)).join(m) + r;
|
|
1536
|
-
const topBorder = makeSep("\u250C", "\u252C", "\u2510");
|
|
1537
|
-
const midBorder = makeSep("\u251C", "\u253C", "\u2524");
|
|
1538
|
-
const botBorder = makeSep("\u2514", "\u2534", "\u2518");
|
|
1539
|
-
function rowLine(cells, keyBase) {
|
|
1540
|
-
return /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
1541
|
-
"\u2502",
|
|
1542
|
-
cells.map((cell, ci) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
1543
|
-
" ",
|
|
1544
|
-
padToWidth(cell.slice(0, colWidths[ci] ?? TABLE_MIN_COL_WIDTH), colWidths[ci] ?? TABLE_MIN_COL_WIDTH, alignments[ci] ?? "left"),
|
|
1545
|
-
" ",
|
|
1546
|
-
"\u2502"
|
|
1547
|
-
] }, ci))
|
|
1548
|
-
] }, keyBase);
|
|
1549
|
-
}
|
|
1550
|
-
const rows = [
|
|
1551
|
-
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: topBorder }, "top"),
|
|
1552
|
-
rowLine(headerCells, "hdr"),
|
|
1553
|
-
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: midBorder }, "mid"),
|
|
1554
|
-
...dataRows.map((cells, ri) => rowLine(cells, `d${ri}`)),
|
|
1555
|
-
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: botBorder }, "bot")
|
|
1556
|
-
];
|
|
1557
|
-
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginTop: 1, children: rows });
|
|
1673
|
+
const termWidth = detectTermWidth();
|
|
1674
|
+
const layout = layoutTable(text, { termWidth });
|
|
1675
|
+
if (layout.colWidths.length === 0) {
|
|
1676
|
+
return /* @__PURE__ */ jsx4(Text5, { children: text });
|
|
1677
|
+
}
|
|
1678
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginTop: 1, children: layout.lines.map((line, i) => {
|
|
1679
|
+
const isFirst = i === 0;
|
|
1680
|
+
const isLast = i === layout.lines.length - 1;
|
|
1681
|
+
const isMid = !isFirst && !isLast && line.startsWith("\u251C");
|
|
1682
|
+
const color = isFirst || isLast || isMid ? "#888888" : void 0;
|
|
1683
|
+
return /* @__PURE__ */ jsx4(Text5, { color, children: line }, i);
|
|
1684
|
+
}) });
|
|
1558
1685
|
}
|
|
1559
1686
|
var EMOJI_CP_RE = /[\u{1F000}-\u{1FFFF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}\u{2600}-\u{27BF}\u{231A}-\u{23FF}\u{2934}\u{2935}\u{25AA}-\u{25FE}\u{2B50}\u{2B55}\u{00A9}\u{00AE}\u{2122}\u{3030}\u{303D}\u{3297}\u{3299}]/u;
|
|
1560
1687
|
function isEmojiCluster(text) {
|
|
@@ -1674,6 +1801,23 @@ function HighlightedText({ children: text }) {
|
|
|
1674
1801
|
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: rendered });
|
|
1675
1802
|
}
|
|
1676
1803
|
|
|
1804
|
+
// src/ui/reasoning-utils.ts
|
|
1805
|
+
var DEFAULT_REASONING_MAX_LINES = 8;
|
|
1806
|
+
function joinReasoningSegments(segments) {
|
|
1807
|
+
return segments.map((s) => s.trim()).filter((s) => s.length > 0).join("\n");
|
|
1808
|
+
}
|
|
1809
|
+
function truncateReasoningLines(text, maxLines) {
|
|
1810
|
+
const lines = text.split("\n");
|
|
1811
|
+
if (lines.length <= maxLines) {
|
|
1812
|
+
return { visible: text, hiddenLines: 0, totalLines: lines.length };
|
|
1813
|
+
}
|
|
1814
|
+
return {
|
|
1815
|
+
visible: lines.slice(-maxLines).join("\n"),
|
|
1816
|
+
hiddenLines: lines.length - maxLines,
|
|
1817
|
+
totalLines: lines.length
|
|
1818
|
+
};
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1677
1821
|
// src/ui/AssistantMessage.tsx
|
|
1678
1822
|
import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1679
1823
|
function formatElapsed(ms) {
|
|
@@ -1707,10 +1851,7 @@ function AnimatedUsage({ usage, cost }) {
|
|
|
1707
1851
|
}
|
|
1708
1852
|
const tokensDelta = targetTokens - displayedTokens;
|
|
1709
1853
|
const costDelta = targetCost - displayedCost;
|
|
1710
|
-
const durationMs = Math.min(
|
|
1711
|
-
600,
|
|
1712
|
-
Math.max(220, Math.max(tokensDelta, 0) * 1.2 + 220)
|
|
1713
|
-
);
|
|
1854
|
+
const durationMs = Math.min(600, Math.max(220, Math.max(tokensDelta, 0) * 1.2 + 220));
|
|
1714
1855
|
startRef.current = {
|
|
1715
1856
|
fromTokens: displayedTokens,
|
|
1716
1857
|
fromCost: displayedCost,
|
|
@@ -1761,6 +1902,7 @@ function AnimatedUsage({ usage, cost }) {
|
|
|
1761
1902
|
}
|
|
1762
1903
|
function AssistantMessage({
|
|
1763
1904
|
content,
|
|
1905
|
+
reasoning,
|
|
1764
1906
|
toolCalls,
|
|
1765
1907
|
isStreaming = false,
|
|
1766
1908
|
usage,
|
|
@@ -1768,21 +1910,43 @@ function AssistantMessage({
|
|
|
1768
1910
|
cost,
|
|
1769
1911
|
model: _model
|
|
1770
1912
|
}) {
|
|
1771
|
-
if (!content && (!toolCalls || toolCalls.length === 0) && !isStreaming) {
|
|
1913
|
+
if (!content && (!toolCalls || toolCalls.length === 0) && (!reasoning || reasoning.length === 0) && !isStreaming) {
|
|
1772
1914
|
return null;
|
|
1773
1915
|
}
|
|
1774
1916
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
1917
|
+
reasoning && reasoning.length > 0 && (() => {
|
|
1918
|
+
const merged = joinReasoningSegments(reasoning);
|
|
1919
|
+
if (!merged) return null;
|
|
1920
|
+
const { visible } = truncateReasoningLines(
|
|
1921
|
+
merged,
|
|
1922
|
+
DEFAULT_REASONING_MAX_LINES
|
|
1923
|
+
);
|
|
1924
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", marginBottom: 1, children: [
|
|
1925
|
+
/* @__PURE__ */ jsx5(Box5, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { dimColor: true, children: "\u{1F9E0}" }) }),
|
|
1926
|
+
/* @__PURE__ */ jsx5(
|
|
1927
|
+
Box5,
|
|
1928
|
+
{
|
|
1929
|
+
flexGrow: 1,
|
|
1930
|
+
flexDirection: "column",
|
|
1931
|
+
borderStyle: "single",
|
|
1932
|
+
borderColor: "#444444",
|
|
1933
|
+
paddingLeft: 1,
|
|
1934
|
+
paddingRight: 1,
|
|
1935
|
+
children: /* @__PURE__ */ jsx5(Text6, { dimColor: true, wrap: "wrap", children: visible })
|
|
1936
|
+
}
|
|
1937
|
+
)
|
|
1938
|
+
] });
|
|
1939
|
+
})(),
|
|
1775
1940
|
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", children: [
|
|
1776
1941
|
/* @__PURE__ */ jsx5(Box5, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#ff00ff", children: "\u{1F916}" }) }),
|
|
1777
1942
|
/* @__PURE__ */ jsxs5(Box5, { flexGrow: 1, flexDirection: "column", children: [
|
|
1778
1943
|
content && /* @__PURE__ */ jsx5(HighlightedText, { children: content }),
|
|
1779
|
-
isStreaming && !content && /* @__PURE__ */ jsx5(Text6, { color: "#888888", children: "..." })
|
|
1944
|
+
isStreaming && !content && (!reasoning || reasoning.length === 0) && /* @__PURE__ */ jsx5(Text6, { color: "#888888", children: "..." })
|
|
1780
1945
|
] })
|
|
1781
1946
|
] }),
|
|
1782
1947
|
toolCalls && toolCalls.length > 0 && /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: toolCalls.map((tc, i) => /* @__PURE__ */ jsx5(ToolCallBlock, { call: tc }, tc.id ?? i)) }),
|
|
1783
1948
|
isStreaming && (usage || cost !== void 0) && /* @__PURE__ */ jsx5(Box5, { flexDirection: "row", marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs5(Text6, { color: "#666666", dimColor: true, children: [
|
|
1784
|
-
"\u23F3 \u5DF2\u6D88\u8017",
|
|
1785
|
-
" ",
|
|
1949
|
+
"\u23F3 \u5DF2\u6D88\u8017 ",
|
|
1786
1950
|
/* @__PURE__ */ jsx5(AnimatedUsage, { usage, cost })
|
|
1787
1951
|
] }) }),
|
|
1788
1952
|
!isStreaming && (usage || elapsed !== void 0) && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, marginLeft: 3, children: [
|
|
@@ -1891,6 +2055,49 @@ function FileSelector({ files, input, selectedIndex }) {
|
|
|
1891
2055
|
] });
|
|
1892
2056
|
}
|
|
1893
2057
|
|
|
2058
|
+
// src/ui/TodoListPanel.tsx
|
|
2059
|
+
import { Box as Box9, Text as Text10 } from "ink";
|
|
2060
|
+
import InkSpinner2 from "ink-spinner";
|
|
2061
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2062
|
+
function statusIcon(status) {
|
|
2063
|
+
switch (status) {
|
|
2064
|
+
case "pending":
|
|
2065
|
+
return "\u2610";
|
|
2066
|
+
case "done":
|
|
2067
|
+
return "\u2611";
|
|
2068
|
+
case "failed":
|
|
2069
|
+
return "\u2717";
|
|
2070
|
+
case "skipped":
|
|
2071
|
+
return "\u2298";
|
|
2072
|
+
// running 不走这里,由 TodoIcon 走 Spinner 组件
|
|
2073
|
+
case "running":
|
|
2074
|
+
return "\u25B6";
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
function TodoIcon({ status }) {
|
|
2078
|
+
if (status === "running") {
|
|
2079
|
+
return /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: /* @__PURE__ */ jsx9(InkSpinner2, { type: "dots" }) });
|
|
2080
|
+
}
|
|
2081
|
+
if (status === "done") {
|
|
2082
|
+
return /* @__PURE__ */ jsx9(Text10, { color: "green", children: "\u2705" });
|
|
2083
|
+
}
|
|
2084
|
+
if (status === "failed") {
|
|
2085
|
+
return /* @__PURE__ */ jsx9(Text10, { color: "red", children: statusIcon(status) });
|
|
2086
|
+
}
|
|
2087
|
+
return /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: statusIcon(status) });
|
|
2088
|
+
}
|
|
2089
|
+
function TodoListPanel({ items }) {
|
|
2090
|
+
if (items.length === 0) return null;
|
|
2091
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, children: [
|
|
2092
|
+
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u{1F527} \u4EFB\u52A1\u8FDB\u5EA6" }) }),
|
|
2093
|
+
items.map((it) => /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2094
|
+
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " " }),
|
|
2095
|
+
/* @__PURE__ */ jsx9(TodoIcon, { status: it.status }),
|
|
2096
|
+
/* @__PURE__ */ jsx9(Text10, { dimColor: true, children: ` ${it.content}` })
|
|
2097
|
+
] }, it.id))
|
|
2098
|
+
] });
|
|
2099
|
+
}
|
|
2100
|
+
|
|
1894
2101
|
// src/provider/registry.ts
|
|
1895
2102
|
var ProviderRegistry = class {
|
|
1896
2103
|
#factories = /* @__PURE__ */ new Map();
|
|
@@ -1985,10 +2192,10 @@ var AlwaysAllowGate = class {
|
|
|
1985
2192
|
import Handlebars from "handlebars";
|
|
1986
2193
|
|
|
1987
2194
|
// src/agent/prompts/system-prompt.hbs
|
|
1988
|
-
var system_prompt_default = '\u4F60\u662F dskcode\uFF0C\u4E00\u4E2A\u57FA\u4E8E DeepSeek \u7684 AI \u7F16\u7A0B\u52A9\u624B\uFF0C\u8FD0\u884C\u5728\u7528\u6237\u7EC8\u7AEF\u4E2D\u3002\u4F60\u7684\u804C\u8D23\u662F\u5E2E\u52A9\u5F00\u53D1\u8005\u7F16\u5199\u3001\u7406\u89E3\u3001\u8C03\u8BD5\u548C\u91CD\u6784\u4EE3\u7801\u3002\r\n\r\n## \u6838\u5FC3\u539F\u5219\r\n- \u56DE\u7B54\u4F7F\u7528\u4E2D\u6587\uFF0C\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u82F1\u6587\r\n- \u63D0\u4F9B\u51C6\u786E\u3001\u5B9E\u7528\u3001\u53EF\u64CD\u4F5C\u7684\u5EFA\u8BAE\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u5185\u5BB9\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- \u4EE3\u7801\u793A\u4F8B\u4FDD\u6301\u7B80\u6D01\uFF0C\u9644\u5E26\u5FC5\u8981\u7684\u6CE8\u91CA\r\n\r\n## \u5DE5\u4F5C\u6D41\u7A0B\r\n\r\n\u4F60\u5904\u4E8E\u4E00\u4E2A\u5DE5\u5177\u8C03\u7528\u5FAA\u73AF\u4E2D\uFF1A\r\n1. \u6536\u5230\u7528\u6237\u8BF7\u6C42\r\n2. \u8C03\u7528\u5DE5\u5177\u83B7\u53D6\u4FE1\u606F\u6216\u4FEE\u6539\u6587\u4EF6\r\n3. \u5DE5\u5177\u7ED3\u679C\u8FD4\u56DE\u7ED9\u4F60\r\n4. \u6839\u636E\u7ED3\u679C\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF08\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u6216\u7ED9\u51FA\u6700\u7EC8\u56DE\u7B54\uFF09\r\n5. \u4E00\u8F6E\u6700\u591A {{maxToolRounds}} \u6B21\u5DE5\u5177\u8C03\u7528\r\n\r\n## \u5DE5\u5177\u4F7F\u7528\u7B56\u7565\r\n\r\n{{#if tools}}\r\n\u5F53\u524D\u53EF\u7528\u7684\u5DE5\u5177\uFF1A\r\n{{#each tools}}\r\n- **{{name}}**\uFF1A{{description}}{{#if params}}\uFF08\u53C2\u6570\uFF1A{{params}}\uFF09{{/if}}\r\n{{/each}}\r\n\r\n\u4F7F\u7528\u539F\u5219\uFF1A\r\n- **\u5148\u641C\u7D22\u518D\u8BFB\u53D6** \u2014 \u4E0D\u786E\u5B9A\u76EE\u6807\u4F4D\u7F6E\u65F6\u5148\u7528 grep/glob \u5B9A\u4F4D\uFF0C\u518D\u7528 read_file \u8BFB\u53D6\r\n- **\u5148\u8BFB\u53D6\u518D\u4FEE\u6539** \u2014 \u7F16\u8F91\u6587\u4EF6\u524D\u5148 read_file \u786E\u8BA4\u5F53\u524D\u5185\u5BB9\r\n- **\u6279\u91CF\u64CD\u4F5C\u4E00\u6B21\u5B8C\u6210** \u2014 \u540C\u4E00\u6587\u4EF6\u7684\u591A\u5904\u6539\u52A8\u5728\u5355\u6B21 edit_file \u4E2D\u5B8C\u6210\r\n- **\u5DE5\u5177\u51FA\u9519\u65F6** \u2014 \u5206\u6790\u9519\u8BEF\u539F\u56E0\uFF08\u8DEF\u5F84\u4E0D\u5BF9\uFF1F\u683C\u5F0F\u4E0D\u5BF9\uFF1F\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09\uFF0C\u4FEE\u6B63\u540E\u91CD\u8BD5\uFF0C\u4E0D\u8981\u91CD\u590D\u76F8\u540C\u7684\u9519\u8BEF\u8C03\u7528\r\n- **\u5BA1\u614E\u6267\u884C** \u2014 bash \u6267\u884C\u5371\u9669\u547D\u4EE4\uFF08rm -rf\u3001\u5F3A\u5236\u5199\u5165\u7B49\uFF09\u524D\u5148\u786E\u8BA4\r\n{{/if}}\r\n\r\n{{#if projectContext}}\r\n## \u9879\u76EE\u4E0A\u4E0B\u6587\r\n\r\n{{projectContext}}\r\n{{/if}}\r\n\r\n## \u56DE\u7B54\u683C\u5F0F\r\n\r\n\u7EC8\u7AEF\u4E0D\u652F\u6301 Markdown \u6E32\u67D3\u3002\u56DE\u590D\u683C\u5F0F\u8981\u6C42\uFF1A\r\n\r\n- \u7528 emoji \u505A\u89C6\u89C9\u6807\u8BB0\uFF08\u{1F4CC} \u8981\u70B9 \u26A0\uFE0F \u6CE8\u610F \u{1F4DD} \u5F85\u529E \u2705 \u5B8C\u6210\uFF09\r\n- \u7528\u6570\u5B57\u5E8F\u53F7\u6216\u77ED\u6A2A\u7EBF\u7EC4\u7EC7\u5217\u8868\r\n- \u4EE3\u7801\u6807\u8BC6\u7B26\u3001\u6587\u4EF6\u8DEF\u5F84\u3001\u7C7B\u578B\u540D\u7528\u5355\u4E2A\u53CD\u5F15\u53F7 ` \u5305\u88F9\uFF0C\u4F1A\u88AB\u81EA\u52A8\u9AD8\u4EAE\r\n- \u5F3A\u8C03\u5185\u5BB9\u7528 **\u52A0\u7C97** \u5305\u88F9\uFF0C\u4F1A\u88AB\u81EA\u52A8\u9AD8\u4EAE\r\n- \u591A\u884C\u4EE3\u7801\u7528\u7F29\u8FDB 4 \u4E2A\u7A7A\u683C\u8868\u793A\uFF0C\u4E0D\u8981\u7528\u4E09\u53CD\u5F15\u53F7\u4EE3\u7801\u5757\r\n- \u6BB5\u843D\u95F4\u7528\u7A7A\u884C\u5206\u9694\r\n- **\u4E0D\u8981\u4F7F\u7528 `#` \u7B26\u53F7** \u2014 \u7EC8\u7AEF\u4E0D\u6E32\u67D3 Markdown \u6807\u9898\uFF0C\u8BF7\u7528 emoji + \u52A0\u7C97\u66FF\u4EE3\uFF08\u5982 `\u{1F4CC} **\u6807\u9898**`\uFF09\r\n\r\n\u6B63\u786E\u793A\u4F8B\uFF1A\r\n\r\n\u{1F4CC} **\u4FEE\u6539\u8BA1\u5212**\r\n\r\n\u{1F4CC} \u9700\u8981\u4FEE\u6539\u4E24\u4E2A\u5730\u65B9\uFF1A\r\n1. \u7B2C 12 \u884C\u7684 `interface FileDiff` \u6539\u4E3A `interface Diff`\r\n2. \u7B2C 432 \u884C\u7684 `): FileDiff` \u6539\u4E3A `): Diff`\r\n\r\n \u4EE3\u7801\u793A\u4F8B\uFF1A\r\n const pool = new Pool({ max: 20 });\r\n await pool.query("SELECT * FROM users");\r\n\r\n## \u884C\u4E3A\u7EA6\u675F\r\n- \u5982\u679C\u7528\u6237\u8BF7\u6C42\u4E0D\u660E\u786E\uFF0C\u4E3B\u52A8\u8BE2\u95EE\u6F84\u6E05\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u4FE1\u606F\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- \u4E0D\u6267\u884C\u53EF\u80FD\u9020\u6210\u4E0D\u53EF\u9006\u635F\u5BB3\u7684\u64CD\u4F5C\uFF08\u5982 rm -rf\uFF09\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u9010\u6761\u786E\u8BA4\r\n- \u5DE5\u5177\u8C03\u7528\u8FD4\u56DE\u9519\u8BEF\u65F6\uFF0C\u5148\u5206\u6790\u539F\u56E0\u518D\u91CD\u8BD5\uFF0C\u4E0D\u8981\u76F2\u76EE\u91CD\u8BD5\r\n\r\n## \u5F53\u524D\u6A21\u578B\r\n- \u6A21\u578B\uFF1A{{model}}\r\n\r\n## \u65F6\u95F4\u4E0A\u4E0B\u6587\r\n- \u5F53\u524D\u65E5\u671F\uFF1A{{date}}\r\n- \u5F53\u524D\u65F6\u95F4\uFF1A{{time}}\r\n- \u5DE5\u4F5C\u76EE\u5F55\uFF1A{{cwd}}\r\n';
|
|
2195
|
+
var system_prompt_default = '\u4F60\u662F dskcode\uFF0C\u4E00\u4E2A\u57FA\u4E8E DeepSeek \u7684 AI \u7F16\u7A0B\u52A9\u624B\uFF0C\u8FD0\u884C\u5728\u7528\u6237\u7EC8\u7AEF\u4E2D\u3002\u4F60\u7684\u804C\u8D23\u662F\u5E2E\u52A9\u5F00\u53D1\u8005\u7F16\u5199\u3001\u7406\u89E3\u3001\u8C03\u8BD5\u548C\u91CD\u6784\u4EE3\u7801\u3002\r\n\r\n## \u6838\u5FC3\u539F\u5219\r\n- \u56DE\u7B54\u4F7F\u7528\u4E2D\u6587\uFF0C\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u82F1\u6587\r\n- **\u601D\u8003\u8FC7\u7A0B\uFF08CoT\uFF09\u4E5F\u4F7F\u7528\u4E2D\u6587**\uFF0C\u4E0D\u8981\u7528\u82F1\u6587\u601D\u8003\u3002\u5982\u679C\u4F60\u53D1\u73B0\u81EA\u5DF1\u5728\u7528\u82F1\u6587\r\n \u60F3\uFF0C\u8BF7\u5207\u6362\u5230\u4E2D\u6587\u3002\u4F60\u7684\u6240\u6709\u5185\u5FC3\u72EC\u767D\u548C\u6700\u7EC8\u56DE\u7B54\u90FD\u5E94\u7528\u4E2D\u6587\u8868\u8FBE\u3002\r\n- \u63D0\u4F9B\u51C6\u786E\u3001\u5B9E\u7528\u3001\u53EF\u64CD\u4F5C\u7684\u5EFA\u8BAE\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u5185\u5BB9\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- \u4EE3\u7801\u793A\u4F8B\u4FDD\u6301\u7B80\u6D01\uFF0C\u9644\u5E26\u5FC5\u8981\u7684\u6CE8\u91CA\r\n\r\n## \u7528\u6237\u8F93\u5165\u8BED\u6CD5\r\n- `@<\u8DEF\u5F84>` \u8868\u793A\u4E00\u4E2A**\u6587\u4EF6\u8DEF\u5F84**\u7684\u5F15\u7528\u6807\u8BC6\u3002`@` \u4E0D\u662F\u90AE\u7BB1\u7B26\u53F7\u3001\u4E5F\u4E0D\u662F\u88C5\u9970\u540E\u7F00\u3002\r\n - `@test.ts` = \u5F15\u7528\u5F53\u524D\u76EE\u5F55\u4E0B\u540D\u4E3A `test.ts` \u7684\u6587\u4EF6\r\n - `@src/foo/bar.ts` = \u5F15\u7528 `src/foo/bar.ts`\r\n - \u591A\u4E2A\u5F15\u7528\uFF1A`\u8BF7\u8BFB @a.ts \u548C @b/d.ts`\r\n - \u8DEF\u5F84\u53EF\u4EE5\u662F\u76F8\u5BF9\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5DE5\u4F5C\u76EE\u5F55\uFF09\u6216\u7EDD\u5BF9\u8DEF\u5F84\r\n- `\\/<\u547D\u4EE4>` \u8868\u793A\u4E00\u4E2A**\u659C\u6760\u547D\u4EE4**\uFF08\u5982 `\\/help`\u3001`\\/plan`\u3001`\\/code`\uFF09\uFF0C\u4E0D\u662F\u76EE\u5F55\u3002\r\n - \u6536\u5230 `/xxx` \u5F00\u5934\u7684\u5185\u5BB9\u5148\u5224\u5B9A\u662F\u4E0D\u662F\u5DF2\u6CE8\u518C\u547D\u4EE4\uFF1B\u4E0D\u662F\u5219\u5F53\u4F5C\u666E\u901A\u6587\u672C\u5904\u7406\u3002\r\n- \u4E0A\u8FF0\u4E24\u79CD\u524D\u7F00\u662F**\u7528\u6237\u8F93\u5165\u9762**\u8BED\u6CD5\uFF0C\u4F60**\u4E0D\u8981\u5728\u56DE\u590D\u4E2D\u8F93\u51FA**\u5B83\u4EEC\uFF08\u4E0D\u8981\u4F2A\u9020 `@/path` \u8FD9\u79CD\u4F2A\u5F15\u7528\uFF09\u3002\u5982\u679C\u8981\u5F15\u7528\u6587\u4EF6\uFF0C\u76F4\u63A5\u7528\u5355\u53CD\u5F15\u53F7\u5305\u88F9\u8DEF\u5F84\uFF08\u5982 `src/foo.ts`\uFF09\u3002\r\n\r\n## \u5DE5\u4F5C\u6D41\u7A0B\r\n\r\n\u4F60\u5904\u4E8E\u4E00\u4E2A\u5DE5\u5177\u8C03\u7528\u5FAA\u73AF\u4E2D\uFF1A\r\n1. \u6536\u5230\u7528\u6237\u8BF7\u6C42\r\n2. \u8C03\u7528\u5DE5\u5177\u83B7\u53D6\u4FE1\u606F\u6216\u4FEE\u6539\u6587\u4EF6\r\n3. \u5DE5\u5177\u7ED3\u679C\u8FD4\u56DE\u7ED9\u4F60\r\n4. \u6839\u636E\u7ED3\u679C\u51B3\u5B9A\u4E0B\u4E00\u6B65\uFF08\u7EE7\u7EED\u8C03\u7528\u5DE5\u5177\u6216\u7ED9\u51FA\u6700\u7EC8\u56DE\u7B54\uFF09\r\n5. \u4E00\u8F6E\u6700\u591A {{maxToolRounds}} \u6B21\u5DE5\u5177\u8C03\u7528\r\n\r\n## \u5DE5\u5177\u4F7F\u7528\u7B56\u7565\r\n\r\n{{#if tools}}\r\n\u5F53\u524D\u53EF\u7528\u7684\u5DE5\u5177\uFF1A\r\n{{#each tools}}\r\n- **{{name}}**\uFF1A{{description}}{{#if params}}\uFF08\u53C2\u6570\uFF1A{{params}}\uFF09{{/if}}\r\n{{/each}}\r\n\r\n\u4F7F\u7528\u539F\u5219\uFF1A\r\n- **\u5148\u641C\u7D22\u518D\u8BFB\u53D6** \u2014 \u4E0D\u786E\u5B9A\u76EE\u6807\u4F4D\u7F6E\u65F6\u5148\u7528 grep/glob \u5B9A\u4F4D\uFF0C\u518D\u7528 read_file \u8BFB\u53D6\r\n- **\u5148\u8BFB\u53D6\u518D\u4FEE\u6539** \u2014 \u7F16\u8F91\u6587\u4EF6\u524D\u5148 read_file \u786E\u8BA4\u5F53\u524D\u5185\u5BB9\r\n- **\u6279\u91CF\u64CD\u4F5C\u4E00\u6B21\u5B8C\u6210** \u2014 \u540C\u4E00\u6587\u4EF6\u7684\u591A\u5904\u6539\u52A8\u5728\u5355\u6B21 edit_file \u4E2D\u5B8C\u6210\r\n- **\u5DE5\u5177\u51FA\u9519\u65F6** \u2014 \u5206\u6790\u9519\u8BEF\u539F\u56E0\uFF08\u8DEF\u5F84\u4E0D\u5BF9\uFF1F\u683C\u5F0F\u4E0D\u5BF9\uFF1F\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09\uFF0C\u4FEE\u6B63\u540E\u91CD\u8BD5\uFF0C\u4E0D\u8981\u91CD\u590D\u76F8\u540C\u7684\u9519\u8BEF\u8C03\u7528\r\n- **\u5BA1\u614E\u6267\u884C** \u2014 bash \u6267\u884C\u5371\u9669\u547D\u4EE4\uFF08rm -rf\u3001\u5F3A\u5236\u5199\u5165\u7B49\uFF09\u524D\u5148\u786E\u8BA4\r\n{{/if}}\r\n\r\n## \u5DE5\u4F5C\u6D41\uFF08\u91CD\u8981\uFF09\u2014 \u590D\u6742\u4EFB\u52A1\u5224\u5B9A\r\n\r\n\u6536\u5230\u7528\u6237\u8BF7\u6C42\u540E\uFF0C**\u5148\u5224\u5B9A\u590D\u6742\u5EA6**\uFF0C\u518D\u51B3\u5B9A\u8981\u4E0D\u8981\u62C6 todo\u3002\r\n\r\n### \u9ED8\u8BA4\u5047\u8BBE\u662F\u300C\u590D\u6742\u300D\r\n\r\n\u9664\u975E\u660E\u786E\u5C5E\u4E8E\u4E0B\u9762\u300C\u7B80\u5355\u300D\u4E09\u9009\u4E00\uFF0C**\u9ED8\u8BA4\u6309\u590D\u6742\u5904\u7406\uFF0C\u5148 todo_add \u62C6 3-7 \u6B65**\u3002\r\n\r\n### \u5224\u5B9A\u95EE\u5377\uFF08\u9010\u6761 yes/no\uFF09\r\n\r\n\u95EE\u81EA\u5DF1\u4EE5\u4E0B\u95EE\u9898\uFF0C**\u4EFB\u4E00\u56DE\u7B54 yes \u2192 \u62C6 todo**\uFF1A\r\n- 1\uFE0F\u20E3 \u8981\u5199/\u6539/\u521B\u5EFA **\u8D85\u8FC7 1 \u4E2A**\u6587\u4EF6\uFF1F\r\n- 2\uFE0F\u20E3 \u8981\u5148 **\u8BFB\u540E\u6539**\uFF08edit_file / write_file \u4E4B\u524D\u5FC5\u987B read_file\uFF09\uFF1F\r\n- 3\uFE0F\u20E3 \u8981\u8DE8 **2 \u79CD\u4EE5\u4E0A**\u5DE5\u5177\uFF08read + edit + bash + ...\uFF09\uFF1F\r\n- 4\uFE0F\u20E3 \u8981 **\u5BF9\u6BD4 2 \u4E2A\u4EE5\u4E0A\u4E8B\u5B9E\u6E90**\uFF08\u5982 README \u8BF4\u7684 vs \u4EE3\u7801\u5B9E\u9645\u5199\u7684\u3001\u8FD9\u91CC vs \u90A3\u91CC\uFF09\uFF1F\r\n- 5\uFE0F\u20E3 \u53E5\u5B50\u8D85\u8FC7 **20 \u4E2A\u5B57** \u4E14 **\u5305\u542B\u300C\u6539\u6210 / \u52A0\u4E2A / \u5B9E\u73B0 / \u5199\u4E00\u4E2A / \u91CD\u6784 / \u4FEE\u590D / \u8C03\u6574\u300D** \u8FD9\u7C7B\u52A8\u8BCD\uFF1F\r\n\r\n### \u300C\u7B80\u5355\u300D\u4E09\u9009\u4E00\uFF08\u53EF\u4EE5\u4E0D\u62C6 todo\uFF09\r\n\r\n- \u7EAF\u67E5\u8BE2\uFF1A\u300C\u5217\u51FA X\u300D\u300C\u770B\u770B Y\u300D\u300C\u641C\u4E00\u4E0B Z\u300D\u2192 1 \u4E2A\u5DE5\u5177 1 \u8F6E\u641E\u5B9A\r\n- 1 \u4E2A\u5DE5\u5177 1 \u8F6E\u80FD\u641E\u5B9A\u7684\u8BFB/\u5217/\u67E5\u64CD\u4F5C\r\n- \u95F2\u804A / \u89E3\u91CA\u6027\u95EE\u9898\uFF08\u4E0D\u8C03\u4EFB\u4F55\u5DE5\u5177\uFF09\r\n\r\n### \u5224\u5B9A\u51B3\u7B56\u6811\r\n\r\n```\r\n\u7528\u6237\u8F93\u5165\r\n \u251C\u2500 \u662F\u300C\u7B80\u5355\u4E09\u9009\u4E00\u300D\uFF1F \u2192 \u76F4\u63A5\u8C03\u5DE5\u5177\uFF0C\u4E0D\u62C6 todo\r\n \u2514\u2500 \u4E0D\u662F\uFF1F \u2192 \u5148 todo_add \u62C6 3-7 \u6B65\u518D\u52A8\u624B\uFF08\u9ED8\u8BA4\u884C\u4E3A\uFF09\r\n```\r\n\r\n### todo \u62C6\u89E3\u6A21\u677F\r\n\r\n**\u6539\u52A8\u578B\u4EFB\u52A1**\uFF08\u6700\u5E38\u89C1\uFF09\uFF1A\r\n1. `todo_add("\u8BFB <\u76EE\u6807\u6587\u4EF6>")`\r\n2. `todo_add("<\u5177\u4F53\u6539\u52A8>", deps=[0])`\r\n3. `todo_add("\u68C0\u67E5\u6539\u52A8", deps=[1])`\uFF08\u91CD\u65B0\u8BFB\u6539\u8FC7\u7684\u6587\u4EF6\uFF0C\u786E\u8BA4\u4FEE\u6539\u6B63\u786E\u4E14\u65E0\u9057\u6F0F\uFF1B\u5FC5\u8981\u65F6\u8DD1 type-check\uFF09\r\n\r\n**\u65B0\u5EFA\u578B\u4EFB\u52A1**\uFF1A\r\n1. `todo_add("\u770B\u73B0\u6709\u540C\u7C7B\u6587\u4EF6\u600E\u4E48\u5199")`\r\n2. `todo_add("\u5B9E\u73B0\u65B0 <X>", deps=[0])`\r\n3. `todo_add("\u9A8C\u8BC1", deps=[1])`\r\n\r\n**\u8C03\u8BD5\u578B\u4EFB\u52A1**\uFF1A\r\n1. `todo_add("\u590D\u73B0 bug")`\r\n2. `todo_add("\u5B9A\u4F4D\u539F\u56E0", deps=[0])`\r\n3. `todo_add("\u4FEE\u590D", deps=[1])`\r\n4. `todo_add("\u68C0\u67E5\u4FEE\u590D", deps=[2])`\uFF08\u8BFB\u6539\u8FC7\u7684\u6587\u4EF6\uFF0C\u786E\u8BA4\u4FEE\u590D\u6B63\u786E\u6CA1\u6709\u5F15\u5165\u65B0\u95EE\u9898\uFF09\r\n\r\n### \u6267\u884C\u6D41\uFF08\u4E25\u683C\u9075\u5B88\uFF09\r\n\r\n- \u62C6\u5B8C todo \u540E\uFF0C**\u5148 `todo_mark_running(id)`** \u2192 \u8C03\u5B9E\u9645\u5DE5\u5177 \u2192 **`todo_mark_done(id, "\u8BC1\u636E")`**\r\n- \u5931\u8D25\uFF1A`todo_mark_failed(id, "\u539F\u56E0")`\uFF1B\u60F3\u91CD\u8BD5\uFF1A`todo_retry(id)` \u2192 \u518D\u8D70\u4E00\u904D\r\n\u8D70\u5B8C\u6240\u6709 todo\uFF0CHarness \u4F1A\u81EA\u52A8\u505A\u4EFB\u52A1\u68C0\u67E5\u2014\u2014\u91CD\u65B0\u8BFB\u53D6\u672C\u6B21\u6539\u8FC7\u7684\u6587\u4EF6\uFF0C\u786E\u8BA4\u4FEE\u6539\u5185\u5BB9\u6B63\u786E\u3001\u65E0\u9057\u6F0F\u3001\u7C7B\u578B\u517C\u5BB9\r\n\r\n### \u53CD\u4F8B\uFF08\u522B\u8FD9\u6837\uFF09\r\n\r\n- \u274C \u7528\u6237\u8BF4\u300C\u628A X \u6539\u6210 Y\u300D\u2192 \u8DF3\u8FC7 todo \u76F4\u63A5 read + edit\uFF08\u649E\u5899\u7387\u9AD8\uFF09\r\n- \u274C \u7528\u6237\u8BF4\u300C\u5199\u4E2A\u65B0\u5DE5\u5177\u300D\u2192 \u8DF3\u8FC7 todo \u76F4\u63A5 write_file\uFF08\u5BB9\u6613\u5199\u9519\u63A5\u53E3\uFF09\r\n- \u274C \u62C6\u4E86 todo \u4F46\u5FD8\u4E86 mark_running \u5C31 mark_done\uFF08\u4F9D\u8D56\u68C0\u67E5\u4F1A\u5931\u8D25\uFF09\r\n\r\n{{#if projectContext}}\r\n## \u9879\u76EE\u4E0A\u4E0B\u6587\r\n\r\n{{projectContext}}\r\n{{/if}}\r\n\r\n## \u56DE\u7B54\u683C\u5F0F\r\n\r\n\u7EC8\u7AEF\u4E0D\u652F\u6301 Markdown \u6E32\u67D3\u3002\u56DE\u590D\u683C\u5F0F\u8981\u6C42\uFF1A\r\n\r\n- \u7528 emoji \u505A\u89C6\u89C9\u6807\u8BB0\uFF08\u{1F4CC} \u8981\u70B9 \u26A0\uFE0F \u6CE8\u610F \u{1F4DD} \u5F85\u529E \u2705 \u5B8C\u6210\uFF09\r\n- \u7528\u6570\u5B57\u5E8F\u53F7\u6216\u77ED\u6A2A\u7EBF\u7EC4\u7EC7\u5217\u8868\r\n- \u4EE3\u7801\u6807\u8BC6\u7B26\u3001\u6587\u4EF6\u8DEF\u5F84\u3001\u7C7B\u578B\u540D\u7528\u5355\u4E2A\u53CD\u5F15\u53F7 ` \u5305\u88F9\uFF0C\u4F1A\u88AB\u81EA\u52A8\u9AD8\u4EAE\r\n- \u5F3A\u8C03\u5185\u5BB9\u7528 **\u52A0\u7C97** \u5305\u88F9\uFF0C\u4F1A\u88AB\u81EA\u52A8\u9AD8\u4EAE\r\n- \u591A\u884C\u4EE3\u7801\u7528\u7F29\u8FDB 4 \u4E2A\u7A7A\u683C\u8868\u793A\uFF0C\u4E0D\u8981\u7528\u4E09\u53CD\u5F15\u53F7\u4EE3\u7801\u5757\r\n- \u6BB5\u843D\u95F4\u7528\u7A7A\u884C\u5206\u9694\r\n- **\u4E0D\u8981\u4F7F\u7528 `#` \u7B26\u53F7** \u2014 \u7EC8\u7AEF\u4E0D\u6E32\u67D3 Markdown \u6807\u9898\uFF0C\u8BF7\u7528 emoji + \u52A0\u7C97\u66FF\u4EE3\uFF08\u5982 `\u{1F4CC} **\u6807\u9898**`\uFF09\r\n\r\n\u6B63\u786E\u793A\u4F8B\uFF1A\r\n\r\n\u{1F4CC} **\u4FEE\u6539\u8BA1\u5212**\r\n\r\n\u{1F4CC} \u9700\u8981\u4FEE\u6539\u4E24\u4E2A\u5730\u65B9\uFF1A\r\n1. \u7B2C 12 \u884C\u7684 `interface FileDiff` \u6539\u4E3A `interface Diff`\r\n2. \u7B2C 432 \u884C\u7684 `): FileDiff` \u6539\u4E3A `): Diff`\r\n\r\n \u4EE3\u7801\u793A\u4F8B\uFF1A\r\n const pool = new Pool({ max: 20 });\r\n await pool.query("SELECT * FROM users");\r\n\r\n## \u884C\u4E3A\u7EA6\u675F\r\n- \u5982\u679C\u7528\u6237\u8BF7\u6C42\u4E0D\u660E\u786E\uFF0C\u4E3B\u52A8\u8BE2\u95EE\u6F84\u6E05\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u4FE1\u606F\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- \u4E0D\u6267\u884C\u53EF\u80FD\u9020\u6210\u4E0D\u53EF\u9006\u635F\u5BB3\u7684\u64CD\u4F5C\uFF08\u5982 rm -rf\uFF09\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u9010\u6761\u786E\u8BA4\r\n- \u5DE5\u5177\u8C03\u7528\u8FD4\u56DE\u9519\u8BEF\u65F6\uFF0C\u5148\u5206\u6790\u539F\u56E0\u518D\u91CD\u8BD5\uFF0C\u4E0D\u8981\u76F2\u76EE\u91CD\u8BD5\r\n\r\n## \u5F53\u524D\u6A21\u578B\r\n- \u6A21\u578B\uFF1A{{model}}\r\n\r\n## \u65F6\u95F4\u4E0A\u4E0B\u6587\r\n- \u5F53\u524D\u65E5\u671F\uFF1A{{date}}\r\n- \u5F53\u524D\u65F6\u95F4\uFF1A{{time}}\r\n- \u5DE5\u4F5C\u76EE\u5F55\uFF1A{{cwd}}\r\n';
|
|
1989
2196
|
|
|
1990
2197
|
// src/agent/prompts/plan-prompt.hbs
|
|
1991
|
-
var plan_prompt_default = "\u4F60\u662F dskcode\uFF0C\u5F53\u524D\u5DE5\u4F5C\u5728**\u8BA1\u5212\u6A21\u5F0F\uFF08Plan Mode\uFF09**\u3002\r\n\r\n\u5728\u6B64\u6A21\u5F0F\u4E0B\uFF0C**\u4F60\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\u4EE3\u7801\uFF0C\u4E0D\u80FD\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\u64CD\u4F5C**\u3002\u4F60\u7684\u804C\u8D23\u662F\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u4EE3\u7801\u3001\u8BBE\u8BA1\u67B6\u6784\u3001\u89C4\u5212\u4EFB\u52A1\u3001\u8BC4\u4F30\u65B9\u6848\u3002\r\n\r\n## \u6838\u5FC3\u539F\u5219\r\n- \u56DE\u7B54\u4F7F\u7528\u4E2D\u6587\uFF0C\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u82F1\u6587\r\n- \u63D0\u4F9B\u51C6\u786E\u3001\u5B9E\u7528\u3001\u53EF\u64CD\u4F5C\u7684\u5EFA\u8BAE\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u5185\u5BB9\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- **\u7EDD\u4E0D\u6267\u884C\u4EFB\u4F55\u5199\u64CD\u4F5C** \u2014 \u4F60\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\r\n\r\n## \u5DE5\u4F5C\u6D41\u7A0B\r\n1. \u6536\u5230\u7528\u6237\u8BF7\u6C42\r\n2. \u4F7F\u7528\u8BFB\u5DE5\u5177\uFF08read-file, grep, glob, ls, fetch\uFF09\u63A2\u7D22\u4EE3\u7801\u5E93\r\n3. \u6839\u636E\u53D1\u73B0\u7684\u4FE1\u606F\u63D0\u4F9B\u7ED3\u6784\u5316\u7684\u5206\u6790\u6216\u8BA1\u5212\r\n4. \u5DE5\u5177\u8FD4\u56DE\u51FA\u9519\u65F6\u5206\u6790\u539F\u56E0\u5E76\u4FEE\u6B63\u540E\u91CD\u8BD5\r\n5. \u5B8C\u6210\u540E\u8F93\u51FA\u6700\u7EC8\u5206\u6790\u7ED3\u679C\r\n\r\n## \u5DE5\u5177\u9650\u5236\r\n**\u4F60\u53EA\u80FD\u4F7F\u7528\u8BFB\u5DE5\u5177**\uFF0C\u4E0D\u80FD\u4F7F\u7528\u4EFB\u4F55\u5199\u5DE5\u5177\uFF08write-file, edit-file, multi-edit, delete-range, bash\uFF09\u3002\r\n\u5982\u679C\u7528\u6237\u8BF7\u6C42\u4FEE\u6539\u4EE3\u7801\uFF0C\u8BF7\uFF1A\r\n- \u63D0\u4F9B\u4FEE\u6539\u5EFA\u8BAE\u548C\u65B9\u6848\r\n- \u6307\u51FA\u9700\u8981\u4FEE\u6539\u7684\u6587\u4EF6\u548C\u4F4D\u7F6E\r\n- \u89E3\u91CA\u4FEE\u6539\u7684\u5F71\u54CD\r\n- \u4F46\u4E0D\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\r\n\r\n## \u8BA1\u5212\u8F93\u51FA\u683C\u5F0F\r\n\r\n\u5F53\u7528\u6237\u8BF7\u6C42\u8BA1\u5212/\u65B9\u6848\u65F6\uFF0C\u5EFA\u8BAE\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u7EC4\u7EC7\u8F93\u51FA\uFF1A\r\n\r\n\u{1F4CB} **\u6982\u8FF0**\r\n 1-2 \u53E5\u8BDD\u8BF4\u660E\u8981\u505A\u4EC0\u4E48\u4EE5\u53CA\u4E3A\u4EC0\u4E48\u8981\u505A\r\n\r\n\u{1F50D} **\u73B0\u72B6\u5206\u6790**\r\n \u5F53\u524D\u4EE3\u7801\u7684\u7EC4\u7EC7\u7ED3\u6784\u548C\u5173\u952E\u53D1\u73B0\r\n\r\n\u26A1 **\u5F71\u54CD\u8303\u56F4**\r\n \u54EA\u4E9B\u6587\u4EF6/\u6A21\u5757\u4F1A\u53D7\u5230\u5F71\u54CD\r\n\r\n\u{1F4DD} **\u5B9E\u65BD\u6B65\u9AA4**\r\n 1. \u7B2C\u4E00\u6B65\uFF08\u6587\u4EF6\u8DEF\u5F84/\u53D8\u66F4\u8BF4\u660E\uFF09\r\n 2. \u7B2C\u4E8C\u6B65\uFF08\u6587\u4EF6\u8DEF\u5F84/\u53D8\u66F4\u8BF4\u660E\uFF09\r\n 3. ...\r\n\r\n\u26A0\uFE0F **\u98CE\u9669\u4E0E\u6CE8\u610F\u4E8B\u9879**\r\n \u53EF\u80FD\u7684\u98CE\u9669\u70B9\u3001\u4F9D\u8D56\u5173\u7CFB\u3001\u56DE\u9000\u7B56\u7565\r\n\r\n## \u56DE\u7B54\u683C\u5F0F\r\n\r\n\u7EC8\u7AEF\u4E0D\u652F\u6301 Markdown \u6E32\u67D3\u3002\u56DE\u590D\u683C\u5F0F\u8981\u6C42\uFF1A\r\n- \u7528 emoji \u505A\u89C6\u89C9\u6807\u8BB0\r\n- \u7528\u6570\u5B57\u5E8F\u53F7\u6216\u77ED\u6A2A\u7EBF\u7EC4\u7EC7\u5217\u8868\r\n- \u4EE3\u7801\u6807\u8BC6\u7B26\u3001\u6587\u4EF6\u8DEF\u5F84\u7528\u5355\u4E2A\u53CD\u5F15\u53F7 ` \u5305\u88F9\r\n- \u591A\u884C\u4EE3\u7801\u7528\u7F29\u8FDB 4 \u4E2A\u7A7A\u683C\u8868\u793A\r\n- \u6BB5\u843D\u95F4\u7528\u7A7A\u884C\u5206\u9694\r\n- **\u4E0D\u8981\u4F7F\u7528 `#` \u7B26\u53F7** \u2014 \u7EC8\u7AEF\u4E0D\u6E32\u67D3 Markdown \u6807\u9898\uFF0C\u8BF7\u7528 emoji + \u52A0\u7C97\u66FF\u4EE3\r\n\r\n## \u5F53\u524D\u6A21\u578B\r\n- \u6A21\u578B\uFF1A{{model}}\r\n\r\n## \u65F6\u95F4\u4E0A\u4E0B\u6587\r\n- \u5F53\u524D\u65E5\u671F\uFF1A{{date}}\r\n- \u5F53\u524D\u65F6\u95F4\uFF1A{{time}}\r\n- \u5DE5\u4F5C\u76EE\u5F55\uFF1A{{cwd}}\r\n";
|
|
2198
|
+
var plan_prompt_default = "\u4F60\u662F dskcode\uFF0C\u5F53\u524D\u5DE5\u4F5C\u5728**\u8BA1\u5212\u6A21\u5F0F\uFF08Plan Mode\uFF09**\u3002\r\n\r\n\u5728\u6B64\u6A21\u5F0F\u4E0B\uFF0C**\u4F60\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\u4EE3\u7801\uFF0C\u4E0D\u80FD\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\u64CD\u4F5C**\u3002\u4F60\u7684\u804C\u8D23\u662F\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u4EE3\u7801\u3001\u8BBE\u8BA1\u67B6\u6784\u3001\u89C4\u5212\u4EFB\u52A1\u3001\u8BC4\u4F30\u65B9\u6848\u3002\r\n\r\n## \u6838\u5FC3\u539F\u5219\r\n- \u56DE\u7B54\u4F7F\u7528\u4E2D\u6587\uFF0C\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u82F1\u6587\r\n- **\u601D\u8003\u8FC7\u7A0B\uFF08CoT\uFF09\u4E5F\u4F7F\u7528\u4E2D\u6587**\uFF0C\u4E0D\u8981\u7528\u82F1\u6587\u601D\u8003\u3002\r\n- \u63D0\u4F9B\u51C6\u786E\u3001\u5B9E\u7528\u3001\u53EF\u64CD\u4F5C\u7684\u5EFA\u8BAE\r\n- \u5BF9\u4E0D\u786E\u5B9A\u7684\u5185\u5BB9\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E\r\n- **\u7EDD\u4E0D\u6267\u884C\u4EFB\u4F55\u5199\u64CD\u4F5C** \u2014 \u4F60\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\r\n\r\n## \u7528\u6237\u8F93\u5165\u8BED\u6CD5\r\n- `@<\u8DEF\u5F84>` \u8868\u793A\u4E00\u4E2A**\u6587\u4EF6\u8DEF\u5F84**\u7684\u5F15\u7528\u6807\u8BC6\u3002`@` \u4E0D\u662F\u90AE\u7BB1\u7B26\u53F7\u3001\u4E5F\u4E0D\u662F\u88C5\u9970\u540E\u7F00\u3002\r\n - `@test.ts` = \u5F15\u7528\u5F53\u524D\u76EE\u5F55\u4E0B\u540D\u4E3A `test.ts` \u7684\u6587\u4EF6\r\n - `@src/foo/bar.ts` = \u5F15\u7528 `src/foo/bar.ts`\r\n - \u591A\u4E2A\u5F15\u7528\uFF1A`\u8BF7\u8BFB @a.ts \u548C @b/d.ts`\r\n - \u8DEF\u5F84\u53EF\u4EE5\u662F\u76F8\u5BF9\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5DE5\u4F5C\u76EE\u5F55\uFF09\u6216\u7EDD\u5BF9\u8DEF\u5F84\r\n- `\\/<\u547D\u4EE4>` \u8868\u793A\u4E00\u4E2A**\u659C\u6760\u547D\u4EE4**\uFF08\u5982 `\\/help`\u3001`\\/plan`\u3001`\\/code`\uFF09\uFF0C\u4E0D\u662F\u76EE\u5F55\u3002\r\n - \u6536\u5230 `/xxx` \u5F00\u5934\u7684\u5185\u5BB9\u5148\u5224\u5B9A\u662F\u4E0D\u662F\u5DF2\u6CE8\u518C\u547D\u4EE4\uFF1B\u4E0D\u662F\u5219\u5F53\u4F5C\u666E\u901A\u6587\u672C\u5904\u7406\u3002\r\n- \u4E0A\u8FF0\u4E24\u79CD\u524D\u7F00\u662F**\u7528\u6237\u8F93\u5165\u9762**\u8BED\u6CD5\uFF0C\u4F60**\u4E0D\u8981\u5728\u56DE\u590D\u4E2D\u8F93\u51FA**\u5B83\u4EEC\uFF08\u4E0D\u8981\u4F2A\u9020 `@/path` \u8FD9\u79CD\u4F2A\u5F15\u7528\uFF09\u3002\u5982\u679C\u8981\u5F15\u7528\u6587\u4EF6\uFF0C\u76F4\u63A5\u7528\u5355\u53CD\u5F15\u53F7\u5305\u88F9\u8DEF\u5F84\uFF08\u5982 `src/foo.ts`\uFF09\u3002\r\n\r\n## \u5DE5\u4F5C\u6D41\u7A0B\r\n1. \u6536\u5230\u7528\u6237\u8BF7\u6C42\r\n2. \u4F7F\u7528\u8BFB\u5DE5\u5177\uFF08read-file, grep, glob, ls, fetch\uFF09\u63A2\u7D22\u4EE3\u7801\u5E93\r\n3. \u6839\u636E\u53D1\u73B0\u7684\u4FE1\u606F\u63D0\u4F9B\u7ED3\u6784\u5316\u7684\u5206\u6790\u6216\u8BA1\u5212\r\n4. \u5DE5\u5177\u8FD4\u56DE\u51FA\u9519\u65F6\u5206\u6790\u539F\u56E0\u5E76\u4FEE\u6B63\u540E\u91CD\u8BD5\r\n5. \u5B8C\u6210\u540E\u8F93\u51FA\u6700\u7EC8\u5206\u6790\u7ED3\u679C\r\n\r\n## \u5DE5\u5177\u9650\u5236\r\n**\u4F60\u53EA\u80FD\u4F7F\u7528\u8BFB\u5DE5\u5177**\uFF0C\u4E0D\u80FD\u4F7F\u7528\u4EFB\u4F55\u5199\u5DE5\u5177\uFF08write-file, edit-file, multi-edit, delete-range, bash\uFF09\u3002\r\n\u5982\u679C\u7528\u6237\u8BF7\u6C42\u4FEE\u6539\u4EE3\u7801\uFF0C\u8BF7\uFF1A\r\n- \u63D0\u4F9B\u4FEE\u6539\u5EFA\u8BAE\u548C\u65B9\u6848\r\n- \u6307\u51FA\u9700\u8981\u4FEE\u6539\u7684\u6587\u4EF6\u548C\u4F4D\u7F6E\r\n- \u89E3\u91CA\u4FEE\u6539\u7684\u5F71\u54CD\r\n- \u4F46\u4E0D\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\r\n\r\n## \u8BA1\u5212\u8F93\u51FA\u683C\u5F0F\r\n\r\n\u5F53\u7528\u6237\u8BF7\u6C42\u8BA1\u5212/\u65B9\u6848\u65F6\uFF0C\u5EFA\u8BAE\u6309\u7167\u4EE5\u4E0B\u7ED3\u6784\u7EC4\u7EC7\u8F93\u51FA\uFF1A\r\n\r\n\u{1F4CB} **\u6982\u8FF0**\r\n 1-2 \u53E5\u8BDD\u8BF4\u660E\u8981\u505A\u4EC0\u4E48\u4EE5\u53CA\u4E3A\u4EC0\u4E48\u8981\u505A\r\n\r\n\u{1F50D} **\u73B0\u72B6\u5206\u6790**\r\n \u5F53\u524D\u4EE3\u7801\u7684\u7EC4\u7EC7\u7ED3\u6784\u548C\u5173\u952E\u53D1\u73B0\r\n\r\n\u26A1 **\u5F71\u54CD\u8303\u56F4**\r\n \u54EA\u4E9B\u6587\u4EF6/\u6A21\u5757\u4F1A\u53D7\u5230\u5F71\u54CD\r\n\r\n\u{1F4DD} **\u5B9E\u65BD\u6B65\u9AA4**\r\n 1. \u7B2C\u4E00\u6B65\uFF08\u6587\u4EF6\u8DEF\u5F84/\u53D8\u66F4\u8BF4\u660E\uFF09\r\n 2. \u7B2C\u4E8C\u6B65\uFF08\u6587\u4EF6\u8DEF\u5F84/\u53D8\u66F4\u8BF4\u660E\uFF09\r\n 3. ...\r\n\r\n\u26A0\uFE0F **\u98CE\u9669\u4E0E\u6CE8\u610F\u4E8B\u9879**\r\n \u53EF\u80FD\u7684\u98CE\u9669\u70B9\u3001\u4F9D\u8D56\u5173\u7CFB\u3001\u56DE\u9000\u7B56\u7565\r\n\r\n## \u56DE\u7B54\u683C\u5F0F\r\n\r\n\u7EC8\u7AEF\u4E0D\u652F\u6301 Markdown \u6E32\u67D3\u3002\u56DE\u590D\u683C\u5F0F\u8981\u6C42\uFF1A\r\n- \u7528 emoji \u505A\u89C6\u89C9\u6807\u8BB0\r\n- \u7528\u6570\u5B57\u5E8F\u53F7\u6216\u77ED\u6A2A\u7EBF\u7EC4\u7EC7\u5217\u8868\r\n- \u4EE3\u7801\u6807\u8BC6\u7B26\u3001\u6587\u4EF6\u8DEF\u5F84\u7528\u5355\u4E2A\u53CD\u5F15\u53F7 ` \u5305\u88F9\r\n- \u591A\u884C\u4EE3\u7801\u7528\u7F29\u8FDB 4 \u4E2A\u7A7A\u683C\u8868\u793A\r\n- \u6BB5\u843D\u95F4\u7528\u7A7A\u884C\u5206\u9694\r\n- **\u4E0D\u8981\u4F7F\u7528 `#` \u7B26\u53F7** \u2014 \u7EC8\u7AEF\u4E0D\u6E32\u67D3 Markdown \u6807\u9898\uFF0C\u8BF7\u7528 emoji + \u52A0\u7C97\u66FF\u4EE3\r\n\r\n## \u5F53\u524D\u6A21\u578B\r\n- \u6A21\u578B\uFF1A{{model}}\r\n\r\n## \u65F6\u95F4\u4E0A\u4E0B\u6587\r\n- \u5F53\u524D\u65E5\u671F\uFF1A{{date}}\r\n- \u5F53\u524D\u65F6\u95F4\uFF1A{{time}}\r\n- \u5DE5\u4F5C\u76EE\u5F55\uFF1A{{cwd}}\r\n";
|
|
1992
2199
|
|
|
1993
2200
|
// src/agent/system-prompt.ts
|
|
1994
2201
|
var compiledTemplate = Handlebars.compile(system_prompt_default);
|
|
@@ -2450,7 +2657,7 @@ var Reflector = class {
|
|
|
2450
2657
|
const reflections = [];
|
|
2451
2658
|
for (const item of items) {
|
|
2452
2659
|
if (item.result.success) continue;
|
|
2453
|
-
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
|
|
2660
|
+
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#ruleTextNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
|
|
2454
2661
|
if (r) reflections.push(r);
|
|
2455
2662
|
if (reflections.length >= this.#maxReflections) break;
|
|
2456
2663
|
}
|
|
@@ -2526,6 +2733,26 @@ var Reflector = class {
|
|
|
2526
2733
|
hint: `\`${item.name}\` \u5931\u8D25\uFF1A\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u7528 \`ls\` / \`glob\` \u770B\u4E00\u4E0B\u76EE\u5F55\u7ED3\u6784\uFF0C\u6216\u786E\u8BA4\u8DEF\u5F84\u62FC\u5199\uFF08\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u89C1 system prompt\uFF09\u3002`
|
|
2527
2734
|
};
|
|
2528
2735
|
}
|
|
2736
|
+
/**
|
|
2737
|
+
* R2.5 文本未找到:edit_file / multi_edit 报 TEXT_NOT_FOUND 或 TEXT_MULTIPLE_MATCHES。
|
|
2738
|
+
*
|
|
2739
|
+
* 这是编辑工具最高频的失败。工具内部已对 CRLF 做归一化,仍报此错通常是
|
|
2740
|
+
* old_text 与当前文件内容不一致(缩进 / 已被改过 / 多次出现)。给一条明确
|
|
2741
|
+
* 的「重新读文件、逐字复制」指引,避免模型用同一份旧 old_text 反复重试。
|
|
2742
|
+
*
|
|
2743
|
+
* @pure 仅读入参
|
|
2744
|
+
*/
|
|
2745
|
+
#ruleTextNotFound(item) {
|
|
2746
|
+
const isTextErr = item.result.error === "TEXT_NOT_FOUND" || item.result.error === "TEXT_MULTIPLE_MATCHES";
|
|
2747
|
+
if (!isTextErr) return null;
|
|
2748
|
+
const multiple = item.result.error === "TEXT_MULTIPLE_MATCHES";
|
|
2749
|
+
const hint = multiple ? `\`${item.name}\`\uFF1Aold_text \u5728\u6587\u4EF6\u4E2D\u51FA\u73B0\u591A\u6B21\u3002\u8BF7\u8865\u5145\u4E0A\u4E0B\u6587\u8BA9 old_text \u552F\u4E00\uFF0C\u6216\u6539\u7528 multi_edit \u7684 replaceAll\u3002` : `\`${item.name}\`\uFF1A\u672A\u627E\u5230 old_text\u3002\u8BF7\u91CD\u65B0 \`read_file\` \u770B\u5F53\u524D\u5185\u5BB9\uFF0C\u9010\u5B57\u590D\u5236\u8981\u66FF\u6362\u7684\u7247\u6BB5\uFF08\u6CE8\u610F\u7F29\u8FDB\u4E0E\u7A7A\u683C\uFF09\uFF1B\u884C\u5C3E\u5DF2\u505A CRLF \u5F52\u4E00\u5316\uFF0C\u65E0\u9700\u624B\u5199 \\r\\n\u3002`;
|
|
2750
|
+
return {
|
|
2751
|
+
category: "text_not_found",
|
|
2752
|
+
toolName: item.name,
|
|
2753
|
+
hint
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2529
2756
|
/**
|
|
2530
2757
|
* R3 权限拒绝:GATE_DENIED 错误码 或 data 含 EACCES / permission / denied(不区分大小写)。
|
|
2531
2758
|
*
|
|
@@ -2543,13 +2770,19 @@ var Reflector = class {
|
|
|
2543
2770
|
};
|
|
2544
2771
|
}
|
|
2545
2772
|
/**
|
|
2546
|
-
* R4 写根外:kind ∈ Edit/Delete/Move
|
|
2773
|
+
* R4 写根外:kind ∈ Edit/Delete/Move 且错误码为 OUTSIDE_WRITE_ROOTS。
|
|
2774
|
+
*
|
|
2775
|
+
* 仅在工具本身明确报「路径超出写根」时才命中。旧实现只要写类工具失败就
|
|
2776
|
+
* 触发,会把 TEXT_NOT_FOUND / EXECUTION_ERROR 等误报为「写根外」,注入
|
|
2777
|
+
* 误导性提示(见会话日志 e65f0205 round 13:edit_file 因 CRLF 失配返回
|
|
2778
|
+
* TEXT_NOT_FOUND,却被反射为 out_of_write_root)。
|
|
2547
2779
|
*
|
|
2548
2780
|
* @pure 仅读入参
|
|
2549
2781
|
*/
|
|
2550
2782
|
#ruleOutOfWriteRoot(item, writeRoots) {
|
|
2551
2783
|
const isWriteKind = item.kind === "edit" /* Edit */ || item.kind === "delete" /* Delete */ || item.kind === "move" /* Move */;
|
|
2552
2784
|
if (!isWriteKind) return null;
|
|
2785
|
+
if (item.result.error !== "OUTSIDE_WRITE_ROOTS") return null;
|
|
2553
2786
|
const primary = writeRoots[0] ?? "<\u672A\u914D\u7F6E>";
|
|
2554
2787
|
return {
|
|
2555
2788
|
category: "out_of_write_root",
|
|
@@ -2581,61 +2814,485 @@ function buildToolDefinitions(registry2, mode) {
|
|
|
2581
2814
|
}));
|
|
2582
2815
|
}
|
|
2583
2816
|
|
|
2584
|
-
// src/
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2817
|
+
// src/harness/todo-list.ts
|
|
2818
|
+
var TodoList = class {
|
|
2819
|
+
#items = [];
|
|
2820
|
+
#nextId = 0;
|
|
2821
|
+
/**
|
|
2822
|
+
* 新增一个 todo,返回分配的 id。
|
|
2823
|
+
*
|
|
2824
|
+
* @param content — 步骤描述(中文)
|
|
2825
|
+
* @param deps — 依赖的 todo id 列表;为空表示无依赖,立即可 running
|
|
2826
|
+
* @returns 新 todo 的 id
|
|
2827
|
+
* @throws 当 deps 引用了不存在的 id 时抛出,避免 LLM 错把不存在的依赖塞进计划
|
|
2828
|
+
*/
|
|
2829
|
+
add(content, deps = []) {
|
|
2830
|
+
for (const d of deps) {
|
|
2831
|
+
if (!this.#items.find((it) => it.id === d)) {
|
|
2832
|
+
throw new Error(`todo \u4F9D\u8D56 #${d} \u4E0D\u5B58\u5728\uFF08\u5DF2\u5206\u914D\u7684 id: ${this.#items.map((it) => it.id).join(", ") || "(\u7A7A)"}\uFF09`);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
const id = this.#nextId++;
|
|
2836
|
+
this.#items.push({
|
|
2837
|
+
id,
|
|
2838
|
+
content,
|
|
2839
|
+
status: "pending",
|
|
2840
|
+
deps: [...deps],
|
|
2841
|
+
updatedAt: Date.now()
|
|
2842
|
+
});
|
|
2843
|
+
return id;
|
|
2844
|
+
}
|
|
2845
|
+
/**
|
|
2846
|
+
* 把失败的 todo 重置回 pending(用于"重试"工作流)。
|
|
2847
|
+
*
|
|
2848
|
+
* 不允许把 done / skipped 重置(一旦完成不应反悔)。
|
|
2849
|
+
* 不允许把 running 重置(应该先 markFailed 再重试)。
|
|
2850
|
+
*
|
|
2851
|
+
* @param id — todo id
|
|
2852
|
+
* @returns 是否成功
|
|
2853
|
+
*/
|
|
2854
|
+
resetForRetry(id) {
|
|
2855
|
+
const item = this.#find(id);
|
|
2856
|
+
if (!item) return false;
|
|
2857
|
+
if (item.status !== "failed") return false;
|
|
2858
|
+
item.status = "pending";
|
|
2859
|
+
item.evidence = void 0;
|
|
2860
|
+
item.updatedAt = Date.now();
|
|
2592
2861
|
return true;
|
|
2593
|
-
} catch {
|
|
2594
|
-
return false;
|
|
2595
2862
|
}
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2863
|
+
/**
|
|
2864
|
+
* 把 todo 标记为 running。
|
|
2865
|
+
*
|
|
2866
|
+
* 前提:该 todo 存在 + 当前是 pending + 依赖全 done。
|
|
2867
|
+
* 不满足时静默返回 false(不抛错,避免污染 agent 主循环)。
|
|
2868
|
+
*
|
|
2869
|
+
* @param id — todo id
|
|
2870
|
+
* @returns 是否成功转换
|
|
2871
|
+
*/
|
|
2872
|
+
markRunning(id) {
|
|
2873
|
+
const item = this.#find(id);
|
|
2874
|
+
if (!item) return false;
|
|
2875
|
+
if (item.status !== "pending") return false;
|
|
2876
|
+
if (!this.#depsAllDone(item.deps)) return false;
|
|
2877
|
+
item.status = "running";
|
|
2878
|
+
item.updatedAt = Date.now();
|
|
2600
2879
|
return true;
|
|
2601
|
-
} catch {
|
|
2602
|
-
return false;
|
|
2603
2880
|
}
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2881
|
+
/**
|
|
2882
|
+
* 标记完成。
|
|
2883
|
+
*
|
|
2884
|
+
* @param id — todo id
|
|
2885
|
+
* @param evidence — 完成证据(如 "读取成功"、"type-check 通过")
|
|
2886
|
+
* @returns 是否成功
|
|
2887
|
+
*/
|
|
2888
|
+
markDone(id, evidence) {
|
|
2889
|
+
const item = this.#find(id);
|
|
2890
|
+
if (!item) return false;
|
|
2891
|
+
if (item.status !== "running" && item.status !== "pending") return false;
|
|
2892
|
+
item.status = "done";
|
|
2893
|
+
if (evidence !== void 0) item.evidence = evidence;
|
|
2894
|
+
item.updatedAt = Date.now();
|
|
2895
|
+
return true;
|
|
2616
2896
|
}
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2897
|
+
/**
|
|
2898
|
+
* 标记失败。
|
|
2899
|
+
*
|
|
2900
|
+
* @param id — todo id
|
|
2901
|
+
* @param reason — 失败原因(人类可读)
|
|
2902
|
+
* @returns 是否成功
|
|
2903
|
+
*/
|
|
2904
|
+
markFailed(id, reason) {
|
|
2905
|
+
const item = this.#find(id);
|
|
2906
|
+
if (!item) return false;
|
|
2907
|
+
if (item.status === "done") return false;
|
|
2908
|
+
item.status = "failed";
|
|
2909
|
+
item.evidence = reason;
|
|
2910
|
+
item.updatedAt = Date.now();
|
|
2911
|
+
return true;
|
|
2912
|
+
}
|
|
2913
|
+
/**
|
|
2914
|
+
* 标记跳过。
|
|
2915
|
+
*
|
|
2916
|
+
* @param id — todo id
|
|
2917
|
+
* @param reason — 跳过原因(如 "项目无测试基建")
|
|
2918
|
+
* @returns 是否成功
|
|
2919
|
+
*/
|
|
2920
|
+
markSkipped(id, reason) {
|
|
2921
|
+
const item = this.#find(id);
|
|
2922
|
+
if (!item) return false;
|
|
2923
|
+
if (item.status === "done" || item.status === "failed") return false;
|
|
2924
|
+
item.status = "skipped";
|
|
2925
|
+
item.evidence = reason;
|
|
2926
|
+
item.updatedAt = Date.now();
|
|
2927
|
+
return true;
|
|
2928
|
+
}
|
|
2929
|
+
/**
|
|
2930
|
+
* 取出所有"立即可做"的 todo(deps 全 done 且 pending)。
|
|
2931
|
+
*
|
|
2932
|
+
* @returns 可执行的 todo 列表
|
|
2933
|
+
*/
|
|
2934
|
+
pending() {
|
|
2935
|
+
return this.#items.filter(
|
|
2936
|
+
(it) => it.status === "pending" && this.#depsAllDone(it.deps)
|
|
2937
|
+
);
|
|
2938
|
+
}
|
|
2939
|
+
/**
|
|
2940
|
+
* 取出所有未完成项(pending / running / failed)。
|
|
2941
|
+
*/
|
|
2942
|
+
unfinished() {
|
|
2943
|
+
return this.#items.filter(
|
|
2944
|
+
(it) => it.status === "pending" || it.status === "running" || it.status === "failed"
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
/**
|
|
2948
|
+
* 是否全部结束(done / failed / skipped)。
|
|
2949
|
+
*/
|
|
2950
|
+
isAllTerminated() {
|
|
2951
|
+
return this.#items.every(
|
|
2952
|
+
(it) => it.status === "done" || it.status === "failed" || it.status === "skipped"
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
/** 全部条目(只读快照) */
|
|
2956
|
+
get items() {
|
|
2957
|
+
return this.#items;
|
|
2958
|
+
}
|
|
2959
|
+
/**
|
|
2960
|
+
* 把 todo 列表拼成 markdown,用于注入 system prompt。
|
|
2961
|
+
*
|
|
2962
|
+
* @param maxItems — 最多展示多少条;超出时保留"最近 N 条 + 进行中",折叠已完成
|
|
2963
|
+
* @returns markdown 字符串
|
|
2964
|
+
*/
|
|
2965
|
+
toMarkdown(maxItems = 20) {
|
|
2966
|
+
if (this.#items.length === 0) return "";
|
|
2967
|
+
const active = this.#items.filter(
|
|
2968
|
+
(it) => it.status === "pending" || it.status === "running" || it.status === "failed"
|
|
2969
|
+
);
|
|
2970
|
+
const finished = this.#items.filter(
|
|
2971
|
+
(it) => it.status === "done" || it.status === "skipped"
|
|
2972
|
+
);
|
|
2973
|
+
const finishedSorted = [...finished].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
2974
|
+
const truncated = finishedSorted.length > maxItems;
|
|
2975
|
+
const finishedToShow = truncated ? finishedSorted.slice(0, Math.max(0, maxItems - active.length)) : finishedSorted;
|
|
2976
|
+
const lines = [...active, ...finishedToShow].map((it) => {
|
|
2977
|
+
const box = this.#statusBox(it.status);
|
|
2978
|
+
const depStr = it.deps.length > 0 ? ` (\u4F9D\u8D56: #${it.deps.join(", #")})` : "";
|
|
2979
|
+
const eviStr = it.evidence ? ` \u2014 ${it.evidence}` : "";
|
|
2980
|
+
return `- ${box} #${it.id} ${it.content}${depStr}${eviStr}`;
|
|
2981
|
+
});
|
|
2982
|
+
if (truncated) {
|
|
2983
|
+
const hidden = finishedSorted.length - finishedToShow.length;
|
|
2984
|
+
lines.push(`- ...\uFF08\u53E6\u6709 ${hidden} \u6761\u5DF2\u5B8C\u6210\u5DF2\u6298\u53E0\uFF09`);
|
|
2985
|
+
}
|
|
2986
|
+
return [
|
|
2987
|
+
"## \u{1F4CB} \u5F53\u524D\u4EFB\u52A1\u8FDB\u5EA6",
|
|
2988
|
+
...lines,
|
|
2989
|
+
"",
|
|
2990
|
+
"\u89C4\u5219\uFF1A\u6309\u987A\u5E8F\u63A8\u8FDB\uFF1B\u672A\u5B8C\u6210\u4F9D\u8D56\u65F6\u4E0D\u8981\u8DF3\u6B65\uFF1B\u5B8C\u6210\u8BF7\u8C03\u7528 todo_mark_done\uFF0C\u5931\u8D25\u8BF7\u8C03\u7528 todo_mark_failed\uFF1B\u91CD\u8BD5\u5931\u8D25\u9879\u5148\u8C03 todo_retry \u518D\u91CD\u8DD1\u3002"
|
|
2991
|
+
].join("\n");
|
|
2992
|
+
}
|
|
2993
|
+
// -------------------------------------------------------------------------
|
|
2994
|
+
// 内部
|
|
2995
|
+
// -------------------------------------------------------------------------
|
|
2996
|
+
#find(id) {
|
|
2997
|
+
return this.#items.find((it) => it.id === id);
|
|
2998
|
+
}
|
|
2999
|
+
#depsAllDone(deps) {
|
|
3000
|
+
return deps.every((d) => {
|
|
3001
|
+
const item = this.#items.find((it) => it.id === d);
|
|
3002
|
+
return item?.status === "done" || item?.status === "skipped";
|
|
3003
|
+
});
|
|
3004
|
+
}
|
|
3005
|
+
#statusBox(status) {
|
|
3006
|
+
switch (status) {
|
|
3007
|
+
case "pending":
|
|
3008
|
+
return "\u2610";
|
|
3009
|
+
case "running":
|
|
3010
|
+
return "\u25B6";
|
|
3011
|
+
case "done":
|
|
3012
|
+
return "\u2705";
|
|
3013
|
+
case "failed":
|
|
3014
|
+
return "\u274C";
|
|
3015
|
+
case "skipped":
|
|
3016
|
+
return "\u23ED";
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
};
|
|
3020
|
+
|
|
3021
|
+
// src/harness/tools.ts
|
|
3022
|
+
function createHarnessTools(todoList) {
|
|
3023
|
+
return [
|
|
3024
|
+
makeTodoAddTool(todoList),
|
|
3025
|
+
makeTodoMarkRunningTool(todoList),
|
|
3026
|
+
makeTodoMarkDoneTool(todoList),
|
|
3027
|
+
makeTodoMarkFailedTool(todoList),
|
|
3028
|
+
makeTodoRetryTool(todoList)
|
|
3029
|
+
];
|
|
3030
|
+
}
|
|
3031
|
+
function makeTodoAddTool(todoList) {
|
|
3032
|
+
return {
|
|
3033
|
+
name: "todo_add",
|
|
3034
|
+
kind: "other" /* Other */,
|
|
3035
|
+
description: '\u26A0\uFE0F \u3010\u590D\u6742\u4EFB\u52A1\u7B2C\u4E00\u6B65\u3011\u6DFB\u52A0\u4E00\u4E2A\u5F85\u529E\u5230\u5F53\u524D\u4EFB\u52A1\u8FDB\u5EA6\u3002\n\n\u4EC0\u4E48\u60C5\u51B5\u4E0B\u8C03\u6211\uFF1A\n - \u9700\u8981\u591A\u6B65\u624D\u80FD\u5B8C\u6210\uFF08\u6539\u591A\u4E2A\u6587\u4EF6 / \u8DE8\u591A\u8F6E\uFF09\n - \u9700\u5148\u8BFB\u540E\u6539\uFF08edit/write \u4E4B\u524D\uFF09\n - \u4F9D\u8D56\u5916\u90E8\u72B6\u6001\uFF08\u6587\u4EF6\u3001API\u3001\u8FD0\u884C\u7ED3\u679C\uFF09\n\n\u4EC0\u4E48\u60C5\u51B5\u4E0B\u4E0D\u8981\u8C03\uFF1A\n - \u4E00\u53E5\u8BDD\u80FD\u5B8C\u6210\u7684\u4E8B\uFF08\u67E5\u3001\u5217\u3001\u95EE\uFF09\n\n\u7528\u6CD5\uFF1A\u6BCF\u6B21\u52A0\u4E00\u4E2A step\uFF0C\u591A\u6B65\u5C31\u8C03\u591A\u6B21\u3002\u6709\u4F9D\u8D56\u5173\u7CFB\u4F20 deps=[\u524D\u6B65 id]\u3002\u8FD4\u56DE\u5206\u914D\u7684 id\uFF0C\u540E\u7EED\u7528 todo_mark_done / todo_mark_failed \u5F15\u7528\u3002\n\n\u793A\u4F8B\uFF1A\u7528\u6237\u8BF4\u300C\u628A X \u6539\u6210 Y\u300D\u2192 \u8C03 1) todo_add("\u8BFB X") 2) todo_add("\u6539 X", deps=[0]) 3) todo_add("\u68C0\u67E5\u6539\u52A8", deps=[1])',
|
|
3036
|
+
parameters: {
|
|
3037
|
+
type: "object",
|
|
3038
|
+
properties: {
|
|
3039
|
+
content: { type: "string", description: "\u6B65\u9AA4\u63CF\u8FF0\uFF08\u4E2D\u6587\uFF0C\u5EFA\u8BAE\u7B80\u6D01\uFF09" },
|
|
3040
|
+
deps: {
|
|
3041
|
+
type: "array",
|
|
3042
|
+
description: "\u4F9D\u8D56\u7684 todo id \u6570\u7EC4\uFF08\u8FD9\u4E9B\u90FD done \u540E\u672C\u9879\u624D\u53EF\u6267\u884C\uFF09",
|
|
3043
|
+
items: { type: "number" }
|
|
3044
|
+
}
|
|
3045
|
+
},
|
|
3046
|
+
required: ["content"],
|
|
3047
|
+
additionalProperties: false
|
|
3048
|
+
},
|
|
3049
|
+
async execute(args) {
|
|
3050
|
+
if (typeof args?.content !== "string" || args.content.length === 0) {
|
|
3051
|
+
return { success: false, data: "\u7F3A\u5C11 content \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3052
|
+
}
|
|
3053
|
+
const deps = Array.isArray(args.deps) ? args.deps.filter((d) => typeof d === "number") : [];
|
|
3054
|
+
try {
|
|
3055
|
+
const id = todoList.add(args.content, deps);
|
|
3056
|
+
return {
|
|
3057
|
+
success: true,
|
|
3058
|
+
data: `\u5DF2\u6DFB\u52A0 todo #${id}\uFF1A${args.content}${deps.length > 0 ? `\uFF08\u4F9D\u8D56: ${deps.join(", ")})` : ""}`,
|
|
3059
|
+
summary: `\u{1F4CB} \u6DFB\u52A0 #${id}`
|
|
3060
|
+
};
|
|
3061
|
+
} catch (err) {
|
|
3062
|
+
return {
|
|
3063
|
+
success: false,
|
|
3064
|
+
data: err instanceof Error ? err.message : String(err),
|
|
3065
|
+
error: "TODO_DEPS_INVALID"
|
|
3066
|
+
};
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
};
|
|
3070
|
+
}
|
|
3071
|
+
function makeTodoMarkRunningTool(todoList) {
|
|
3072
|
+
return {
|
|
3073
|
+
name: "todo_mark_running",
|
|
3074
|
+
kind: "other" /* Other */,
|
|
3075
|
+
description: "\u628A todo \u4ECE pending \u63A8\u8FDB\u5230 running\uFF0C\u8868\u793A\u4F60\u300C\u6B63\u5728\u505A\u300D\u8FD9\u4E00\u6B65\u3002\n\u524D\u63D0\uFF1A\u8BE5 todo \u5B58\u5728\u3001\u5F53\u524D\u662F pending\u3001\u4E14\u6240\u6709 deps \u5DF2 done \u6216 skipped\u3002\n\u5DE5\u4F5C\u6D41\uFF1A\u5148\u8C03 todo_mark_running\uFF0C\u518D\u53BB\u8C03\u5B9E\u9645\u7684\u5DE5\u5177\uFF08read_file / edit_file \u7B49\uFF09\uFF0C\u6700\u540E\u7528 todo_mark_done \u6216 todo_mark_failed \u6536\u5C3E\u3002\n**\u4E0D\u8981\u8DF3\u8FC7 mark_running \u76F4\u63A5 mark_done** \u2014 \u4F1A\u7834\u574F\u4F9D\u8D56\u68C0\u67E5\uFF0C\u4E0B\u6E38\u6B65\u9AA4\u53EF\u80FD\u8BEF\u4EE5\u4E3A\u4F9D\u8D56\u5DF2\u6EE1\u8DB3\u3002",
|
|
3076
|
+
parameters: {
|
|
3077
|
+
type: "object",
|
|
3078
|
+
properties: {
|
|
3079
|
+
id: { type: "number", description: "todo \u7684 id" }
|
|
3080
|
+
},
|
|
3081
|
+
required: ["id"],
|
|
3082
|
+
additionalProperties: false
|
|
3083
|
+
},
|
|
3084
|
+
async execute(args) {
|
|
3085
|
+
if (typeof args?.id !== "number") {
|
|
3086
|
+
return { success: false, data: "\u7F3A\u5C11 id \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3087
|
+
}
|
|
3088
|
+
const item = todoList.items.find((it) => it.id === args.id);
|
|
3089
|
+
if (!item) {
|
|
3090
|
+
return { success: false, data: `todo #${args.id} \u4E0D\u5B58\u5728`, error: "TODO_NOT_FOUND" };
|
|
3091
|
+
}
|
|
3092
|
+
if (item.status !== "pending") {
|
|
3093
|
+
return {
|
|
3094
|
+
success: false,
|
|
3095
|
+
data: `todo #${args.id} \u5F53\u524D\u72B6\u6001\u662F ${item.status}\uFF0C\u53EA\u6709 pending \u53EF\u4EE5\u63A8\u8FDB\u5230 running`,
|
|
3096
|
+
error: "TODO_INVALID_STATE"
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
const ok = todoList.markRunning(args.id);
|
|
3100
|
+
if (!ok) {
|
|
3101
|
+
return {
|
|
3102
|
+
success: false,
|
|
3103
|
+
data: `todo #${args.id} \u4F9D\u8D56\u672A\u5168\u90E8\u5B8C\u6210\uFF08\u4F9D\u8D56: #${item.deps.join(", #")}\uFF09`,
|
|
3104
|
+
error: "TODO_DEPS_NOT_READY"
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
return {
|
|
3108
|
+
success: true,
|
|
3109
|
+
data: `\u5DF2\u5F00\u59CB todo #${args.id}\uFF1A${item.content}`,
|
|
3110
|
+
summary: `\u25B6 \u5F00\u59CB #${args.id}`
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
3113
|
+
};
|
|
3114
|
+
}
|
|
3115
|
+
function makeTodoMarkDoneTool(todoList) {
|
|
3116
|
+
return {
|
|
3117
|
+
name: "todo_mark_done",
|
|
3118
|
+
kind: "other" /* Other */,
|
|
3119
|
+
description: "\u628A todo \u6807\u8BB0\u4E3A\u5B8C\u6210\u3002evidence \u586B\u300C\u5B8C\u6210\u8BC1\u636E\u300D\uFF08\u5982\u300C\u8BFB\u5230 120 \u884C\u300D\u3001\u300Ctypecheck \u901A\u8FC7\u300D\u3001\u300Cedit \u6210\u529F\u300D\uFF09\uFF0C\u4E0D\u586B\u4E5F\u884C\u3002\n\u524D\u63D0\uFF1A\u5F53\u524D\u72B6\u6001\u5FC5\u987B\u662F running\u3002\u82E5\u8FD8\u662F pending\uFF0C\u5148\u8C03 todo_mark_running\u3002",
|
|
3120
|
+
parameters: {
|
|
3121
|
+
type: "object",
|
|
3122
|
+
properties: {
|
|
3123
|
+
id: { type: "number", description: "todo \u7684 id" },
|
|
3124
|
+
evidence: { type: "string", description: "\u5B8C\u6210\u8BC1\u636E\uFF08\u4E00\u53E5\u8BDD\uFF0C\u53EF\u9009\uFF09" }
|
|
3125
|
+
},
|
|
3126
|
+
required: ["id"],
|
|
3127
|
+
additionalProperties: false
|
|
3128
|
+
},
|
|
3129
|
+
async execute(args) {
|
|
3130
|
+
if (typeof args?.id !== "number") {
|
|
3131
|
+
return { success: false, data: "\u7F3A\u5C11 id \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3132
|
+
}
|
|
3133
|
+
const item = todoList.items.find((it) => it.id === args.id);
|
|
3134
|
+
if (!item) {
|
|
3135
|
+
return { success: false, data: `todo #${args.id} \u4E0D\u5B58\u5728`, error: "TODO_NOT_FOUND" };
|
|
3136
|
+
}
|
|
3137
|
+
if (item.status !== "running") {
|
|
3138
|
+
return {
|
|
3139
|
+
success: false,
|
|
3140
|
+
data: `todo #${args.id} \u5F53\u524D\u72B6\u6001\u662F ${item.status}\uFF0C\u53EA\u6709 running \u53EF\u4EE5 mark_done\uFF1B\u5982\u9700\u91CD\u8BD5\u8BF7\u5148 todo_retry`,
|
|
3141
|
+
error: "TODO_INVALID_STATE"
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
const ok = todoList.markDone(args.id, args.evidence);
|
|
3145
|
+
if (!ok) {
|
|
3146
|
+
return { success: false, data: `todo #${args.id} \u72B6\u6001\u8F6C\u6362\u5931\u8D25`, error: "TODO_INVALID" };
|
|
3147
|
+
}
|
|
3148
|
+
return {
|
|
3149
|
+
success: true,
|
|
3150
|
+
data: `\u5DF2\u6807\u8BB0 todo #${args.id} \u5B8C\u6210${args.evidence ? `\uFF1A${args.evidence}` : ""}`,
|
|
3151
|
+
summary: `\u2705 \u5B8C\u6210 #${args.id}`
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
3156
|
+
function makeTodoMarkFailedTool(todoList) {
|
|
3157
|
+
return {
|
|
3158
|
+
name: "todo_mark_failed",
|
|
3159
|
+
kind: "other" /* Other */,
|
|
3160
|
+
description: "\u628A todo \u6807\u8BB0\u4E3A\u5931\u8D25\uFF0Creason \u586B\u300C\u5931\u8D25\u539F\u56E0\u300D\uFF08\u5982\u300Cold_text \u62FC\u9519\u300D\u3001\u300C\u6587\u4EF6\u4E0D\u5B58\u5728\u300D\uFF09\u3002\n\u524D\u63D0\uFF1A\u5F53\u524D\u72B6\u6001\u5FC5\u987B\u662F running\u3002\u82E5\u8FD8\u662F pending\uFF0C\u5148\u8C03 todo_mark_running\u3002\n\u8C03\u7528\u540E\u8BE5 step \u72B6\u6001\u53D8\u4E3A failed\u3002\u60F3\u91CD\u8BD5\uFF1A\u8C03 todo_retry(id) \u91CD\u7F6E\u56DE pending\uFF0C\u518D mark_running \u2192 \u8DD1\u5DE5\u5177 \u2192 mark_done\u3002",
|
|
3161
|
+
parameters: {
|
|
3162
|
+
type: "object",
|
|
3163
|
+
properties: {
|
|
3164
|
+
id: { type: "number", description: "todo \u7684 id" },
|
|
3165
|
+
reason: { type: "string", description: "\u5931\u8D25\u539F\u56E0\uFF08\u4E00\u53E5\u8BDD\uFF09" }
|
|
3166
|
+
},
|
|
3167
|
+
required: ["id", "reason"],
|
|
3168
|
+
additionalProperties: false
|
|
3169
|
+
},
|
|
3170
|
+
async execute(args) {
|
|
3171
|
+
if (typeof args?.id !== "number") {
|
|
3172
|
+
return { success: false, data: "\u7F3A\u5C11 id \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3173
|
+
}
|
|
3174
|
+
if (typeof args?.reason !== "string") {
|
|
3175
|
+
return { success: false, data: "\u7F3A\u5C11 reason \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3176
|
+
}
|
|
3177
|
+
const item = todoList.items.find((it) => it.id === args.id);
|
|
3178
|
+
if (!item) {
|
|
3179
|
+
return { success: false, data: `todo #${args.id} \u4E0D\u5B58\u5728`, error: "TODO_NOT_FOUND" };
|
|
3180
|
+
}
|
|
3181
|
+
if (item.status !== "running") {
|
|
3182
|
+
return {
|
|
3183
|
+
success: false,
|
|
3184
|
+
data: `todo #${args.id} \u5F53\u524D\u72B6\u6001\u662F ${item.status}\uFF0C\u53EA\u6709 running \u53EF\u4EE5 mark_failed`,
|
|
3185
|
+
error: "TODO_INVALID_STATE"
|
|
3186
|
+
};
|
|
3187
|
+
}
|
|
3188
|
+
const ok = todoList.markFailed(args.id, args.reason);
|
|
3189
|
+
if (!ok) {
|
|
3190
|
+
return { success: false, data: `todo #${args.id} \u72B6\u6001\u8F6C\u6362\u5931\u8D25`, error: "TODO_INVALID" };
|
|
3191
|
+
}
|
|
3192
|
+
return {
|
|
3193
|
+
success: true,
|
|
3194
|
+
data: `\u5DF2\u6807\u8BB0 todo #${args.id} \u5931\u8D25\uFF1A${args.reason}`,
|
|
3195
|
+
summary: `\u274C \u5931\u8D25 #${args.id}`
|
|
3196
|
+
};
|
|
3197
|
+
}
|
|
3198
|
+
};
|
|
3199
|
+
}
|
|
3200
|
+
function makeTodoRetryTool(todoList) {
|
|
3201
|
+
return {
|
|
3202
|
+
name: "todo_retry",
|
|
3203
|
+
kind: "other" /* Other */,
|
|
3204
|
+
description: "\u628A\u5931\u8D25\u7684 todo \u91CD\u7F6E\u56DE pending\uFF08\u6E05\u7A7A evidence\uFF09\uFF0C\u7136\u540E\u4F60\u53EF\u4EE5\u91CD\u65B0\u8D70 todo_mark_running \u2192 \u8DD1\u5DE5\u5177 \u2192 todo_mark_done \u7684\u6D41\u7A0B\u3002\n\u524D\u63D0\uFF1A\u5F53\u524D\u72B6\u6001\u5FC5\u987B\u662F failed\u3002done / skipped / running \u4E0D\u5141\u8BB8\u91CD\u8BD5\uFF08done \u4E0D\u53EF\u53CD\u6094\u3001running \u5E94\u5148 mark_failed\uFF09\u3002",
|
|
3205
|
+
parameters: {
|
|
3206
|
+
type: "object",
|
|
3207
|
+
properties: {
|
|
3208
|
+
id: { type: "number", description: "todo \u7684 id" }
|
|
3209
|
+
},
|
|
3210
|
+
required: ["id"],
|
|
3211
|
+
additionalProperties: false
|
|
3212
|
+
},
|
|
3213
|
+
async execute(args) {
|
|
3214
|
+
if (typeof args?.id !== "number") {
|
|
3215
|
+
return { success: false, data: "\u7F3A\u5C11 id \u53C2\u6570", error: "INVALID_ARGS" };
|
|
3216
|
+
}
|
|
3217
|
+
const item = todoList.items.find((it) => it.id === args.id);
|
|
3218
|
+
if (!item) {
|
|
3219
|
+
return { success: false, data: `todo #${args.id} \u4E0D\u5B58\u5728`, error: "TODO_NOT_FOUND" };
|
|
3220
|
+
}
|
|
3221
|
+
if (item.status !== "failed") {
|
|
3222
|
+
return {
|
|
3223
|
+
success: false,
|
|
3224
|
+
data: `todo #${args.id} \u5F53\u524D\u72B6\u6001\u662F ${item.status}\uFF0C\u53EA\u6709 failed \u53EF\u4EE5\u91CD\u8BD5`,
|
|
3225
|
+
error: "TODO_INVALID_STATE"
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3228
|
+
const ok = todoList.resetForRetry(args.id);
|
|
3229
|
+
if (!ok) {
|
|
3230
|
+
return { success: false, data: `todo #${args.id} \u72B6\u6001\u8F6C\u6362\u5931\u8D25`, error: "TODO_INVALID" };
|
|
3231
|
+
}
|
|
3232
|
+
return {
|
|
3233
|
+
success: true,
|
|
3234
|
+
data: `\u5DF2\u91CD\u7F6E todo #${args.id} \u4E3A pending\uFF0C\u53EF\u91CD\u65B0\u8DD1`,
|
|
3235
|
+
summary: `\u{1F504} \u91CD\u8BD5 #${args.id}`
|
|
3236
|
+
};
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
// src/checkpoint/git-checkpoint.ts
|
|
3242
|
+
import { execFile } from "child_process";
|
|
3243
|
+
import { promisify } from "util";
|
|
3244
|
+
var execFileAsync = promisify(execFile);
|
|
3245
|
+
var EXEC_OPTIONS = { windowsHide: true };
|
|
3246
|
+
async function isGitRepo(cwd) {
|
|
3247
|
+
try {
|
|
3248
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd, ...EXEC_OPTIONS });
|
|
3249
|
+
return true;
|
|
3250
|
+
} catch {
|
|
3251
|
+
return false;
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
async function hasCommits(cwd) {
|
|
3255
|
+
try {
|
|
3256
|
+
await execFileAsync("git", ["rev-parse", "--verify", "HEAD"], { cwd, ...EXEC_OPTIONS });
|
|
3257
|
+
return true;
|
|
3258
|
+
} catch {
|
|
3259
|
+
return false;
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
async function hasWorkingChanges(cwd) {
|
|
3263
|
+
const out = await execFileAsync("git", ["status", "--porcelain"], { cwd, ...EXEC_OPTIONS });
|
|
3264
|
+
return out.stdout.trim().length > 0;
|
|
3265
|
+
}
|
|
3266
|
+
async function git(args, cwd) {
|
|
3267
|
+
try {
|
|
3268
|
+
const { stdout } = await execFileAsync("git", args, { cwd, ...EXEC_OPTIONS });
|
|
3269
|
+
return stdout;
|
|
3270
|
+
} catch (err) {
|
|
3271
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3272
|
+
throw new Error(`git ${args.join(" ")} \u5931\u8D25: ${msg}`);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
async function listStashShas(cwd) {
|
|
3276
|
+
const out = await git(["stash", "list", "--format=%H"], cwd);
|
|
3277
|
+
return out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
3278
|
+
}
|
|
3279
|
+
async function createCheckpoint(cwd) {
|
|
3280
|
+
const timestamp = Date.now();
|
|
3281
|
+
const inRepo = await isGitRepo(cwd);
|
|
3282
|
+
if (!inRepo) return { stashSha: "", timestamp, cwd, isGitRepo: false };
|
|
3283
|
+
if (!await hasCommits(cwd)) return { stashSha: "", timestamp, cwd, isGitRepo: true };
|
|
3284
|
+
if (!await hasWorkingChanges(cwd)) return { stashSha: "", timestamp, cwd, isGitRepo: true };
|
|
3285
|
+
const beforeShas = await listStashShas(cwd);
|
|
3286
|
+
await git(["stash", "push", "-m", `dskcode-cp-${timestamp}`, "-u"], cwd);
|
|
3287
|
+
const newShas = await listStashShas(cwd);
|
|
3288
|
+
if (newShas.length === 0) throw new Error("git stash push \u672A\u80FD\u521B\u5EFA stash entry");
|
|
3289
|
+
const newSha = newShas.find((s) => !beforeShas.includes(s)) ?? newShas[0];
|
|
3290
|
+
await git(["stash", "apply", newSha], cwd);
|
|
3291
|
+
return { stashSha: newSha, timestamp, cwd, isGitRepo: true };
|
|
3292
|
+
}
|
|
3293
|
+
async function restoreCheckpointForce(checkpoint) {
|
|
3294
|
+
if (!checkpoint.isGitRepo) throw new Error("\u975E git \u4ED3\u5E93\uFF0C\u65E0\u6CD5\u6062\u590D\u6587\u4EF6\u72B6\u6001");
|
|
3295
|
+
if (!checkpoint.stashSha) throw new Error("\u68C0\u67E5\u70B9\u4E3A\u7A7A\uFF08\u5DE5\u4F5C\u533A\u539F\u672C\u5C31\u5E72\u51C0\uFF09\uFF0C\u65E0\u9700\u6062\u590D");
|
|
2639
3296
|
const { cwd, stashSha } = checkpoint;
|
|
2640
3297
|
const currentShas = await listStashShas(cwd);
|
|
2641
3298
|
if (!currentShas.includes(stashSha)) {
|
|
@@ -2849,6 +3506,10 @@ var ConversationLogger = class _ConversationLogger {
|
|
|
2849
3506
|
logAssistantText(content, round) {
|
|
2850
3507
|
this.log({ ts: Date.now(), type: "assistant_text", content, round });
|
|
2851
3508
|
}
|
|
3509
|
+
/** 记录思考链(thinking 模式下模型的 CoT) */
|
|
3510
|
+
logReasoning(content, round) {
|
|
3511
|
+
this.log({ ts: Date.now(), type: "reasoning", content, round });
|
|
3512
|
+
}
|
|
2852
3513
|
/** 记录工具调用 */
|
|
2853
3514
|
logToolCall(name, callId, args, round) {
|
|
2854
3515
|
this.log({ ts: Date.now(), type: "tool_call", name, callId, arguments: args, round });
|
|
@@ -2999,6 +3660,10 @@ var Session = class _Session {
|
|
|
2999
3660
|
#reflector;
|
|
3000
3661
|
/** 本轮工具执行结果(仅在 chat() 循环内使用;用于下一轮注入 reflection) */
|
|
3001
3662
|
#lastRoundResults = null;
|
|
3663
|
+
/** Harness 任务列表(仅在 enableHarness 时非 null) */
|
|
3664
|
+
#todoList;
|
|
3665
|
+
/** 本会话内是否已发出过「未拆 todo」护栏提示(避免每轮骚扰) */
|
|
3666
|
+
#harnessHintEmitted = false;
|
|
3002
3667
|
/**
|
|
3003
3668
|
* 构造一个 Session。
|
|
3004
3669
|
*
|
|
@@ -3028,7 +3693,8 @@ var Session = class _Session {
|
|
|
3028
3693
|
writeRoots: options?.writeRoots ?? [options?.cwd ?? process.cwd()],
|
|
3029
3694
|
enableCheckpoint: options?.enableCheckpoint ?? true,
|
|
3030
3695
|
enableLog: options?.enableLog ?? true,
|
|
3031
|
-
enableReflection: options?.enableReflection !== false
|
|
3696
|
+
enableReflection: options?.enableReflection !== false,
|
|
3697
|
+
enableHarness: options?.enableHarness !== false
|
|
3032
3698
|
};
|
|
3033
3699
|
this.#sessionId = options?.sessionId ?? SessionStore.newId();
|
|
3034
3700
|
this.#store = options?.store === false ? null : options?.store ?? new SessionStore();
|
|
@@ -3036,9 +3702,23 @@ var Session = class _Session {
|
|
|
3036
3702
|
this.#logger = new ConversationLogger(this.#sessionId, this.#options.cwd, {
|
|
3037
3703
|
enabled: this.#options.enableLog
|
|
3038
3704
|
});
|
|
3039
|
-
this.#logger.logSessionStart(
|
|
3705
|
+
this.#logger.logSessionStart(
|
|
3706
|
+
this.#sessionId,
|
|
3707
|
+
this.#options.cwd,
|
|
3708
|
+
this.#provider.model(),
|
|
3709
|
+
this.#mode
|
|
3710
|
+
);
|
|
3040
3711
|
this.#stormDetector = new StormDetector({ threshold: 3 });
|
|
3041
3712
|
this.#reflector = this.#options.enableReflection ? new Reflector() : null;
|
|
3713
|
+
if (this.#options.enableHarness) {
|
|
3714
|
+
const todoList = new TodoList();
|
|
3715
|
+
this.#todoList = todoList;
|
|
3716
|
+
for (const t of createHarnessTools(todoList)) {
|
|
3717
|
+
this.#toolRegistry.registerErased(eraseTool(t));
|
|
3718
|
+
}
|
|
3719
|
+
} else {
|
|
3720
|
+
this.#todoList = null;
|
|
3721
|
+
}
|
|
3042
3722
|
}
|
|
3043
3723
|
/** 当前会话的完整消息历史(只读视图) */
|
|
3044
3724
|
get messages() {
|
|
@@ -3118,6 +3798,7 @@ var Session = class _Session {
|
|
|
3118
3798
|
const startTime = Date.now();
|
|
3119
3799
|
let toolRounds = 0;
|
|
3120
3800
|
const toolExecutor = this.#buildToolExecutor();
|
|
3801
|
+
this.#harnessHintEmitted = false;
|
|
3121
3802
|
try {
|
|
3122
3803
|
while (toolRounds < this.#options.maxToolRounds) {
|
|
3123
3804
|
let systemPrompt = this.#buildSystemPrompt();
|
|
@@ -3129,20 +3810,21 @@ var Session = class _Session {
|
|
|
3129
3810
|
if (reflections.length > 0) {
|
|
3130
3811
|
systemPrompt = this.#reflector.injectIntoPrompt(systemPrompt, reflections);
|
|
3131
3812
|
this.#logger.logReflections(
|
|
3132
|
-
reflections.map((r) => ({
|
|
3813
|
+
reflections.map((r) => ({
|
|
3814
|
+
category: r.category,
|
|
3815
|
+
toolName: r.toolName,
|
|
3816
|
+
hint: r.hint
|
|
3817
|
+
}))
|
|
3133
3818
|
);
|
|
3134
3819
|
}
|
|
3135
3820
|
this.#lastRoundResults = null;
|
|
3136
3821
|
}
|
|
3137
|
-
const [trimmed] = trimMessages(
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
preserveRecentRounds: this.#options.preserveRecentRounds
|
|
3144
|
-
}
|
|
3145
|
-
);
|
|
3822
|
+
const [trimmed] = trimMessages([...this.#messages], {
|
|
3823
|
+
model: this.#provider.model(),
|
|
3824
|
+
reservedForOutput: this.#options.reservedForOutput,
|
|
3825
|
+
systemPrompt,
|
|
3826
|
+
preserveRecentRounds: this.#options.preserveRecentRounds
|
|
3827
|
+
});
|
|
3146
3828
|
const apiMessages = buildApiMessages(systemPrompt, trimmed);
|
|
3147
3829
|
const toolDefs = buildToolDefinitions(this.#toolRegistry, this.#mode);
|
|
3148
3830
|
const stream = this.#provider.chat(apiMessages, {
|
|
@@ -3155,6 +3837,7 @@ var Session = class _Session {
|
|
|
3155
3837
|
});
|
|
3156
3838
|
const modelId = this.#provider.model();
|
|
3157
3839
|
let accumulatedText = "";
|
|
3840
|
+
let accumulatedReasoning = "";
|
|
3158
3841
|
let lastUsage;
|
|
3159
3842
|
let lastToolCalls;
|
|
3160
3843
|
let _lastFinishReason = null;
|
|
@@ -3165,6 +3848,10 @@ var Session = class _Session {
|
|
|
3165
3848
|
let lastEmitMs = 0;
|
|
3166
3849
|
const EST_EMIT_INTERVAL_MS = 300;
|
|
3167
3850
|
for await (const chunk of stream) {
|
|
3851
|
+
if (chunk.reasoningContent) {
|
|
3852
|
+
accumulatedReasoning += chunk.reasoningContent;
|
|
3853
|
+
yield { type: "reasoning_delta", content: chunk.reasoningContent };
|
|
3854
|
+
}
|
|
3168
3855
|
if (chunk.content) {
|
|
3169
3856
|
accumulatedText += chunk.content;
|
|
3170
3857
|
yield { type: "text_delta", content: chunk.content };
|
|
@@ -3186,7 +3873,8 @@ var Session = class _Session {
|
|
|
3186
3873
|
};
|
|
3187
3874
|
}
|
|
3188
3875
|
}
|
|
3189
|
-
if (chunk.toolCalls && chunk.toolCalls.length > 0)
|
|
3876
|
+
if (chunk.toolCalls && chunk.toolCalls.length > 0)
|
|
3877
|
+
lastToolCalls = chunk.toolCalls;
|
|
3190
3878
|
if (chunk.usage) {
|
|
3191
3879
|
lastUsage = chunk.usage;
|
|
3192
3880
|
const realCost = calculateCost(chunk.usage, modelId);
|
|
@@ -3229,15 +3917,22 @@ var Session = class _Session {
|
|
|
3229
3917
|
yield { type: "usage", usage: lastUsage, model: modelId };
|
|
3230
3918
|
}
|
|
3231
3919
|
const assistantMsg = { role: "assistant", content: accumulatedText };
|
|
3232
|
-
if (lastToolCalls && lastToolCalls.length > 0)
|
|
3920
|
+
if (lastToolCalls && lastToolCalls.length > 0)
|
|
3921
|
+
assistantMsg.toolCalls = lastToolCalls;
|
|
3233
3922
|
this.#messages.push(assistantMsg);
|
|
3234
3923
|
this.#logger.logAssistantText(accumulatedText, toolRounds);
|
|
3924
|
+
if (accumulatedReasoning) {
|
|
3925
|
+
this.#logger.logReasoning(accumulatedReasoning, toolRounds);
|
|
3926
|
+
}
|
|
3235
3927
|
if (lastToolCalls && lastToolCalls.length > 0) {
|
|
3236
3928
|
yield { type: "tool_calls", calls: lastToolCalls };
|
|
3237
3929
|
for (const tc of lastToolCalls) {
|
|
3238
3930
|
this.#logger.logToolCall(tc.name, tc.id, tc.arguments, toolRounds);
|
|
3239
3931
|
}
|
|
3240
|
-
const stormBroken = this.#stormDetector.shouldBreak(
|
|
3932
|
+
const stormBroken = this.#stormDetector.shouldBreak(
|
|
3933
|
+
this.#stormRecords,
|
|
3934
|
+
lastToolCalls
|
|
3935
|
+
);
|
|
3241
3936
|
if (stormBroken) {
|
|
3242
3937
|
const stormMsg = "\n\u26A0\uFE0F \u540C\u4E00\u5DE5\u5177\u91CD\u590D\u51FA\u9519\uFF0C\u5DF2\u5F3A\u5236\u5207\u6362\u7B56\u7565\n";
|
|
3243
3938
|
yield { type: "text_delta", content: stormMsg };
|
|
@@ -3249,7 +3944,6 @@ var Session = class _Session {
|
|
|
3249
3944
|
}
|
|
3250
3945
|
const results = await toolExecutor.executeBatch(lastToolCalls);
|
|
3251
3946
|
this.#stormRecords = results.records;
|
|
3252
|
-
console.log("results", results);
|
|
3253
3947
|
this.#lastRoundResults = results.items.map((it) => {
|
|
3254
3948
|
const tool = this.#toolRegistry.get(it.name);
|
|
3255
3949
|
return {
|
|
@@ -3260,7 +3954,13 @@ var Session = class _Session {
|
|
|
3260
3954
|
};
|
|
3261
3955
|
});
|
|
3262
3956
|
for (const item of results.items) {
|
|
3263
|
-
|
|
3957
|
+
const todoSnapshot = item.name.startsWith("todo_") && this.#todoList ? this.#todoList.items : void 0;
|
|
3958
|
+
yield {
|
|
3959
|
+
type: "tool_result",
|
|
3960
|
+
name: item.name,
|
|
3961
|
+
result: item.result,
|
|
3962
|
+
todoSnapshot
|
|
3963
|
+
};
|
|
3264
3964
|
this.#logger.logToolResult(
|
|
3265
3965
|
item.name,
|
|
3266
3966
|
item.callId,
|
|
@@ -3271,7 +3971,8 @@ var Session = class _Session {
|
|
|
3271
3971
|
toolRounds
|
|
3272
3972
|
);
|
|
3273
3973
|
let toolContent = item.result.data;
|
|
3274
|
-
if (item.result.diff && item.result.diff.patch)
|
|
3974
|
+
if (item.result.diff && item.result.diff.patch)
|
|
3975
|
+
toolContent += `
|
|
3275
3976
|
|
|
3276
3977
|
${item.result.diff.patch}`;
|
|
3277
3978
|
this.#messages.push({
|
|
@@ -3281,9 +3982,16 @@ ${item.result.diff.patch}`;
|
|
|
3281
3982
|
name: item.name
|
|
3282
3983
|
});
|
|
3283
3984
|
}
|
|
3985
|
+
this.#maybeEmitHarnessHint(results.items);
|
|
3284
3986
|
toolRounds++;
|
|
3285
3987
|
continue;
|
|
3286
3988
|
}
|
|
3989
|
+
if (this.#todoList && this.#todoList.items.length > 0 && this.#todoList.isAllTerminated()) {
|
|
3990
|
+
this.#messages.push({
|
|
3991
|
+
role: "user",
|
|
3992
|
+
content: "[\u7CFB\u7EDF] \u5168\u90E8 todo \u5DF2\u5B8C\u6210\u3002\u8BF7\u505A\u4E00\u6B21\u4EFB\u52A1\u81EA\u68C0\uFF1A\u91CD\u65B0\u8BFB\u53D6\u672C\u6B21\u4FEE\u6539\u8FC7\u7684\u6587\u4EF6\uFF0C\u786E\u8BA4\u6539\u52A8\u6B63\u786E\u65E0\u8BEF\u3001\u7C7B\u578B\u517C\u5BB9\u3001\u6CA1\u6709\u9057\u6F0F\u3002\u5982\u6709\u95EE\u9898\u8BF7\u65B0\u589E todo \u4FEE\u590D\uFF1B\u786E\u8BA4\u65E0\u8BEF\u540E\u8F93\u51FA\u6700\u7EC8\u603B\u7ED3\u3002"
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3287
3995
|
break;
|
|
3288
3996
|
}
|
|
3289
3997
|
} catch (err) {
|
|
@@ -3439,7 +4147,11 @@ ${item.result.diff.patch}`;
|
|
|
3439
4147
|
if (!store) throw new Error("resume \u9700\u8981\u542F\u7528\u6301\u4E45\u5316\uFF08options.store \u4E0D\u80FD\u4E3A false\uFF09");
|
|
3440
4148
|
const stored = await store.load(id);
|
|
3441
4149
|
if (!stored) throw new Error(`\u4F1A\u8BDD ${id} \u4E0D\u5B58\u5728`);
|
|
3442
|
-
const session = new _Session(provider, tools, costTracker, {
|
|
4150
|
+
const session = new _Session(provider, tools, costTracker, {
|
|
4151
|
+
...options,
|
|
4152
|
+
sessionId: id,
|
|
4153
|
+
store
|
|
4154
|
+
});
|
|
3443
4155
|
for (const m of stored.messages) {
|
|
3444
4156
|
session.#messages.push({
|
|
3445
4157
|
role: m.role,
|
|
@@ -3471,7 +4183,12 @@ ${item.result.diff.patch}`;
|
|
|
3471
4183
|
for (const [index, checkpoint] of this.#checkpoints) {
|
|
3472
4184
|
const msg = this.#messages[index];
|
|
3473
4185
|
if (!msg || msg.role !== "user") continue;
|
|
3474
|
-
result.push({
|
|
4186
|
+
result.push({
|
|
4187
|
+
index,
|
|
4188
|
+
preview: msg.content.slice(0, 80),
|
|
4189
|
+
timestamp: checkpoint.timestamp,
|
|
4190
|
+
isGitRepo: checkpoint.isGitRepo
|
|
4191
|
+
});
|
|
3475
4192
|
}
|
|
3476
4193
|
return result.sort((a, b) => a.index - b.index);
|
|
3477
4194
|
}
|
|
@@ -3599,8 +4316,38 @@ ${item.result.diff.patch}`;
|
|
|
3599
4316
|
projectContext: this.#options.projectContext ?? void 0,
|
|
3600
4317
|
cwd: this.#options.cwd
|
|
3601
4318
|
};
|
|
3602
|
-
|
|
3603
|
-
|
|
4319
|
+
let base;
|
|
4320
|
+
if (this.#mode === "plan") base = buildPlanSystemPrompt(opts);
|
|
4321
|
+
else base = buildSystemPrompt(opts);
|
|
4322
|
+
if (this.#todoList && this.#todoList.items.length > 0) {
|
|
4323
|
+
base = base + "\n\n" + this.#todoList.toMarkdown();
|
|
4324
|
+
}
|
|
4325
|
+
return base;
|
|
4326
|
+
}
|
|
4327
|
+
/**
|
|
4328
|
+
* Harness 护栏:模型跳过 todo_add 直接动手时,主动发一条提示让其重评。
|
|
4329
|
+
*
|
|
4330
|
+
* 触发条件(全部需满足):
|
|
4331
|
+
* 1. Harness 开启(#todoList 非空)
|
|
4332
|
+
* 2. todoList 仍为空(未拆 todo)
|
|
4333
|
+
* 3. 本会话内未提示过(#harnessHintEmitted 为 false)
|
|
4334
|
+
* 4. 本轮调了 ≥1 个**非 todo_* 的工具**(说明模型跳过了 todo_add 直接干活)
|
|
4335
|
+
*
|
|
4336
|
+
* 动作:push 一条 user role 消息到 #messages,让下一轮 LLM 看到;设 #harnessHintEmitted = true。
|
|
4337
|
+
*
|
|
4338
|
+
* @sideEffect 写 #messages / #harnessHintEmitted
|
|
4339
|
+
*/
|
|
4340
|
+
#maybeEmitHarnessHint(items) {
|
|
4341
|
+
if (!this.#todoList) return;
|
|
4342
|
+
if (this.#todoList.items.length > 0) return;
|
|
4343
|
+
if (this.#harnessHintEmitted) return;
|
|
4344
|
+
const hasNonTodo = items.some((it) => !it.name.startsWith("todo_"));
|
|
4345
|
+
if (!hasNonTodo) return;
|
|
4346
|
+
this.#harnessHintEmitted = true;
|
|
4347
|
+
this.#messages.push({
|
|
4348
|
+
role: "user",
|
|
4349
|
+
content: "[\u7CFB\u7EDF\u63D0\u793A] \u4F60\u8FD8\u6CA1\u6709 todo \u8FC7\uFF0C\u4F46\u5DF2\u7ECF\u8C03\u4E86\u5177\u4F53\u5DE5\u5177\u3002\n\u8BF7\u56DE\u987E\u4F60\u521A\u505A\u7684\u4E8B\uFF1A\u8FD9\u662F\u300C\u7B80\u5355\u300D\u4EFB\u52A1\uFF081 \u8F6E 1 \u5DE5\u5177\u80FD\u5B8C\u6210\uFF09\u8FD8\u662F\u300C\u590D\u6742\u300D\u4EFB\u52A1\uFF1F\n\u5982\u679C\u662F\u590D\u6742\uFF08\u6539\u4E86/\u521B\u5EFA\u4E86/\u8981\u8BFB\u540E\u6539/\u8DE8\u591A\u79CD\u5DE5\u5177\uFF09\uFF0C\u8BF7\u505C\u4E0B\uFF0C\u5148\u8C03 todo_add \u62C6\u89E3 3-7 \u6B65\u518D\u7EE7\u7EED\u3002\n\u5982\u679C\u662F\u7B80\u5355\uFF0C\u5FFD\u7565\u672C\u63D0\u793A\u3002\n\uFF08\u672C\u63D0\u793A\u672C\u4F1A\u8BDD\u4EC5\u53D1\u4E00\u6B21\uFF0C\u540E\u7EED\u4E0D\u518D\u63D0\u9192\u3002\uFF09"
|
|
4350
|
+
});
|
|
3604
4351
|
}
|
|
3605
4352
|
};
|
|
3606
4353
|
|
|
@@ -3613,8 +4360,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
|
|
|
3613
4360
|
var DEFAULT_MAX_OUTPUT_LENGTH = 5e4;
|
|
3614
4361
|
var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
3615
4362
|
var isWindows = process2.platform === "win32";
|
|
4363
|
+
function stripMentionPrefix(inputPath) {
|
|
4364
|
+
if (inputPath.startsWith("@")) return inputPath.slice(1);
|
|
4365
|
+
return inputPath;
|
|
4366
|
+
}
|
|
3616
4367
|
function resolvePath(inputPath, cwd) {
|
|
3617
|
-
const
|
|
4368
|
+
const stripped = stripMentionPrefix(inputPath);
|
|
4369
|
+
const resolved = isAbsolute(stripped) ? stripped : resolve(cwd, stripped);
|
|
3618
4370
|
return resolve(resolved);
|
|
3619
4371
|
}
|
|
3620
4372
|
async function realPath(target) {
|
|
@@ -4010,6 +4762,10 @@ function detectEol(text) {
|
|
|
4010
4762
|
function hasTrailingNewline(text) {
|
|
4011
4763
|
return text.endsWith("\n") || text.endsWith("\r\n");
|
|
4012
4764
|
}
|
|
4765
|
+
function toLf(text) {
|
|
4766
|
+
if (!text.includes("\r")) return text;
|
|
4767
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
4768
|
+
}
|
|
4013
4769
|
function normalizeEol(originalContent, newContent) {
|
|
4014
4770
|
const targetEol = detectEol(originalContent);
|
|
4015
4771
|
const lines = newContent.replace(/\r\n/g, "\n").split("\n");
|
|
@@ -4101,7 +4857,7 @@ var readFileTool = {
|
|
|
4101
4857
|
}
|
|
4102
4858
|
}
|
|
4103
4859
|
const content = await readFile5(filePath, "utf-8");
|
|
4104
|
-
const lines = content.split("\n");
|
|
4860
|
+
const lines = toLf(content).split("\n");
|
|
4105
4861
|
if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
|
|
4106
4862
|
lines.pop();
|
|
4107
4863
|
}
|
|
@@ -4209,6 +4965,7 @@ var writeFileTool = {
|
|
|
4209
4965
|
|
|
4210
4966
|
// src/tool/builtins/edit-file.ts
|
|
4211
4967
|
import { readFile as readFile7 } from "fs/promises";
|
|
4968
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
4212
4969
|
import { basename as basename3 } from "path";
|
|
4213
4970
|
var editFileTool = {
|
|
4214
4971
|
name: "edit_file",
|
|
@@ -4252,7 +5009,9 @@ var editFileTool = {
|
|
|
4252
5009
|
}
|
|
4253
5010
|
try {
|
|
4254
5011
|
const content = await readFile7(filePath, "utf-8");
|
|
4255
|
-
const
|
|
5012
|
+
const contentN = toLf(content);
|
|
5013
|
+
const oldTextN = toLf(args.old_text);
|
|
5014
|
+
const firstIndex = contentN.indexOf(oldTextN);
|
|
4256
5015
|
if (firstIndex === -1) {
|
|
4257
5016
|
return {
|
|
4258
5017
|
success: false,
|
|
@@ -4260,7 +5019,7 @@ var editFileTool = {
|
|
|
4260
5019
|
error: "TEXT_NOT_FOUND"
|
|
4261
5020
|
};
|
|
4262
5021
|
}
|
|
4263
|
-
const secondIndex =
|
|
5022
|
+
const secondIndex = contentN.indexOf(oldTextN, firstIndex + 1);
|
|
4264
5023
|
if (secondIndex !== -1) {
|
|
4265
5024
|
return {
|
|
4266
5025
|
success: false,
|
|
@@ -4268,14 +5027,15 @@ var editFileTool = {
|
|
|
4268
5027
|
error: "TEXT_MULTIPLE_MATCHES"
|
|
4269
5028
|
};
|
|
4270
5029
|
}
|
|
4271
|
-
const
|
|
4272
|
-
|
|
4273
|
-
|
|
5030
|
+
const newContentN = contentN.slice(0, firstIndex) + toLf(args.new_text) + contentN.slice(firstIndex + oldTextN.length);
|
|
5031
|
+
const writtenContent = normalizeEol(content, newContentN);
|
|
5032
|
+
await writeFile5(filePath, writtenContent, "utf-8");
|
|
5033
|
+
const diff = computeFileDiff(content, writtenContent, filePath);
|
|
4274
5034
|
diff.existedBefore = true;
|
|
4275
|
-
const beforeText =
|
|
5035
|
+
const beforeText = contentN.slice(0, firstIndex);
|
|
4276
5036
|
const startLine = beforeText.split("\n").length;
|
|
4277
|
-
const oldLines =
|
|
4278
|
-
const newLines = args.new_text.split("\n").length;
|
|
5037
|
+
const oldLines = oldTextN.split("\n").length;
|
|
5038
|
+
const newLines = toLf(args.new_text).split("\n").length;
|
|
4279
5039
|
const diffSummary = `+${diff.additions} -${diff.deletions}`;
|
|
4280
5040
|
const summary = `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (+${diff.additions} -${diff.deletions})`;
|
|
4281
5041
|
return {
|
|
@@ -4300,6 +5060,7 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
|
|
|
4300
5060
|
|
|
4301
5061
|
// src/tool/builtins/multi-edit.ts
|
|
4302
5062
|
import { readFile as readFile8 } from "fs/promises";
|
|
5063
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
4303
5064
|
import { basename as basename4 } from "path";
|
|
4304
5065
|
var multiEditTool = {
|
|
4305
5066
|
name: "multi_edit",
|
|
@@ -4346,7 +5107,7 @@ var multiEditTool = {
|
|
|
4346
5107
|
}
|
|
4347
5108
|
try {
|
|
4348
5109
|
const originalContent = await readFile8(filePath, "utf-8");
|
|
4349
|
-
let currentContent = originalContent;
|
|
5110
|
+
let currentContent = toLf(originalContent);
|
|
4350
5111
|
for (let idx = 0; idx < args.edits.length; idx++) {
|
|
4351
5112
|
const step = args.edits[idx];
|
|
4352
5113
|
if (typeof step.oldText !== "string") {
|
|
@@ -4356,10 +5117,19 @@ var multiEditTool = {
|
|
|
4356
5117
|
error: "INVALID_STEP_ARGS"
|
|
4357
5118
|
};
|
|
4358
5119
|
}
|
|
5120
|
+
if (typeof step.newText !== "string") {
|
|
5121
|
+
return {
|
|
5122
|
+
success: false,
|
|
5123
|
+
data: `\u7B2C ${idx + 1} \u6B65\uFF1A\u7F3A\u5C11\u6709\u6548\u7684 newText`,
|
|
5124
|
+
error: "INVALID_STEP_ARGS"
|
|
5125
|
+
};
|
|
5126
|
+
}
|
|
5127
|
+
const oldTextN = toLf(step.oldText);
|
|
5128
|
+
const newTextN = toLf(step.newText);
|
|
4359
5129
|
if (step.replaceAll) {
|
|
4360
5130
|
let count = 0;
|
|
4361
5131
|
let pos = -1;
|
|
4362
|
-
while ((pos = currentContent.indexOf(
|
|
5132
|
+
while ((pos = currentContent.indexOf(oldTextN, pos + 1)) !== -1) {
|
|
4363
5133
|
count++;
|
|
4364
5134
|
}
|
|
4365
5135
|
if (count === 0) {
|
|
@@ -4369,9 +5139,9 @@ var multiEditTool = {
|
|
|
4369
5139
|
error: "TEXT_NOT_FOUND"
|
|
4370
5140
|
};
|
|
4371
5141
|
}
|
|
4372
|
-
currentContent = currentContent.split(
|
|
5142
|
+
currentContent = currentContent.split(oldTextN).join(newTextN);
|
|
4373
5143
|
} else {
|
|
4374
|
-
const firstIdx = currentContent.indexOf(
|
|
5144
|
+
const firstIdx = currentContent.indexOf(oldTextN);
|
|
4375
5145
|
if (firstIdx === -1) {
|
|
4376
5146
|
return {
|
|
4377
5147
|
success: false,
|
|
@@ -4379,7 +5149,7 @@ var multiEditTool = {
|
|
|
4379
5149
|
error: "TEXT_NOT_FOUND"
|
|
4380
5150
|
};
|
|
4381
5151
|
}
|
|
4382
|
-
const secondIdx = currentContent.indexOf(
|
|
5152
|
+
const secondIdx = currentContent.indexOf(oldTextN, firstIdx + 1);
|
|
4383
5153
|
if (secondIdx !== -1) {
|
|
4384
5154
|
return {
|
|
4385
5155
|
success: false,
|
|
@@ -4387,11 +5157,12 @@ var multiEditTool = {
|
|
|
4387
5157
|
error: "TEXT_MULTIPLE_MATCHES"
|
|
4388
5158
|
};
|
|
4389
5159
|
}
|
|
4390
|
-
currentContent = currentContent.
|
|
5160
|
+
currentContent = currentContent.slice(0, firstIdx) + newTextN + currentContent.slice(firstIdx + oldTextN.length);
|
|
4391
5161
|
}
|
|
4392
5162
|
}
|
|
4393
|
-
|
|
4394
|
-
|
|
5163
|
+
const writtenContent = normalizeEol(originalContent, currentContent);
|
|
5164
|
+
await writeFile6(filePath, writtenContent, "utf-8");
|
|
5165
|
+
const diff = computeFileDiff(originalContent, writtenContent, filePath);
|
|
4395
5166
|
diff.existedBefore = true;
|
|
4396
5167
|
return {
|
|
4397
5168
|
success: true,
|
|
@@ -4414,11 +5185,13 @@ var multiEditTool = {
|
|
|
4414
5185
|
|
|
4415
5186
|
// src/tool/builtins/delete-range.ts
|
|
4416
5187
|
import { readFile as readFile9 } from "fs/promises";
|
|
5188
|
+
import { writeFile as writeFile7 } from "fs/promises";
|
|
4417
5189
|
import { basename as basename5 } from "path";
|
|
4418
5190
|
function findUniqueLine(lines, anchor, label) {
|
|
5191
|
+
const anchorN = toLf(anchor);
|
|
4419
5192
|
const matches = [];
|
|
4420
5193
|
for (let i = 0; i < lines.length; i++) {
|
|
4421
|
-
if (lines[i] ===
|
|
5194
|
+
if (toLf(lines[i]) === anchorN) {
|
|
4422
5195
|
matches.push(i);
|
|
4423
5196
|
}
|
|
4424
5197
|
}
|
|
@@ -4477,7 +5250,7 @@ var deleteRangeTool = {
|
|
|
4477
5250
|
}
|
|
4478
5251
|
try {
|
|
4479
5252
|
const content = await readFile9(filePath, "utf-8");
|
|
4480
|
-
const lines = content.split("\n");
|
|
5253
|
+
const lines = toLf(content).split("\n");
|
|
4481
5254
|
const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
|
|
4482
5255
|
if ("error" in startResult) {
|
|
4483
5256
|
return { success: false, data: startResult.error, error: "ANCHOR_NOT_FOUND" };
|
|
@@ -4505,9 +5278,10 @@ var deleteRangeTool = {
|
|
|
4505
5278
|
};
|
|
4506
5279
|
}
|
|
4507
5280
|
const newLines = [...lines.slice(0, rangeStart), ...lines.slice(rangeEnd + 1)];
|
|
4508
|
-
const
|
|
4509
|
-
|
|
4510
|
-
|
|
5281
|
+
const newContentN = newLines.join("\n");
|
|
5282
|
+
const writtenContent = normalizeEol(content, newContentN);
|
|
5283
|
+
await writeFile7(filePath, writtenContent, "utf-8");
|
|
5284
|
+
const diff = computeFileDiff(content, writtenContent, filePath);
|
|
4511
5285
|
diff.existedBefore = true;
|
|
4512
5286
|
const deletedLines = rangeEnd - rangeStart + 1;
|
|
4513
5287
|
const summary = `\u{1F4DD} \u4FEE\u6539: ${basename5(filePath)} (\u5220 ${deletedLines} \u884C, +${diff.additions} -${diff.deletions})`;
|
|
@@ -4703,7 +5477,8 @@ var globTool = {
|
|
|
4703
5477
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
4704
5478
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
4705
5479
|
}
|
|
4706
|
-
const
|
|
5480
|
+
const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
|
|
5481
|
+
const searchDir = dir ? isAbsolute2(dir) ? dir : join7(ctx.cwd, dir) : ctx.cwd;
|
|
4707
5482
|
const regex = globToRegex(args.pattern);
|
|
4708
5483
|
try {
|
|
4709
5484
|
const dirStat = await stat2(searchDir);
|
|
@@ -4804,7 +5579,8 @@ var grepTool = {
|
|
|
4804
5579
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
4805
5580
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
4806
5581
|
}
|
|
4807
|
-
const
|
|
5582
|
+
const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
|
|
5583
|
+
const searchDir = dir ? isAbsolute3(dir) ? dir : join8(ctx.cwd, dir) : ctx.cwd;
|
|
4808
5584
|
const maxFiles = args.max_files ?? 200;
|
|
4809
5585
|
try {
|
|
4810
5586
|
const flags = args.case_sensitive ? "g" : "gi";
|
|
@@ -5104,7 +5880,7 @@ function getGradientColors(text, phase, stops) {
|
|
|
5104
5880
|
}
|
|
5105
5881
|
|
|
5106
5882
|
// src/ui/ChatSession.tsx
|
|
5107
|
-
import { Fragment as Fragment2, jsx as
|
|
5883
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5108
5884
|
var PHASE_CONFIG = {
|
|
5109
5885
|
thinking: { icon: "\u{1F9E0}", label: "\u6DF1\u5EA6\u601D\u8003\u4E2D", color: "#ff9800" },
|
|
5110
5886
|
generating: { icon: "\u2728", label: "\u751F\u6210\u4E2D", color: "#00ff41" },
|
|
@@ -5114,6 +5890,11 @@ var PHASE_CONFIG = {
|
|
|
5114
5890
|
function isFileMutatingTool(name) {
|
|
5115
5891
|
return name === "edit_file" || name === "write_file" || name === "multi_edit" || name === "delete_range";
|
|
5116
5892
|
}
|
|
5893
|
+
function filterTodoToolCalls(calls) {
|
|
5894
|
+
if (!calls) return void 0;
|
|
5895
|
+
const filtered = calls.filter((tc) => !tc.name.startsWith("todo_"));
|
|
5896
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
5897
|
+
}
|
|
5117
5898
|
var commandRegistry = /* @__PURE__ */ new Map();
|
|
5118
5899
|
function registerCommand(name, cmd) {
|
|
5119
5900
|
commandRegistry.set(name, cmd);
|
|
@@ -5135,15 +5916,45 @@ registerCommand("/help", {
|
|
|
5135
5916
|
}
|
|
5136
5917
|
});
|
|
5137
5918
|
registerCommand("/clear", { desc: "\u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", handler: () => ({ kind: "clear" }) });
|
|
5138
|
-
registerCommand("/version", {
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
registerCommand("/
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
registerCommand("/
|
|
5919
|
+
registerCommand("/version", {
|
|
5920
|
+
desc: "\u663E\u793A\u7248\u672C\u4FE1\u606F",
|
|
5921
|
+
handler: () => ({ kind: "text", content: "dskcode v0.1.10" })
|
|
5922
|
+
});
|
|
5923
|
+
registerCommand("/model", {
|
|
5924
|
+
desc: "\u5207\u6362\u6A21\u578B",
|
|
5925
|
+
handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /model \u8FDB\u5165\u9009\u62E9\u754C\u9762" })
|
|
5926
|
+
});
|
|
5927
|
+
registerCommand("/thinking", {
|
|
5928
|
+
desc: "\u5207\u6362\u6DF1\u5EA6\u601D\u8003\u6A21\u5F0F",
|
|
5929
|
+
handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /thinking \u5207\u6362" })
|
|
5930
|
+
});
|
|
5931
|
+
registerCommand("/effort", {
|
|
5932
|
+
desc: "\u5207\u6362\u63A8\u7406\u7B49\u7EA7 High/Max",
|
|
5933
|
+
handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /effort \u5207\u6362" })
|
|
5934
|
+
});
|
|
5935
|
+
registerCommand("/game", {
|
|
5936
|
+
desc: "\u542F\u52A8\u6E38\u620F",
|
|
5937
|
+
handler: () => ({ kind: "navigate", target: "game" })
|
|
5938
|
+
});
|
|
5939
|
+
registerCommand("/stock", {
|
|
5940
|
+
desc: "\u67E5\u770B\u80A1\u7968\u884C\u60C5",
|
|
5941
|
+
handler: () => ({ kind: "navigate", target: "stock" })
|
|
5942
|
+
});
|
|
5943
|
+
registerCommand("/plan", {
|
|
5944
|
+
desc: "\u5207\u6362\u4E3A\u8BA1\u5212\u6A21\u5F0F\uFF08Shift+Tab\uFF09",
|
|
5945
|
+
handler: () => ({ kind: "text", content: "\u8F93\u5165 /plan \u6216\u6309 Shift+Tab \u5207\u6362\u4E3A\u8BA1\u5212\u6A21\u5F0F" })
|
|
5946
|
+
});
|
|
5947
|
+
registerCommand("/code", {
|
|
5948
|
+
desc: "\u5207\u6362\u56DE\u4EE3\u7801\u6A21\u5F0F\uFF08Shift+Tab\uFF09",
|
|
5949
|
+
handler: () => ({ kind: "text", content: "\u8F93\u5165 /code \u6216\u6309 Shift+Tab \u5207\u6362\u56DE\u4EE3\u7801\u6A21\u5F0F" })
|
|
5950
|
+
});
|
|
5951
|
+
registerCommand("/rewind", {
|
|
5952
|
+
desc: "\u56DE\u9000\u5230\u5386\u53F2\u68C0\u67E5\u70B9\uFF081 = \u6700\u65B0\uFF09",
|
|
5953
|
+
handler: () => ({
|
|
5954
|
+
kind: "text",
|
|
5955
|
+
content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /rewind \u67E5\u770B\u53EF\u56DE\u9000\u7684\u68C0\u67E5\u70B9\u5217\u8868\uFF0C\u6216 /rewind <\u5E8F\u53F7> \u76F4\u63A5\u56DE\u9000\uFF081 = \u6700\u65B0\uFF0C2 = \u4E0A\u4E00\u6B21\uFF0C\u4F9D\u6B64\u7C7B\u63A8\uFF09"
|
|
5956
|
+
})
|
|
5957
|
+
});
|
|
5147
5958
|
var STREAMING_PLACEHOLDERS = [
|
|
5148
5959
|
"\u8BA9\u5B50\u5F39\u98DE\u4E00\u4F1A\u513F...",
|
|
5149
5960
|
"\u9A6C\u4E0A\u5C31\u597D...",
|
|
@@ -5188,12 +5999,15 @@ function ChatSession({
|
|
|
5188
5999
|
const [isStreaming, setIsStreaming] = useState4(false);
|
|
5189
6000
|
const [streamingPhase, setStreamingPhase] = useState4(null);
|
|
5190
6001
|
const [streamingPlaceholder, setStreamingPlaceholder] = useState4("");
|
|
5191
|
-
const [idlePlaceholder, setIdlePlaceholder] = useState4(
|
|
6002
|
+
const [idlePlaceholder, setIdlePlaceholder] = useState4(
|
|
6003
|
+
() => pickRandom(IDLE_PLACEHOLDERS)
|
|
6004
|
+
);
|
|
5192
6005
|
const [gradientColors, setGradientColors] = useState4([]);
|
|
5193
6006
|
const gradientPhaseRef = useRef3(0);
|
|
5194
6007
|
const [streamingGradientColors, setStreamingGradientColors] = useState4([]);
|
|
5195
6008
|
const streamingPhaseRef = useRef3(0);
|
|
5196
6009
|
const [currentContent, setCurrentContent] = useState4("");
|
|
6010
|
+
const [currentReasoning, setCurrentReasoning] = useState4([]);
|
|
5197
6011
|
const [currentToolCalls, setCurrentToolCalls] = useState4([]);
|
|
5198
6012
|
const [_currentUsage, setCurrentUsage] = useState4(void 0);
|
|
5199
6013
|
const [_currentElapsed, setCurrentElapsed] = useState4(void 0);
|
|
@@ -5201,11 +6015,16 @@ function ChatSession({
|
|
|
5201
6015
|
const [activeModel, setActiveModel] = useState4(model);
|
|
5202
6016
|
const [_streamingModel, setStreamingModel] = useState4(void 0);
|
|
5203
6017
|
const [streamError, setStreamError] = useState4(void 0);
|
|
6018
|
+
const [todoSnapshot, setTodoSnapshot] = useState4([]);
|
|
6019
|
+
const [todoPanelVisible, setTodoPanelVisible] = useState4(true);
|
|
6020
|
+
const todoHideTimerRef = useRef3(null);
|
|
5204
6021
|
const [sessionMode, setSessionMode] = useState4("code");
|
|
5205
6022
|
const [thinkingEnabled, setThinkingEnabled] = useState4(true);
|
|
5206
6023
|
const [thinkingEffort, setThinkingEffort] = useState4("high");
|
|
5207
6024
|
const [responseFormat] = useState4("text");
|
|
5208
|
-
const [toolChoice, setToolChoice] = useState4(
|
|
6025
|
+
const [toolChoice, setToolChoice] = useState4(
|
|
6026
|
+
void 0
|
|
6027
|
+
);
|
|
5209
6028
|
const sessionCost = useMemo(() => {
|
|
5210
6029
|
return displayMessages.reduce((sum, msg) => {
|
|
5211
6030
|
if (msg.assistantDetail?.cost) {
|
|
@@ -5226,7 +6045,9 @@ function ChatSession({
|
|
|
5226
6045
|
const [rewindSelectIndex, setRewindSelectIndex] = useState4(0);
|
|
5227
6046
|
const [rewindList, setRewindList] = useState4([]);
|
|
5228
6047
|
const [rewinding, setRewinding] = useState4(false);
|
|
5229
|
-
const [rewindHintPhase, setRewindHintPhase] = useState4(
|
|
6048
|
+
const [rewindHintPhase, setRewindHintPhase] = useState4(
|
|
6049
|
+
"idle"
|
|
6050
|
+
);
|
|
5230
6051
|
const currentRoundModifiedRef = useRef3(false);
|
|
5231
6052
|
const rewindHintTimerRef = useRef3(null);
|
|
5232
6053
|
const [selectingModel, setSelectingModel] = useState4(false);
|
|
@@ -5235,6 +6056,7 @@ function ChatSession({
|
|
|
5235
6056
|
const sessionRef = useRef3(null);
|
|
5236
6057
|
const abortRef = useRef3(null);
|
|
5237
6058
|
const currentContentRef = useRef3("");
|
|
6059
|
+
const currentReasoningRef = useRef3([]);
|
|
5238
6060
|
const currentToolCallsRef = useRef3([]);
|
|
5239
6061
|
const currentUsageRef = useRef3(void 0);
|
|
5240
6062
|
const currentElapsedRef = useRef3(void 0);
|
|
@@ -5253,6 +6075,20 @@ function ChatSession({
|
|
|
5253
6075
|
}
|
|
5254
6076
|
};
|
|
5255
6077
|
}, []);
|
|
6078
|
+
useEffect4(() => {
|
|
6079
|
+
if (todoHideTimerRef.current) {
|
|
6080
|
+
clearTimeout(todoHideTimerRef.current);
|
|
6081
|
+
todoHideTimerRef.current = null;
|
|
6082
|
+
}
|
|
6083
|
+
if (todoSnapshot.length === 0) {
|
|
6084
|
+
setTodoPanelVisible(false);
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
const hasUnfinished = todoSnapshot.some(
|
|
6088
|
+
(it) => it.status === "pending" || it.status === "running" || it.status === "failed"
|
|
6089
|
+
);
|
|
6090
|
+
setTodoPanelVisible(hasUnfinished);
|
|
6091
|
+
}, [todoSnapshot]);
|
|
5256
6092
|
const getFilteredSkills = useCallback2(
|
|
5257
6093
|
(value) => {
|
|
5258
6094
|
const match = value.match(/(?:^|\s)\/([^/]*)$/);
|
|
@@ -5294,7 +6130,7 @@ function ChatSession({
|
|
|
5294
6130
|
content: m.content,
|
|
5295
6131
|
assistantDetail: {
|
|
5296
6132
|
content: m.content,
|
|
5297
|
-
toolCalls: m.toolCalls
|
|
6133
|
+
toolCalls: filterTodoToolCalls(m.toolCalls)
|
|
5298
6134
|
}
|
|
5299
6135
|
});
|
|
5300
6136
|
} else if (m.role === "tool") {
|
|
@@ -5304,42 +6140,48 @@ function ChatSession({
|
|
|
5304
6140
|
setDisplayMessages(next);
|
|
5305
6141
|
setStaticKey((prev) => prev + 1);
|
|
5306
6142
|
}
|
|
5307
|
-
const doRewind = useCallback2(
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
6143
|
+
const doRewind = useCallback2(
|
|
6144
|
+
async (target, displayNumber) => {
|
|
6145
|
+
const session = sessionRef.current;
|
|
6146
|
+
if (!session) return;
|
|
6147
|
+
setRewinding(true);
|
|
6148
|
+
setIsStreaming(true);
|
|
6149
|
+
setStreamingPhase("thinking");
|
|
6150
|
+
setStreamingPlaceholder("\u23EA \u6B63\u5728\u56DE\u9000\u5230\u68C0\u67E5\u70B9\u2026");
|
|
6151
|
+
setInput("");
|
|
6152
|
+
try {
|
|
6153
|
+
const r = await session.rewind(target.index);
|
|
6154
|
+
if (r.ok) {
|
|
6155
|
+
rebuildDisplayFromSession(session);
|
|
6156
|
+
const tail = r.fileRestored ? "\uFF0C\u5DE5\u4F5C\u533A\u6587\u4EF6\u5DF2\u6062\u590D" : "\uFF08\u4EC5\u5BF9\u8BDD\u56DE\u9000\uFF0C\u672A\u6062\u590D\u6587\u4EF6\uFF09";
|
|
6157
|
+
setDisplayMessages((prev) => [
|
|
6158
|
+
...prev,
|
|
6159
|
+
{
|
|
6160
|
+
role: "assistant",
|
|
6161
|
+
content: `\u23EA \u5DF2\u56DE\u9000\u5230\u68C0\u67E5\u70B9 #${displayNumber}${tail}\u3002`
|
|
6162
|
+
}
|
|
6163
|
+
]);
|
|
6164
|
+
} else {
|
|
6165
|
+
setDisplayMessages((prev) => [
|
|
6166
|
+
...prev,
|
|
6167
|
+
{ role: "assistant", content: `\u26A0 \u56DE\u9000\u5931\u8D25\uFF1A${r.error}` }
|
|
6168
|
+
]);
|
|
6169
|
+
}
|
|
6170
|
+
} catch (err) {
|
|
6171
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5325
6172
|
setDisplayMessages((prev) => [
|
|
5326
6173
|
...prev,
|
|
5327
|
-
{ role: "assistant", content: `\u26A0 \u56DE\u9000\
|
|
6174
|
+
{ role: "assistant", content: `\u26A0 \u56DE\u9000\u5F02\u5E38\uFF1A${msg}` }
|
|
5328
6175
|
]);
|
|
6176
|
+
} finally {
|
|
6177
|
+
setRewinding(false);
|
|
6178
|
+
setIsStreaming(false);
|
|
6179
|
+
setStreamingPhase(null);
|
|
6180
|
+
setStreamingPlaceholder("");
|
|
5329
6181
|
}
|
|
5330
|
-
}
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
...prev,
|
|
5334
|
-
{ role: "assistant", content: `\u26A0 \u56DE\u9000\u5F02\u5E38\uFF1A${msg}` }
|
|
5335
|
-
]);
|
|
5336
|
-
} finally {
|
|
5337
|
-
setRewinding(false);
|
|
5338
|
-
setIsStreaming(false);
|
|
5339
|
-
setStreamingPhase(null);
|
|
5340
|
-
setStreamingPlaceholder("");
|
|
5341
|
-
}
|
|
5342
|
-
}, []);
|
|
6182
|
+
},
|
|
6183
|
+
[]
|
|
6184
|
+
);
|
|
5343
6185
|
const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(() => {
|
|
5344
6186
|
const s = sessionRef.current;
|
|
5345
6187
|
if (s) {
|
|
@@ -5353,7 +6195,9 @@ function ChatSession({
|
|
|
5353
6195
|
(_input, key) => {
|
|
5354
6196
|
if (rewindSelecting) {
|
|
5355
6197
|
if (key.upArrow) {
|
|
5356
|
-
setRewindSelectIndex(
|
|
6198
|
+
setRewindSelectIndex(
|
|
6199
|
+
(prev) => (prev - 1 + rewindList.length) % rewindList.length
|
|
6200
|
+
);
|
|
5357
6201
|
} else if (key.downArrow) {
|
|
5358
6202
|
setRewindSelectIndex((prev) => (prev + 1) % rewindList.length);
|
|
5359
6203
|
} else if (key.return) {
|
|
@@ -5373,7 +6217,9 @@ function ChatSession({
|
|
|
5373
6217
|
}
|
|
5374
6218
|
if (selectingModel) {
|
|
5375
6219
|
if (key.upArrow) {
|
|
5376
|
-
setModelSelectIndex(
|
|
6220
|
+
setModelSelectIndex(
|
|
6221
|
+
(prev) => (prev - 1 + modelOptions.length) % modelOptions.length
|
|
6222
|
+
);
|
|
5377
6223
|
} else if (key.downArrow) {
|
|
5378
6224
|
setModelSelectIndex((prev) => (prev + 1) % modelOptions.length);
|
|
5379
6225
|
} else if (key.return) {
|
|
@@ -5381,7 +6227,10 @@ function ChatSession({
|
|
|
5381
6227
|
if (selected === activeModel) {
|
|
5382
6228
|
setDisplayMessages((prev) => [
|
|
5383
6229
|
...prev,
|
|
5384
|
-
{
|
|
6230
|
+
{
|
|
6231
|
+
role: "assistant",
|
|
6232
|
+
content: `\u5DF2\u7ECF\u5728\u4F7F\u7528 ${SUPPORTED_MODELS[selected].displayName}`
|
|
6233
|
+
}
|
|
5385
6234
|
]);
|
|
5386
6235
|
} else {
|
|
5387
6236
|
setActiveModel(selected);
|
|
@@ -5390,7 +6239,10 @@ function ChatSession({
|
|
|
5390
6239
|
});
|
|
5391
6240
|
setDisplayMessages((prev) => [
|
|
5392
6241
|
...prev,
|
|
5393
|
-
{
|
|
6242
|
+
{
|
|
6243
|
+
role: "assistant",
|
|
6244
|
+
content: `\u6A21\u578B\u5DF2\u5207\u6362\u4E3A ${SUPPORTED_MODELS[selected].displayName}\uFF08${selected}\uFF09`
|
|
6245
|
+
}
|
|
5394
6246
|
]);
|
|
5395
6247
|
}
|
|
5396
6248
|
setSelectingModel(false);
|
|
@@ -5424,7 +6276,9 @@ function ChatSession({
|
|
|
5424
6276
|
}
|
|
5425
6277
|
if (skillList.length > 0) {
|
|
5426
6278
|
if (key.upArrow) {
|
|
5427
|
-
setSkillSelectIndex(
|
|
6279
|
+
setSkillSelectIndex(
|
|
6280
|
+
(prev) => (prev - 1 + skillList.length) % skillList.length
|
|
6281
|
+
);
|
|
5428
6282
|
return;
|
|
5429
6283
|
}
|
|
5430
6284
|
if (key.downArrow) {
|
|
@@ -5477,7 +6331,26 @@ function ChatSession({
|
|
|
5477
6331
|
setInput(_input);
|
|
5478
6332
|
}
|
|
5479
6333
|
},
|
|
5480
|
-
[
|
|
6334
|
+
[
|
|
6335
|
+
selectingModel,
|
|
6336
|
+
modelSelectIndex,
|
|
6337
|
+
modelOptions,
|
|
6338
|
+
activeModel,
|
|
6339
|
+
isStreaming,
|
|
6340
|
+
handleCtrlC,
|
|
6341
|
+
input,
|
|
6342
|
+
skills,
|
|
6343
|
+
skillSelectIndex,
|
|
6344
|
+
fileSelectIndex,
|
|
6345
|
+
getFilteredSkills,
|
|
6346
|
+
getFilteredFiles,
|
|
6347
|
+
sessionMode,
|
|
6348
|
+
setSessionMode,
|
|
6349
|
+
rewindSelecting,
|
|
6350
|
+
rewindSelectIndex,
|
|
6351
|
+
rewindList,
|
|
6352
|
+
doRewind
|
|
6353
|
+
]
|
|
5481
6354
|
)
|
|
5482
6355
|
);
|
|
5483
6356
|
useEffect4(() => {
|
|
@@ -5498,7 +6371,9 @@ function ChatSession({
|
|
|
5498
6371
|
setCmdTipGradientColors(getGradientColors(text, 1, CMD_TIP_GRADIENT_STOPS));
|
|
5499
6372
|
const interval = setInterval(() => {
|
|
5500
6373
|
cmdTipPhaseRef.current = (cmdTipPhaseRef.current + GRADIENT_ANIMATION.cmdTipPhaseStep) % 1;
|
|
5501
|
-
setCmdTipGradientColors(
|
|
6374
|
+
setCmdTipGradientColors(
|
|
6375
|
+
getGradientColors(text, 1 - cmdTipPhaseRef.current, CMD_TIP_GRADIENT_STOPS)
|
|
6376
|
+
);
|
|
5502
6377
|
}, GRADIENT_ANIMATION.cmdTipInterval);
|
|
5503
6378
|
return () => clearInterval(interval);
|
|
5504
6379
|
}, [cmdTipIndex, cmdTips.length]);
|
|
@@ -5531,7 +6406,7 @@ function ChatSession({
|
|
|
5531
6406
|
if (!apiKey || !baseUrl) return;
|
|
5532
6407
|
let cancelled = false;
|
|
5533
6408
|
setBalanceLoading(true);
|
|
5534
|
-
import("./deepseek-
|
|
6409
|
+
import("./deepseek-WFSVA5UQ.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
|
|
5535
6410
|
const provider = new DeepSeekProvider2({
|
|
5536
6411
|
apiKey,
|
|
5537
6412
|
baseUrl,
|
|
@@ -5579,7 +6454,13 @@ function ChatSession({
|
|
|
5579
6454
|
setGradientColors(getGradientColors(idlePlaceholder, 1, IDLE_GRADIENT_STOPS));
|
|
5580
6455
|
const interval = setInterval(() => {
|
|
5581
6456
|
gradientPhaseRef.current = (gradientPhaseRef.current + GRADIENT_ANIMATION.idlePhaseStep) % 1;
|
|
5582
|
-
setGradientColors(
|
|
6457
|
+
setGradientColors(
|
|
6458
|
+
getGradientColors(
|
|
6459
|
+
idlePlaceholder,
|
|
6460
|
+
1 - gradientPhaseRef.current,
|
|
6461
|
+
IDLE_GRADIENT_STOPS
|
|
6462
|
+
)
|
|
6463
|
+
);
|
|
5583
6464
|
}, GRADIENT_ANIMATION.idleInterval);
|
|
5584
6465
|
return () => clearInterval(interval);
|
|
5585
6466
|
}, [isStreaming, idlePlaceholder]);
|
|
@@ -5589,385 +6470,472 @@ function ChatSession({
|
|
|
5589
6470
|
return;
|
|
5590
6471
|
}
|
|
5591
6472
|
streamingPhaseRef.current = 0;
|
|
5592
|
-
setStreamingGradientColors(
|
|
6473
|
+
setStreamingGradientColors(
|
|
6474
|
+
getGradientColors(streamingPlaceholder, 1, STREAMING_GRADIENT_STOPS)
|
|
6475
|
+
);
|
|
5593
6476
|
const interval = setInterval(() => {
|
|
5594
6477
|
streamingPhaseRef.current = (streamingPhaseRef.current + GRADIENT_ANIMATION.streamingPhaseStep) % 1;
|
|
5595
|
-
setStreamingGradientColors(
|
|
6478
|
+
setStreamingGradientColors(
|
|
6479
|
+
getGradientColors(
|
|
6480
|
+
streamingPlaceholder,
|
|
6481
|
+
1 - streamingPhaseRef.current,
|
|
6482
|
+
STREAMING_GRADIENT_STOPS
|
|
6483
|
+
)
|
|
6484
|
+
);
|
|
5596
6485
|
}, GRADIENT_ANIMATION.streamingInterval);
|
|
5597
6486
|
return () => clearInterval(interval);
|
|
5598
6487
|
}, [isStreaming, streamingPlaceholder]);
|
|
5599
|
-
const handleSubmit = useCallback2(
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
if (
|
|
5606
|
-
|
|
6488
|
+
const handleSubmit = useCallback2(
|
|
6489
|
+
async (value) => {
|
|
6490
|
+
const trimmed = value.trim();
|
|
6491
|
+
if (!trimmed) return;
|
|
6492
|
+
if (trimmed.startsWith("/") && trimmed.length > 1) {
|
|
6493
|
+
const cmdLower = trimmed.toLowerCase();
|
|
6494
|
+
if (cmdLower === "/rewind" || cmdLower.startsWith("/rewind ")) {
|
|
6495
|
+
if (isStreaming || rewinding) {
|
|
6496
|
+
const reason = rewinding ? "\u56DE\u9000\u4E2D" : "\u751F\u6210\u4E2D";
|
|
6497
|
+
setDisplayMessages((prev) => [
|
|
6498
|
+
...prev,
|
|
6499
|
+
{ role: "user", content: trimmed },
|
|
6500
|
+
{ role: "assistant", content: `\u26A0 \u6B63\u5728${reason}\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 /rewind\u3002` }
|
|
6501
|
+
]);
|
|
6502
|
+
setInput("");
|
|
6503
|
+
return;
|
|
6504
|
+
}
|
|
6505
|
+
if (!sessionRef.current) {
|
|
6506
|
+
setDisplayMessages((prev) => [
|
|
6507
|
+
...prev,
|
|
6508
|
+
{ role: "user", content: trimmed },
|
|
6509
|
+
{ role: "assistant", content: "\u26A0 Session \u672A\u5C31\u7EEA\uFF0C\u65E0\u6CD5\u56DE\u9000\u3002" }
|
|
6510
|
+
]);
|
|
6511
|
+
setInput("");
|
|
6512
|
+
return;
|
|
6513
|
+
}
|
|
6514
|
+
const cps = sessionRef.current.listCheckpoints();
|
|
6515
|
+
if (cps.length === 0) {
|
|
6516
|
+
setDisplayMessages((prev) => [
|
|
6517
|
+
...prev,
|
|
6518
|
+
{ role: "user", content: trimmed },
|
|
6519
|
+
{
|
|
6520
|
+
role: "assistant",
|
|
6521
|
+
content: "\u26A0 \u6CA1\u6709\u53EF\u56DE\u9000\u7684\u68C0\u67E5\u70B9\u3002\n\u53EA\u6709\u5728 git \u4ED3\u5E93\u5185\u4E14\u53D1\u751F\u8FC7\u5BF9\u8BDD\u540E\u624D\u4F1A\u751F\u6210\u68C0\u67E5\u70B9\u3002"
|
|
6522
|
+
}
|
|
6523
|
+
]);
|
|
6524
|
+
setInput("");
|
|
6525
|
+
return;
|
|
6526
|
+
}
|
|
6527
|
+
const parts = trimmed.split(/\s+/);
|
|
6528
|
+
if (parts.length >= 2) {
|
|
6529
|
+
const n = Number(parts[1]);
|
|
6530
|
+
if (!Number.isInteger(n) || n < 1 || n > cps.length) {
|
|
6531
|
+
setDisplayMessages((prev) => [
|
|
6532
|
+
...prev,
|
|
6533
|
+
{ role: "user", content: trimmed },
|
|
6534
|
+
{
|
|
6535
|
+
role: "assistant",
|
|
6536
|
+
content: `\u26A0 \u65E0\u6548\u7684\u5E8F\u53F7\u300C${parts[1]}\u300D\u3002\u53EF\u7528\u8303\u56F4 1~${cps.length}\uFF081 \u8868\u793A\u6700\u65B0\uFF09\u3002`
|
|
6537
|
+
}
|
|
6538
|
+
]);
|
|
6539
|
+
setInput("");
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
const target = cps[cps.length - n];
|
|
6543
|
+
setInput("");
|
|
6544
|
+
await doRewind(target, n);
|
|
6545
|
+
return;
|
|
6546
|
+
}
|
|
6547
|
+
setRewindList([...cps].reverse());
|
|
6548
|
+
setRewindSelectIndex(0);
|
|
6549
|
+
setRewindSelecting(true);
|
|
5607
6550
|
setDisplayMessages((prev) => [
|
|
5608
6551
|
...prev,
|
|
5609
6552
|
{ role: "user", content: trimmed },
|
|
5610
|
-
{
|
|
6553
|
+
{
|
|
6554
|
+
role: "assistant",
|
|
6555
|
+
content: `\u23F7\u2191\u2193 \u9009\u62E9\u68C0\u67E5\u70B9\uFF0CEnter \u786E\u8BA4\uFF0CEsc \u53D6\u6D88\uFF08\u5171 ${cps.length} \u4E2A\u53EF\u56DE\u9000\u4F4D\u7F6E\uFF09`
|
|
6556
|
+
}
|
|
5611
6557
|
]);
|
|
5612
6558
|
setInput("");
|
|
5613
6559
|
return;
|
|
5614
6560
|
}
|
|
5615
|
-
if (
|
|
6561
|
+
if (cmdLower === "/model") {
|
|
6562
|
+
const curIdx = modelOptions.indexOf(activeModel);
|
|
6563
|
+
setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
|
|
6564
|
+
setSelectingModel(true);
|
|
6565
|
+
setInput("");
|
|
6566
|
+
return;
|
|
6567
|
+
}
|
|
6568
|
+
if (cmdLower === "/thinking") {
|
|
6569
|
+
setThinkingEnabled((prev) => !prev);
|
|
5616
6570
|
setDisplayMessages((prev) => [
|
|
5617
6571
|
...prev,
|
|
5618
6572
|
{ role: "user", content: trimmed },
|
|
5619
|
-
{
|
|
6573
|
+
{
|
|
6574
|
+
role: "assistant",
|
|
6575
|
+
content: `\u6DF1\u5EA6\u601D\u8003\u5DF2${thinkingEnabled ? "\u5173\u95ED" : "\u5F00\u542F"}`
|
|
6576
|
+
}
|
|
5620
6577
|
]);
|
|
5621
6578
|
setInput("");
|
|
5622
6579
|
return;
|
|
5623
6580
|
}
|
|
5624
|
-
|
|
5625
|
-
|
|
6581
|
+
if (cmdLower === "/effort") {
|
|
6582
|
+
const next = thinkingEffort === "high" ? "max" : "high";
|
|
6583
|
+
setThinkingEffort(next);
|
|
5626
6584
|
setDisplayMessages((prev) => [
|
|
5627
6585
|
...prev,
|
|
5628
6586
|
{ role: "user", content: trimmed },
|
|
5629
|
-
{
|
|
6587
|
+
{
|
|
6588
|
+
role: "assistant",
|
|
6589
|
+
content: `\u63A8\u7406\u7B49\u7EA7\u5DF2\u5207\u6362\u4E3A ${next === "high" ? "High" : "Max"}`
|
|
6590
|
+
}
|
|
5630
6591
|
]);
|
|
5631
6592
|
setInput("");
|
|
5632
6593
|
return;
|
|
5633
6594
|
}
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
const n = Number(parts[1]);
|
|
5637
|
-
if (!Number.isInteger(n) || n < 1 || n > cps.length) {
|
|
6595
|
+
if (cmdLower === "/plan") {
|
|
6596
|
+
if (sessionMode === "plan") {
|
|
5638
6597
|
setDisplayMessages((prev) => [
|
|
5639
6598
|
...prev,
|
|
5640
6599
|
{ role: "user", content: trimmed },
|
|
5641
|
-
{
|
|
6600
|
+
{
|
|
6601
|
+
role: "assistant",
|
|
6602
|
+
content: "\u5DF2\u7ECF\u5728\u8BA1\u5212\u6A21\u5F0F\u4E2D\u3002\u8F93\u5165 /code \u5207\u56DE\u4EE3\u7801\u6A21\u5F0F\u3002"
|
|
6603
|
+
}
|
|
5642
6604
|
]);
|
|
5643
|
-
|
|
5644
|
-
|
|
6605
|
+
} else {
|
|
6606
|
+
setSessionMode("plan");
|
|
6607
|
+
sessionRef.current?.setMode("plan");
|
|
6608
|
+
setToolChoice(void 0);
|
|
6609
|
+
setDisplayMessages((prev) => [
|
|
6610
|
+
...prev,
|
|
6611
|
+
{ role: "user", content: trimmed },
|
|
6612
|
+
{
|
|
6613
|
+
role: "assistant",
|
|
6614
|
+
content: "\u{1F4CB} \u5DF2\u5207\u6362\u4E3A **\u8BA1\u5212\u6A21\u5F0F**\n\n\u5728\u6B64\u6A21\u5F0F\u4E0B\uFF0C\u6211\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\u4EE3\u7801\uFF0C\u4E0D\u4F1A\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\u3002\n\u8F93\u5165 /code \u5207\u56DE\u4EE3\u7801\u6A21\u5F0F\u3002"
|
|
6615
|
+
}
|
|
6616
|
+
]);
|
|
6617
|
+
sessionRef.current?.reset();
|
|
5645
6618
|
}
|
|
5646
|
-
const target = cps[cps.length - n];
|
|
5647
6619
|
setInput("");
|
|
5648
|
-
await doRewind(target, n);
|
|
5649
6620
|
return;
|
|
5650
6621
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
return;
|
|
5678
|
-
}
|
|
5679
|
-
if (cmdLower === "/effort") {
|
|
5680
|
-
const next = thinkingEffort === "high" ? "max" : "high";
|
|
5681
|
-
setThinkingEffort(next);
|
|
5682
|
-
setDisplayMessages((prev) => [
|
|
5683
|
-
...prev,
|
|
5684
|
-
{ role: "user", content: trimmed },
|
|
5685
|
-
{ role: "assistant", content: `\u63A8\u7406\u7B49\u7EA7\u5DF2\u5207\u6362\u4E3A ${next === "high" ? "High" : "Max"}` }
|
|
5686
|
-
]);
|
|
5687
|
-
setInput("");
|
|
5688
|
-
return;
|
|
5689
|
-
}
|
|
5690
|
-
if (cmdLower === "/plan") {
|
|
5691
|
-
if (sessionMode === "plan") {
|
|
5692
|
-
setDisplayMessages((prev) => [
|
|
5693
|
-
...prev,
|
|
5694
|
-
{ role: "user", content: trimmed },
|
|
5695
|
-
{ role: "assistant", content: "\u5DF2\u7ECF\u5728\u8BA1\u5212\u6A21\u5F0F\u4E2D\u3002\u8F93\u5165 /code \u5207\u56DE\u4EE3\u7801\u6A21\u5F0F\u3002" }
|
|
5696
|
-
]);
|
|
5697
|
-
} else {
|
|
5698
|
-
setSessionMode("plan");
|
|
5699
|
-
sessionRef.current?.setMode("plan");
|
|
5700
|
-
setToolChoice(void 0);
|
|
5701
|
-
setDisplayMessages((prev) => [
|
|
5702
|
-
...prev,
|
|
5703
|
-
{ role: "user", content: trimmed },
|
|
5704
|
-
{ role: "assistant", content: "\u{1F4CB} \u5DF2\u5207\u6362\u4E3A **\u8BA1\u5212\u6A21\u5F0F**\n\n\u5728\u6B64\u6A21\u5F0F\u4E0B\uFF0C\u6211\u53EA\u80FD\u8BFB\u53D6\u548C\u5206\u6790\u4EE3\u7801\uFF0C\u4E0D\u4F1A\u6267\u884C\u4EFB\u4F55\u4FEE\u6539\u3002\n\u8F93\u5165 /code \u5207\u56DE\u4EE3\u7801\u6A21\u5F0F\u3002" }
|
|
5705
|
-
]);
|
|
5706
|
-
sessionRef.current?.reset();
|
|
6622
|
+
if (cmdLower === "/code") {
|
|
6623
|
+
if (sessionMode === "code") {
|
|
6624
|
+
setDisplayMessages((prev) => [
|
|
6625
|
+
...prev,
|
|
6626
|
+
{ role: "user", content: trimmed },
|
|
6627
|
+
{
|
|
6628
|
+
role: "assistant",
|
|
6629
|
+
content: "\u5DF2\u7ECF\u5728\u4EE3\u7801\u6A21\u5F0F\u4E2D\u3002\u8F93\u5165 /plan \u5207\u56DE\u8BA1\u5212\u6A21\u5F0F\u3002"
|
|
6630
|
+
}
|
|
6631
|
+
]);
|
|
6632
|
+
} else {
|
|
6633
|
+
setSessionMode("code");
|
|
6634
|
+
sessionRef.current?.setMode("code");
|
|
6635
|
+
setToolChoice(void 0);
|
|
6636
|
+
setDisplayMessages((prev) => [
|
|
6637
|
+
...prev,
|
|
6638
|
+
{ role: "user", content: trimmed },
|
|
6639
|
+
{
|
|
6640
|
+
role: "assistant",
|
|
6641
|
+
content: "\u{1F6E0} \u5DF2\u5207\u6362\u4E3A **\u4EE3\u7801\u6A21\u5F0F**\n\n\u73B0\u5728\u53EF\u4EE5\u6B63\u5E38\u8BFB\u53D6\u548C\u4FEE\u6539\u4EE3\u7801\u4E86\u3002\n\u8F93\u5165 /plan \u5207\u6362\u4E3A\u8BA1\u5212\u6A21\u5F0F\uFF08\u53EA\u8BFB\u5206\u6790\uFF09\u3002"
|
|
6642
|
+
}
|
|
6643
|
+
]);
|
|
6644
|
+
sessionRef.current?.reset();
|
|
6645
|
+
}
|
|
6646
|
+
setInput("");
|
|
6647
|
+
return;
|
|
5707
6648
|
}
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
if (sessionMode === "code") {
|
|
5713
|
-
setDisplayMessages((prev) => [
|
|
5714
|
-
...prev,
|
|
5715
|
-
{ role: "user", content: trimmed },
|
|
5716
|
-
{ role: "assistant", content: "\u5DF2\u7ECF\u5728\u4EE3\u7801\u6A21\u5F0F\u4E2D\u3002\u8F93\u5165 /plan \u5207\u56DE\u8BA1\u5212\u6A21\u5F0F\u3002" }
|
|
5717
|
-
]);
|
|
5718
|
-
} else {
|
|
5719
|
-
setSessionMode("code");
|
|
5720
|
-
sessionRef.current?.setMode("code");
|
|
5721
|
-
setToolChoice(void 0);
|
|
6649
|
+
if (cmdLower === "/tools") {
|
|
6650
|
+
const next = toolChoice === void 0 ? "none" : toolChoice === "none" ? "required" : toolChoice === "required" ? "auto" : void 0;
|
|
6651
|
+
setToolChoice(next);
|
|
6652
|
+
const label = next === void 0 ? "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09" : next === "none" ? "\u7981\u6B62\u8C03\u7528" : next === "required" ? "\u5F3A\u5236\u8C03\u7528" : "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09";
|
|
5722
6653
|
setDisplayMessages((prev) => [
|
|
5723
6654
|
...prev,
|
|
5724
6655
|
{ role: "user", content: trimmed },
|
|
5725
|
-
{ role: "assistant", content:
|
|
6656
|
+
{ role: "assistant", content: `\u5DE5\u5177\u8C03\u7528\u7B56\u7565\u5DF2\u5207\u6362\u4E3A ${label}` }
|
|
5726
6657
|
]);
|
|
5727
|
-
|
|
6658
|
+
setInput("");
|
|
6659
|
+
return;
|
|
6660
|
+
}
|
|
6661
|
+
const cmd = commandRegistry.get(cmdLower);
|
|
6662
|
+
if (cmd) {
|
|
6663
|
+
const result = cmd.handler();
|
|
6664
|
+
switch (result.kind) {
|
|
6665
|
+
case "exit":
|
|
6666
|
+
await sessionRef.current?.flushLog();
|
|
6667
|
+
process.exit(0);
|
|
6668
|
+
return;
|
|
6669
|
+
case "clear":
|
|
6670
|
+
setDisplayMessages([]);
|
|
6671
|
+
setStaticKey((prev) => prev + 1);
|
|
6672
|
+
setInput("");
|
|
6673
|
+
setStreamError(void 0);
|
|
6674
|
+
process.stdout.write("\x1B[2J\x1B[H\x1B[3J");
|
|
6675
|
+
sessionRef.current?.reset();
|
|
6676
|
+
return;
|
|
6677
|
+
case "navigate":
|
|
6678
|
+
setInput("");
|
|
6679
|
+
if (result.target === "game") {
|
|
6680
|
+
onLaunchGame?.();
|
|
6681
|
+
} else if (result.target === "stock") {
|
|
6682
|
+
onLaunchStock?.();
|
|
6683
|
+
}
|
|
6684
|
+
return;
|
|
6685
|
+
case "text":
|
|
6686
|
+
setDisplayMessages((prev) => [
|
|
6687
|
+
...prev,
|
|
6688
|
+
{ role: "user", content: trimmed },
|
|
6689
|
+
{ role: "assistant", content: result.content }
|
|
6690
|
+
]);
|
|
6691
|
+
setInput("");
|
|
6692
|
+
return;
|
|
6693
|
+
}
|
|
5728
6694
|
}
|
|
6695
|
+
setDisplayMessages((prev) => [
|
|
6696
|
+
...prev,
|
|
6697
|
+
{ role: "user", content: trimmed },
|
|
6698
|
+
{ role: "assistant", content: `\u672A\u77E5\u547D\u4EE4\uFF1A${trimmed}\u3002\u8F93\u5165 /help \u67E5\u770B\u3002` }
|
|
6699
|
+
]);
|
|
5729
6700
|
setInput("");
|
|
5730
6701
|
return;
|
|
5731
6702
|
}
|
|
5732
|
-
if (
|
|
5733
|
-
const next = toolChoice === void 0 ? "none" : toolChoice === "none" ? "required" : toolChoice === "required" ? "auto" : void 0;
|
|
5734
|
-
setToolChoice(next);
|
|
5735
|
-
const label = next === void 0 ? "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09" : next === "none" ? "\u7981\u6B62\u8C03\u7528" : next === "required" ? "\u5F3A\u5236\u8C03\u7528" : "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09";
|
|
6703
|
+
if (!sessionRef.current) {
|
|
5736
6704
|
setDisplayMessages((prev) => [
|
|
5737
6705
|
...prev,
|
|
5738
6706
|
{ role: "user", content: trimmed },
|
|
5739
|
-
{
|
|
6707
|
+
{
|
|
6708
|
+
role: "assistant",
|
|
6709
|
+
content: "\u26A0 \u65E0\u6CD5\u8FDE\u63A5\u5230 Provider\u3002\u8BF7\u68C0\u67E5 API Key \u548C\u7F51\u7EDC\u914D\u7F6E\u3002"
|
|
6710
|
+
}
|
|
5740
6711
|
]);
|
|
5741
6712
|
setInput("");
|
|
5742
6713
|
return;
|
|
5743
6714
|
}
|
|
5744
|
-
|
|
5745
|
-
if (cmd) {
|
|
5746
|
-
const result = cmd.handler();
|
|
5747
|
-
switch (result.kind) {
|
|
5748
|
-
case "exit":
|
|
5749
|
-
await sessionRef.current?.flushLog();
|
|
5750
|
-
process.exit(0);
|
|
5751
|
-
return;
|
|
5752
|
-
case "clear":
|
|
5753
|
-
setDisplayMessages([]);
|
|
5754
|
-
setStaticKey((prev) => prev + 1);
|
|
5755
|
-
setInput("");
|
|
5756
|
-
setStreamError(void 0);
|
|
5757
|
-
process.stdout.write("\x1B[2J\x1B[H\x1B[3J");
|
|
5758
|
-
sessionRef.current?.reset();
|
|
5759
|
-
return;
|
|
5760
|
-
case "navigate":
|
|
5761
|
-
setInput("");
|
|
5762
|
-
if (result.target === "game") {
|
|
5763
|
-
onLaunchGame?.();
|
|
5764
|
-
} else if (result.target === "stock") {
|
|
5765
|
-
onLaunchStock?.();
|
|
5766
|
-
}
|
|
5767
|
-
return;
|
|
5768
|
-
case "text":
|
|
5769
|
-
setDisplayMessages((prev) => [
|
|
5770
|
-
...prev,
|
|
5771
|
-
{ role: "user", content: trimmed },
|
|
5772
|
-
{ role: "assistant", content: result.content }
|
|
5773
|
-
]);
|
|
5774
|
-
setInput("");
|
|
5775
|
-
return;
|
|
5776
|
-
}
|
|
5777
|
-
}
|
|
5778
|
-
setDisplayMessages((prev) => [
|
|
5779
|
-
...prev,
|
|
5780
|
-
{ role: "user", content: trimmed },
|
|
5781
|
-
{ role: "assistant", content: `\u672A\u77E5\u547D\u4EE4\uFF1A${trimmed}\u3002\u8F93\u5165 /help \u67E5\u770B\u3002` }
|
|
5782
|
-
]);
|
|
6715
|
+
setDisplayMessages((prev) => [...prev, { role: "user", content: trimmed }]);
|
|
5783
6716
|
setInput("");
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
for (const call of event.calls) {
|
|
5851
|
-
if (isFileMutatingTool(call.name)) {
|
|
5852
|
-
currentRoundModifiedRef.current = true;
|
|
5853
|
-
break;
|
|
6717
|
+
setIsStreaming(true);
|
|
6718
|
+
setStreamingPhase("thinking");
|
|
6719
|
+
setStreamingPlaceholder(pickRandom(STREAMING_PLACEHOLDERS));
|
|
6720
|
+
setCurrentContent("");
|
|
6721
|
+
setCurrentReasoning([]);
|
|
6722
|
+
setCurrentToolCalls([]);
|
|
6723
|
+
setCurrentUsage(void 0);
|
|
6724
|
+
setCurrentElapsed(void 0);
|
|
6725
|
+
setCurrentCost(void 0);
|
|
6726
|
+
setStreamingModel(void 0);
|
|
6727
|
+
setStreamError(void 0);
|
|
6728
|
+
currentContentRef.current = "";
|
|
6729
|
+
currentReasoningRef.current = [];
|
|
6730
|
+
currentToolCallsRef.current = [];
|
|
6731
|
+
currentUsageRef.current = void 0;
|
|
6732
|
+
currentElapsedRef.current = void 0;
|
|
6733
|
+
currentCostRef.current = void 0;
|
|
6734
|
+
currentModelRef.current = void 0;
|
|
6735
|
+
streamErrorRef.current = void 0;
|
|
6736
|
+
currentRoundModifiedRef.current = false;
|
|
6737
|
+
setRewindHintPhase("idle");
|
|
6738
|
+
if (rewindHintTimerRef.current) {
|
|
6739
|
+
clearTimeout(rewindHintTimerRef.current);
|
|
6740
|
+
rewindHintTimerRef.current = null;
|
|
6741
|
+
}
|
|
6742
|
+
const session = sessionRef.current;
|
|
6743
|
+
const abortController = new AbortController();
|
|
6744
|
+
abortRef.current = abortController;
|
|
6745
|
+
try {
|
|
6746
|
+
for await (const event of session.chat(trimmed, {
|
|
6747
|
+
thinkingAllowed: thinkingEnabled || void 0,
|
|
6748
|
+
thinkingEffort: thinkingEnabled ? thinkingEffort : void 0,
|
|
6749
|
+
responseFormat: responseFormat !== "text" ? responseFormat : void 0,
|
|
6750
|
+
toolChoice
|
|
6751
|
+
})) {
|
|
6752
|
+
if (abortController.signal.aborted) break;
|
|
6753
|
+
switch (event.type) {
|
|
6754
|
+
case "text_delta":
|
|
6755
|
+
setStreamingPhase("generating");
|
|
6756
|
+
setCurrentContent((prev) => {
|
|
6757
|
+
const next = prev + event.content;
|
|
6758
|
+
currentContentRef.current = next;
|
|
6759
|
+
return next;
|
|
6760
|
+
});
|
|
6761
|
+
break;
|
|
6762
|
+
case "reasoning_delta":
|
|
6763
|
+
setStreamingPhase("thinking");
|
|
6764
|
+
setCurrentReasoning((prev) => {
|
|
6765
|
+
const last = prev[prev.length - 1];
|
|
6766
|
+
const next = last !== void 0 ? [...prev.slice(0, -1), last + event.content] : [...prev, event.content];
|
|
6767
|
+
currentReasoningRef.current = next;
|
|
6768
|
+
return next;
|
|
6769
|
+
});
|
|
6770
|
+
break;
|
|
6771
|
+
case "tool_calls":
|
|
6772
|
+
setStreamingPhase("calling_tools");
|
|
6773
|
+
setCurrentToolCalls((prev) => {
|
|
6774
|
+
const next = [...prev, ...event.calls];
|
|
6775
|
+
currentToolCallsRef.current = next;
|
|
6776
|
+
return next;
|
|
6777
|
+
});
|
|
6778
|
+
for (const call of event.calls) {
|
|
6779
|
+
if (isFileMutatingTool(call.name)) {
|
|
6780
|
+
currentRoundModifiedRef.current = true;
|
|
6781
|
+
break;
|
|
6782
|
+
}
|
|
5854
6783
|
}
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
6784
|
+
break;
|
|
6785
|
+
case "tool_result":
|
|
6786
|
+
setStreamingPhase("executing_tools");
|
|
6787
|
+
setTimeout(() => setStreamingPhase("thinking"), 300);
|
|
6788
|
+
setCurrentContent("");
|
|
6789
|
+
currentContentRef.current = "";
|
|
6790
|
+
setCurrentReasoning((prev) => {
|
|
6791
|
+
const next = [...prev, ""];
|
|
6792
|
+
currentReasoningRef.current = next;
|
|
6793
|
+
return next;
|
|
6794
|
+
});
|
|
6795
|
+
setCurrentToolCalls([]);
|
|
6796
|
+
currentToolCallsRef.current = [];
|
|
6797
|
+
const r = event.result;
|
|
6798
|
+
if (event.name.startsWith("todo_") && event.todoSnapshot) {
|
|
6799
|
+
const allTerminated = event.todoSnapshot.length > 0 && event.todoSnapshot.every(
|
|
6800
|
+
(it) => it.status === "done" || it.status === "failed" || it.status === "skipped"
|
|
6801
|
+
);
|
|
6802
|
+
if (allTerminated) {
|
|
6803
|
+
setTodoSnapshot([]);
|
|
6804
|
+
} else {
|
|
6805
|
+
setTodoSnapshot(event.todoSnapshot);
|
|
6806
|
+
}
|
|
6807
|
+
} else {
|
|
6808
|
+
const line = r.success ? r.summary ?? `\u2705 ${event.name}: ${r.data.slice(0, 500)}${r.data.length > 500 ? "..." : ""}` : `\u274C ${event.name}: ${r.error ?? "\u6267\u884C\u5931\u8D25"}`;
|
|
6809
|
+
setDisplayMessages((prev) => [
|
|
6810
|
+
...prev,
|
|
6811
|
+
{
|
|
6812
|
+
role: "tool",
|
|
6813
|
+
content: line,
|
|
6814
|
+
diff: r.diff
|
|
6815
|
+
}
|
|
6816
|
+
]);
|
|
6817
|
+
}
|
|
6818
|
+
break;
|
|
6819
|
+
case "usage":
|
|
6820
|
+
setCurrentUsage(event.usage);
|
|
6821
|
+
setStreamingModel(event.model);
|
|
6822
|
+
currentUsageRef.current = event.usage;
|
|
6823
|
+
currentModelRef.current = event.model;
|
|
5868
6824
|
{
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
6825
|
+
const cost = calculateCost(
|
|
6826
|
+
event.usage,
|
|
6827
|
+
event.model
|
|
6828
|
+
);
|
|
6829
|
+
setCurrentCost(cost.totalCost);
|
|
6830
|
+
currentCostRef.current = cost.totalCost;
|
|
5872
6831
|
}
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
6832
|
+
break;
|
|
6833
|
+
case "done":
|
|
6834
|
+
setCurrentElapsed(event.elapsed);
|
|
6835
|
+
currentElapsedRef.current = event.elapsed;
|
|
6836
|
+
break;
|
|
6837
|
+
case "error":
|
|
6838
|
+
setStreamError(event.error.message);
|
|
6839
|
+
streamErrorRef.current = event.error.message;
|
|
6840
|
+
break;
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
} catch (err) {
|
|
6844
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
6845
|
+
setStreamError(msg);
|
|
6846
|
+
streamErrorRef.current = msg;
|
|
6847
|
+
} finally {
|
|
6848
|
+
setIsStreaming(false);
|
|
6849
|
+
setStreamingPhase(null);
|
|
6850
|
+
setIdlePlaceholder(pickRandom(IDLE_PLACEHOLDERS));
|
|
6851
|
+
abortRef.current = null;
|
|
6852
|
+
const finContent = currentContentRef.current;
|
|
6853
|
+
const finReasoning = currentReasoningRef.current.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6854
|
+
const finToolCalls = filterTodoToolCalls(currentToolCallsRef.current);
|
|
6855
|
+
const finStreamError = streamErrorRef.current;
|
|
6856
|
+
if (finContent || finToolCalls || finStreamError) {
|
|
6857
|
+
const completed = {
|
|
6858
|
+
content: finStreamError ? `\u26A0 \u8BF7\u6C42\u51FA\u9519\uFF1A${finStreamError}` : finContent || "",
|
|
6859
|
+
...finReasoning.length > 0 ? { reasoning: finReasoning } : {},
|
|
6860
|
+
toolCalls: finToolCalls,
|
|
6861
|
+
usage: currentUsageRef.current,
|
|
6862
|
+
elapsed: currentElapsedRef.current,
|
|
6863
|
+
cost: currentCostRef.current,
|
|
6864
|
+
model: currentModelRef.current
|
|
6865
|
+
};
|
|
6866
|
+
setDisplayMessages((prev) => [
|
|
6867
|
+
...prev,
|
|
5880
6868
|
{
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
6869
|
+
role: "assistant",
|
|
6870
|
+
content: completed.content,
|
|
6871
|
+
assistantDetail: completed
|
|
5884
6872
|
}
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
6873
|
+
]);
|
|
6874
|
+
}
|
|
6875
|
+
if (currentRoundModifiedRef.current && !finStreamError) {
|
|
6876
|
+
setRewindHintPhase("pending");
|
|
6877
|
+
if (rewindHintTimerRef.current) clearTimeout(rewindHintTimerRef.current);
|
|
6878
|
+
rewindHintTimerRef.current = setTimeout(() => {
|
|
6879
|
+
setRewindHintPhase((prev) => prev === "pending" ? "visible" : prev);
|
|
6880
|
+
rewindHintTimerRef.current = null;
|
|
6881
|
+
}, 2e3);
|
|
5894
6882
|
}
|
|
5895
6883
|
}
|
|
5896
|
-
}
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
};
|
|
5917
|
-
setDisplayMessages((prev) => [
|
|
5918
|
-
...prev,
|
|
5919
|
-
{
|
|
5920
|
-
role: "assistant",
|
|
5921
|
-
content: completed.content,
|
|
5922
|
-
assistantDetail: completed
|
|
5923
|
-
}
|
|
5924
|
-
]);
|
|
5925
|
-
}
|
|
5926
|
-
if (currentRoundModifiedRef.current && !finStreamError) {
|
|
5927
|
-
setRewindHintPhase("pending");
|
|
5928
|
-
if (rewindHintTimerRef.current) clearTimeout(rewindHintTimerRef.current);
|
|
5929
|
-
rewindHintTimerRef.current = setTimeout(() => {
|
|
5930
|
-
setRewindHintPhase((prev) => prev === "pending" ? "visible" : prev);
|
|
5931
|
-
rewindHintTimerRef.current = null;
|
|
5932
|
-
}, 2e3);
|
|
5933
|
-
}
|
|
5934
|
-
}
|
|
5935
|
-
}, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills, thinkingEnabled, thinkingEffort, responseFormat, toolChoice, activeModel, sessionMode, isStreaming, rewinding]);
|
|
6884
|
+
},
|
|
6885
|
+
[
|
|
6886
|
+
onLaunchGame,
|
|
6887
|
+
onLaunchStock,
|
|
6888
|
+
currentContent,
|
|
6889
|
+
currentReasoning,
|
|
6890
|
+
currentToolCalls,
|
|
6891
|
+
skills,
|
|
6892
|
+
skillSelectIndex,
|
|
6893
|
+
getFilteredSkills,
|
|
6894
|
+
thinkingEnabled,
|
|
6895
|
+
thinkingEffort,
|
|
6896
|
+
responseFormat,
|
|
6897
|
+
toolChoice,
|
|
6898
|
+
activeModel,
|
|
6899
|
+
sessionMode,
|
|
6900
|
+
isStreaming,
|
|
6901
|
+
rewinding
|
|
6902
|
+
]
|
|
6903
|
+
);
|
|
5936
6904
|
useEffect4(() => {
|
|
5937
6905
|
if (!isStreaming && externalCostTracker) {
|
|
5938
6906
|
setTodayCost(externalCostTracker.todayTotalCost);
|
|
5939
6907
|
}
|
|
5940
6908
|
}, [isStreaming, externalCostTracker]);
|
|
5941
|
-
return /* @__PURE__ */
|
|
5942
|
-
!hasConversationStarted && /* @__PURE__ */
|
|
5943
|
-
/* @__PURE__ */
|
|
6909
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
|
|
6910
|
+
!hasConversationStarted && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", marginBottom: 1, children: [
|
|
6911
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
|
|
5944
6912
|
const colorIndex = (i + offset) % CYBER_PALETTE.length;
|
|
5945
|
-
return /* @__PURE__ */
|
|
6913
|
+
return /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
|
|
5946
6914
|
}) }),
|
|
5947
|
-
/* @__PURE__ */
|
|
5948
|
-
/* @__PURE__ */
|
|
6915
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", justifyContent: "center", children: [
|
|
6916
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "#00ff41", children: [
|
|
5949
6917
|
" \u2714 ",
|
|
5950
6918
|
"\u5DF2\u5C31\u7EEA ",
|
|
5951
6919
|
skillCount,
|
|
5952
6920
|
" \u4E2A Skill"
|
|
5953
6921
|
] }),
|
|
5954
|
-
/* @__PURE__ */
|
|
6922
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "#00ffff", children: [
|
|
5955
6923
|
" \u2139 ",
|
|
5956
6924
|
"\u5DF2\u5C31\u7EEA ",
|
|
5957
6925
|
toolCount,
|
|
5958
6926
|
" \u4E2A\u5DE5\u5177"
|
|
5959
6927
|
] }),
|
|
5960
|
-
/* @__PURE__ */
|
|
6928
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "#00ffff", children: [
|
|
5961
6929
|
" \u{1F527} \u6A21\u578B ",
|
|
5962
6930
|
SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
|
|
5963
6931
|
] }),
|
|
5964
|
-
thinkingEnabled && /* @__PURE__ */
|
|
6932
|
+
thinkingEnabled && /* @__PURE__ */ jsxs10(Text11, { color: "#ff9800", children: [
|
|
5965
6933
|
" \u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
|
|
5966
6934
|
thinkingEffort === "max" ? "Max" : "High"
|
|
5967
6935
|
] }),
|
|
5968
|
-
sessionMode === "plan" && /* @__PURE__ */
|
|
5969
|
-
responseFormat === "json_object" && /* @__PURE__ */
|
|
5970
|
-
toolChoice !== void 0 && /* @__PURE__ */
|
|
6936
|
+
sessionMode === "plan" && /* @__PURE__ */ jsx10(Text11, { color: "#ff69b4", bold: true, children: " \u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" }),
|
|
6937
|
+
responseFormat === "json_object" && /* @__PURE__ */ jsx10(Text11, { color: "#4caf50", children: " \u{1F4C4} JSON" }),
|
|
6938
|
+
toolChoice !== void 0 && /* @__PURE__ */ jsxs10(Text11, { color: "#e91e63", children: [
|
|
5971
6939
|
" \u{1F6E0} ",
|
|
5972
6940
|
toolChoice === "none" ? "\u7981\u6B62\u5DE5\u5177" : toolChoice === "required" ? "\u5F3A\u5236\u5DE5\u5177" : ""
|
|
5973
6941
|
] }),
|
|
@@ -5975,52 +6943,62 @@ function ChatSession({
|
|
|
5975
6943
|
const tip = cmdTips[cmdTipIndex % cmdTips.length];
|
|
5976
6944
|
if (!tip) return null;
|
|
5977
6945
|
const text = `${tip.name} ${tip.desc}`;
|
|
5978
|
-
return /* @__PURE__ */
|
|
5979
|
-
/* @__PURE__ */
|
|
5980
|
-
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */
|
|
6946
|
+
return /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
6947
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#808080", children: " \u{1F4A1} " }),
|
|
6948
|
+
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx10(Text11, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx10(Text11, { color: "#808080", children: text })
|
|
5981
6949
|
] });
|
|
5982
6950
|
})(),
|
|
5983
|
-
verbose ? /* @__PURE__ */
|
|
6951
|
+
verbose ? /* @__PURE__ */ jsx10(Text11, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
|
|
5984
6952
|
] }),
|
|
5985
|
-
/* @__PURE__ */
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6953
|
+
/* @__PURE__ */ jsxs10(
|
|
6954
|
+
Box10,
|
|
6955
|
+
{
|
|
6956
|
+
flexGrow: 1,
|
|
6957
|
+
flexDirection: "column",
|
|
6958
|
+
justifyContent: "center",
|
|
6959
|
+
alignItems: "flex-end",
|
|
6960
|
+
children: [
|
|
6961
|
+
balanceLoading && balance === null ? /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
6962
|
+
/* @__PURE__ */ jsx10(Text11, { color: "yellow", children: "\u{1F4B0} " }),
|
|
6963
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "yellow", children: [
|
|
6964
|
+
"\u4F59\u989D \xA5",
|
|
6965
|
+
balance.toFixed(2)
|
|
6966
|
+
] })
|
|
6967
|
+
] }) : null,
|
|
6968
|
+
todayCost !== null ? /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
6969
|
+
/* @__PURE__ */ jsx10(Text11, { color: "cyan", children: "\u{1F4CA} " }),
|
|
6970
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
|
|
6971
|
+
"\u4ECA\u65E5 \xA5",
|
|
6972
|
+
todayCost.toFixed(2)
|
|
6973
|
+
] })
|
|
6974
|
+
] }) : null
|
|
6975
|
+
]
|
|
6976
|
+
}
|
|
6977
|
+
)
|
|
6001
6978
|
] }),
|
|
6002
|
-
/* @__PURE__ */
|
|
6003
|
-
/* @__PURE__ */
|
|
6979
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
6980
|
+
/* @__PURE__ */ jsx10(Static, { items: displayMessages, children: (msg, i) => {
|
|
6004
6981
|
if (msg.role === "user") {
|
|
6005
|
-
return /* @__PURE__ */
|
|
6006
|
-
/* @__PURE__ */
|
|
6007
|
-
/* @__PURE__ */
|
|
6982
|
+
return /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
6983
|
+
/* @__PURE__ */ jsx10(Box10, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
|
|
6984
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, children: /* @__PURE__ */ jsx10(Text11, { wrap: "wrap", children: msg.content }) })
|
|
6008
6985
|
] }, i);
|
|
6009
6986
|
}
|
|
6010
6987
|
if (msg.role === "tool") {
|
|
6011
|
-
return /* @__PURE__ */
|
|
6012
|
-
/* @__PURE__ */
|
|
6013
|
-
/* @__PURE__ */
|
|
6014
|
-
/* @__PURE__ */
|
|
6988
|
+
return /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
6989
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
6990
|
+
/* @__PURE__ */ jsx10(Box10, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u{1F527}" }) }),
|
|
6991
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, wrap: "wrap", children: msg.content }) })
|
|
6015
6992
|
] }),
|
|
6016
|
-
msg.diff && /* @__PURE__ */
|
|
6993
|
+
msg.diff && /* @__PURE__ */ jsx10(DiffPreview, { diff: msg.diff })
|
|
6017
6994
|
] }, i);
|
|
6018
6995
|
}
|
|
6019
6996
|
const detail = msg.assistantDetail;
|
|
6020
|
-
return /* @__PURE__ */
|
|
6997
|
+
return /* @__PURE__ */ jsx10(
|
|
6021
6998
|
AssistantMessage,
|
|
6022
6999
|
{
|
|
6023
7000
|
content: msg.content,
|
|
7001
|
+
reasoning: detail?.reasoning,
|
|
6024
7002
|
toolCalls: detail?.toolCalls,
|
|
6025
7003
|
isStreaming: false,
|
|
6026
7004
|
usage: detail?.usage,
|
|
@@ -6031,10 +7009,11 @@ function ChatSession({
|
|
|
6031
7009
|
i
|
|
6032
7010
|
);
|
|
6033
7011
|
} }, staticKey),
|
|
6034
|
-
isStreaming && /* @__PURE__ */
|
|
7012
|
+
isStreaming && /* @__PURE__ */ jsx10(
|
|
6035
7013
|
AssistantMessage,
|
|
6036
7014
|
{
|
|
6037
7015
|
content: currentContent,
|
|
7016
|
+
reasoning: currentReasoning,
|
|
6038
7017
|
toolCalls: currentToolCalls.length > 0 ? currentToolCalls : void 0,
|
|
6039
7018
|
isStreaming: true,
|
|
6040
7019
|
usage: _currentUsage,
|
|
@@ -6042,106 +7021,100 @@ function ChatSession({
|
|
|
6042
7021
|
model: _streamingModel
|
|
6043
7022
|
}
|
|
6044
7023
|
),
|
|
6045
|
-
!isStreaming && streamError && /* @__PURE__ */
|
|
7024
|
+
!isStreaming && streamError && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs10(Text11, { color: "red", children: [
|
|
6046
7025
|
"\u26A0 ",
|
|
6047
7026
|
streamError
|
|
6048
7027
|
] }) })
|
|
6049
7028
|
] }),
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
/* @__PURE__ */
|
|
6053
|
-
|
|
7029
|
+
todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx10(TodoListPanel, { items: todoSnapshot }),
|
|
7030
|
+
selectingModel ? /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
7031
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
7032
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
7033
|
+
/* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
|
|
6054
7034
|
modelOptions.map((id, i) => {
|
|
6055
7035
|
const meta = SUPPORTED_MODELS[id];
|
|
6056
7036
|
const isCurrent = id === activeModel;
|
|
6057
7037
|
const isSelected = i === modelSelectIndex;
|
|
6058
7038
|
const marker = isSelected ? " > " : " ";
|
|
6059
7039
|
const suffix = isCurrent ? " (\u5F53\u524D)" : "";
|
|
6060
|
-
return /* @__PURE__ */
|
|
6061
|
-
/* @__PURE__ */
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
marker,
|
|
6068
|
-
meta.displayName,
|
|
6069
|
-
suffix
|
|
6070
|
-
]
|
|
6071
|
-
}
|
|
6072
|
-
),
|
|
6073
|
-
isSelected && /* @__PURE__ */ jsxs9(Text10, { color: "#808080", children: [
|
|
7040
|
+
return /* @__PURE__ */ jsxs10(Box10, { children: [
|
|
7041
|
+
/* @__PURE__ */ jsxs10(Text11, { color: isSelected ? "#00ff41" : void 0, bold: isSelected, children: [
|
|
7042
|
+
marker,
|
|
7043
|
+
meta.displayName,
|
|
7044
|
+
suffix
|
|
7045
|
+
] }),
|
|
7046
|
+
isSelected && /* @__PURE__ */ jsxs10(Text11, { color: "#808080", children: [
|
|
6074
7047
|
" \u2014 ",
|
|
6075
7048
|
id
|
|
6076
7049
|
] })
|
|
6077
7050
|
] }, id);
|
|
6078
7051
|
}),
|
|
6079
|
-
/* @__PURE__ */
|
|
7052
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
6080
7053
|
] }),
|
|
6081
|
-
/* @__PURE__ */
|
|
6082
|
-
] }) : rewindSelecting ? /* @__PURE__ */
|
|
6083
|
-
/* @__PURE__ */
|
|
6084
|
-
/* @__PURE__ */
|
|
6085
|
-
/* @__PURE__ */
|
|
7054
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
|
|
7055
|
+
] }) : rewindSelecting ? /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
7056
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
7057
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
7058
|
+
/* @__PURE__ */ jsx10(Text11, { bold: true, color: "#ff9800", children: "\u9009\u62E9\u8981\u56DE\u9000\u7684\u68C0\u67E5\u70B9\uFF1A" }),
|
|
6086
7059
|
rewindList.map((cp2, i) => {
|
|
6087
7060
|
const isSelected = i === rewindSelectIndex;
|
|
6088
7061
|
const marker = isSelected ? " > " : " ";
|
|
6089
7062
|
const time = new Date(cp2.timestamp).toLocaleTimeString();
|
|
6090
7063
|
const preview = cp2.preview || "(\u7A7A)";
|
|
6091
7064
|
const tag = cp2.isGitRepo ? "" : " [\u975E git\uFF0C\u4EC5\u5BF9\u8BDD]";
|
|
6092
|
-
return /* @__PURE__ */
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
" `",
|
|
6104
|
-
preview,
|
|
6105
|
-
tag,
|
|
6106
|
-
"`"
|
|
6107
|
-
]
|
|
6108
|
-
}
|
|
6109
|
-
) }, cp2.index);
|
|
7065
|
+
return /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsxs10(Text11, { color: isSelected ? "#ff9800" : void 0, bold: isSelected, children: [
|
|
7066
|
+
marker,
|
|
7067
|
+
"#",
|
|
7068
|
+
i + 1,
|
|
7069
|
+
" ",
|
|
7070
|
+
time,
|
|
7071
|
+
" `",
|
|
7072
|
+
preview,
|
|
7073
|
+
tag,
|
|
7074
|
+
"`"
|
|
7075
|
+
] }) }, cp2.index);
|
|
6110
7076
|
}),
|
|
6111
|
-
/* @__PURE__ */
|
|
7077
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
6112
7078
|
] }),
|
|
6113
|
-
/* @__PURE__ */
|
|
6114
|
-
] }) : /* @__PURE__ */
|
|
6115
|
-
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */
|
|
7079
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
|
|
7080
|
+
] }) : /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
7081
|
+
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx10(Box10, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs10(Text11, { bold: true, color: PHASE_CONFIG[streamingPhase].color, children: [
|
|
6116
7082
|
PHASE_CONFIG[streamingPhase].icon,
|
|
6117
7083
|
" ",
|
|
6118
7084
|
PHASE_CONFIG[streamingPhase].label,
|
|
6119
7085
|
" ",
|
|
6120
|
-
/* @__PURE__ */
|
|
7086
|
+
/* @__PURE__ */ jsx10(InkSpinner3, { type: "dots" })
|
|
6121
7087
|
] }) }) : rewindHintPhase === "visible" ? (
|
|
6122
7088
|
// 本轮修改了文件时,流式结束后 2s 在原位置展示 /rewind 提示
|
|
6123
7089
|
// 一直保留到下次对话开始,与 /rewind 1(最新检查点)配套
|
|
6124
|
-
/* @__PURE__ */
|
|
7090
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx10(Text11, { color: "#808080", children: "\u21A9 /rewind 1 \u53EF\u64A4\u56DE\u672C\u6B21\u4FEE\u6539" }) })
|
|
6125
7091
|
) : null,
|
|
6126
|
-
/* @__PURE__ */
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
"
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
7092
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: hasConversationStarted || sessionMode === "plan" ? /* @__PURE__ */ jsxs10(
|
|
7093
|
+
Text11,
|
|
7094
|
+
{
|
|
7095
|
+
color: sessionMode === "plan" ? "#ff69b4" : "#00ffff",
|
|
7096
|
+
dimColor: sessionMode !== "plan",
|
|
7097
|
+
children: [
|
|
7098
|
+
/* @__PURE__ */ jsx10(Text11, { children: sessionMode === "plan" ? "\u2500".repeat(Math.max(dividerWidth - 48, 1)) : "\u2500".repeat(Math.max(dividerWidth - 35, 10)) }),
|
|
7099
|
+
balance !== null && /* @__PURE__ */ jsxs10(Text11, { color: "yellow", children: [
|
|
7100
|
+
" \u{1F4B0} \u4F59\u989D \xA5",
|
|
7101
|
+
balance.toFixed(2)
|
|
7102
|
+
] }),
|
|
7103
|
+
isStreaming ? /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
|
|
7104
|
+
" \u{1F4CA} \u672C\u6B21 \xA5",
|
|
7105
|
+
sessionCost > 0 ? sessionCost.toFixed(4) + " " : "",
|
|
7106
|
+
/* @__PURE__ */ jsx10(InkSpinner3, { type: "dots" })
|
|
7107
|
+
] }) : sessionCost > 0 ? /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
|
|
7108
|
+
" \u{1F4CA} \u672C\u6B21 \xA5",
|
|
7109
|
+
sessionCost.toFixed(4)
|
|
7110
|
+
] }) : null,
|
|
7111
|
+
sessionMode === "plan" && /* @__PURE__ */ jsx10(Text11, { color: "#ff69b4", bold: true, children: " \u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" })
|
|
7112
|
+
]
|
|
7113
|
+
}
|
|
7114
|
+
) : /* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
7115
|
+
/* @__PURE__ */ jsxs10(Box10, { children: [
|
|
7116
|
+
/* @__PURE__ */ jsx10(Box10, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
|
|
7117
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx10(Text11, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx10(Text11, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx10(Text11, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx10(Text11, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx10(
|
|
6145
7118
|
TextInput,
|
|
6146
7119
|
{
|
|
6147
7120
|
value: input,
|
|
@@ -6152,19 +7125,19 @@ function ChatSession({
|
|
|
6152
7125
|
inputKey
|
|
6153
7126
|
) })
|
|
6154
7127
|
] }),
|
|
6155
|
-
/* @__PURE__ */
|
|
6156
|
-
/* @__PURE__ */
|
|
6157
|
-
/* @__PURE__ */
|
|
7128
|
+
/* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
7129
|
+
/* @__PURE__ */ jsx10(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
|
|
7130
|
+
/* @__PURE__ */ jsx10(FileSelector, { files, input, selectedIndex: fileSelectIndex })
|
|
6158
7131
|
] }),
|
|
6159
|
-
doubleCtrlC && !isStreaming && /* @__PURE__ */
|
|
6160
|
-
isStreaming && /* @__PURE__ */
|
|
7132
|
+
doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
|
|
7133
|
+
isStreaming && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
|
|
6161
7134
|
] });
|
|
6162
7135
|
}
|
|
6163
7136
|
|
|
6164
7137
|
// src/ui/GamePicker.tsx
|
|
6165
|
-
import { Box as
|
|
7138
|
+
import { Box as Box11, Text as Text12, useInput as useInput2 } from "ink";
|
|
6166
7139
|
import { useState as useState5, useCallback as useCallback3 } from "react";
|
|
6167
|
-
import { jsx as
|
|
7140
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
6168
7141
|
function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
6169
7142
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
6170
7143
|
const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
|
|
@@ -6192,18 +7165,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
|
6192
7165
|
[games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
|
|
6193
7166
|
)
|
|
6194
7167
|
);
|
|
6195
|
-
return /* @__PURE__ */
|
|
6196
|
-
/* @__PURE__ */
|
|
6197
|
-
/* @__PURE__ */
|
|
7168
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
7169
|
+
/* @__PURE__ */ jsx11(Box11, { marginBottom: 1, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
|
|
7170
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: games.map((game, index) => {
|
|
6198
7171
|
const isSelected = index === selectedIndex;
|
|
6199
|
-
return /* @__PURE__ */
|
|
6200
|
-
/* @__PURE__ */
|
|
6201
|
-
/* @__PURE__ */
|
|
6202
|
-
/* @__PURE__ */
|
|
7172
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
|
|
7173
|
+
/* @__PURE__ */ jsx11(Box11, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx11(Text12, { children: " " }) }),
|
|
7174
|
+
/* @__PURE__ */ jsx11(Box11, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
|
|
7175
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: game.description }) })
|
|
6203
7176
|
] }, game.id);
|
|
6204
7177
|
}) }),
|
|
6205
|
-
/* @__PURE__ */
|
|
6206
|
-
doubleCtrlC && /* @__PURE__ */
|
|
7178
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
|
|
7179
|
+
doubleCtrlC && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
6207
7180
|
] });
|
|
6208
7181
|
}
|
|
6209
7182
|
|
|
@@ -6220,9 +7193,9 @@ function listGames() {
|
|
|
6220
7193
|
}
|
|
6221
7194
|
|
|
6222
7195
|
// src/game/brick-breaker/index.tsx
|
|
6223
|
-
import { Box as
|
|
7196
|
+
import { Box as Box12, Text as Text13, useInput as useInput3, render as render2 } from "ink";
|
|
6224
7197
|
import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback4 } from "react";
|
|
6225
|
-
import { jsx as
|
|
7198
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
6226
7199
|
var GAME_WIDTH = 40;
|
|
6227
7200
|
var GAME_HEIGHT = 18;
|
|
6228
7201
|
var PADDLE_WIDTH = 9;
|
|
@@ -6412,49 +7385,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
6412
7385
|
const board = buildBoard(s);
|
|
6413
7386
|
const def = getLevel(s.level);
|
|
6414
7387
|
void tick2;
|
|
6415
|
-
return /* @__PURE__ */
|
|
6416
|
-
/* @__PURE__ */
|
|
6417
|
-
/* @__PURE__ */
|
|
7388
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
7389
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
7390
|
+
/* @__PURE__ */ jsx12(Box12, { width: 20, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6418
7391
|
"\u5173\u5361 ",
|
|
6419
7392
|
s.level,
|
|
6420
7393
|
": ",
|
|
6421
|
-
/* @__PURE__ */
|
|
7394
|
+
/* @__PURE__ */ jsx12(Text13, { color: "cyan", children: def.desc })
|
|
6422
7395
|
] }) }),
|
|
6423
|
-
/* @__PURE__ */
|
|
7396
|
+
/* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6424
7397
|
"\u5206\u6570: ",
|
|
6425
|
-
/* @__PURE__ */
|
|
7398
|
+
/* @__PURE__ */ jsx12(Text13, { color: "yellow", children: String(s.score).padStart(3, "0") })
|
|
6426
7399
|
] }) }),
|
|
6427
|
-
/* @__PURE__ */
|
|
7400
|
+
/* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6428
7401
|
"\u751F\u547D: ",
|
|
6429
|
-
/* @__PURE__ */
|
|
7402
|
+
/* @__PURE__ */ jsx12(Text13, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
|
|
6430
7403
|
] }) }),
|
|
6431
|
-
/* @__PURE__ */
|
|
7404
|
+
/* @__PURE__ */ jsx12(Box12, { width: 10, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6432
7405
|
"\u7816\u5757: ",
|
|
6433
|
-
/* @__PURE__ */
|
|
7406
|
+
/* @__PURE__ */ jsx12(Text13, { color: "cyan", children: aliveCount })
|
|
6434
7407
|
] }) }),
|
|
6435
|
-
/* @__PURE__ */
|
|
7408
|
+
/* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: s.paused ? "gray" : "green", children: [
|
|
6436
7409
|
"[",
|
|
6437
7410
|
s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
|
|
6438
7411
|
"]"
|
|
6439
7412
|
] }) })
|
|
6440
7413
|
] }),
|
|
6441
|
-
/* @__PURE__ */
|
|
6442
|
-
/* @__PURE__ */
|
|
7414
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
7415
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6443
7416
|
"\u250C",
|
|
6444
7417
|
"\u2500".repeat(GAME_WIDTH),
|
|
6445
7418
|
"\u2510"
|
|
6446
7419
|
] }),
|
|
6447
|
-
/* @__PURE__ */
|
|
6448
|
-
/* @__PURE__ */
|
|
7420
|
+
/* @__PURE__ */ jsx12(Text13, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
|
|
7421
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6449
7422
|
"\u2514",
|
|
6450
7423
|
"\u2500".repeat(GAME_WIDTH),
|
|
6451
7424
|
"\u2518"
|
|
6452
7425
|
] })
|
|
6453
7426
|
] }),
|
|
6454
|
-
selectingLevel && /* @__PURE__ */
|
|
6455
|
-
/* @__PURE__ */
|
|
6456
|
-
/* @__PURE__ */
|
|
6457
|
-
/* @__PURE__ */
|
|
7427
|
+
selectingLevel && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
7428
|
+
/* @__PURE__ */ jsx12(Text13, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
|
|
7429
|
+
/* @__PURE__ */ jsx12(Box12, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx12(Box12, { width: 22, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
7430
|
+
/* @__PURE__ */ jsx12(Text13, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
|
|
6458
7431
|
". ",
|
|
6459
7432
|
lv.desc,
|
|
6460
7433
|
" (",
|
|
@@ -6463,16 +7436,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
6463
7436
|
lv.cols,
|
|
6464
7437
|
")"
|
|
6465
7438
|
] }) }, i)) }),
|
|
6466
|
-
/* @__PURE__ */
|
|
7439
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
|
|
6467
7440
|
] }),
|
|
6468
|
-
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */
|
|
6469
|
-
/* @__PURE__ */
|
|
6470
|
-
/* @__PURE__ */
|
|
7441
|
+
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, children: [
|
|
7442
|
+
/* @__PURE__ */ jsx12(Text13, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
|
|
7443
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
6471
7444
|
" \u5206\u6570: ",
|
|
6472
|
-
/* @__PURE__ */
|
|
7445
|
+
/* @__PURE__ */ jsx12(Text13, { color: "yellow", children: s.score })
|
|
6473
7446
|
] })
|
|
6474
7447
|
] }),
|
|
6475
|
-
!selectingLevel && /* @__PURE__ */
|
|
7448
|
+
!selectingLevel && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
|
|
6476
7449
|
] });
|
|
6477
7450
|
}
|
|
6478
7451
|
var brick_breaker_default = {
|
|
@@ -6482,7 +7455,7 @@ var brick_breaker_default = {
|
|
|
6482
7455
|
play: async () => {
|
|
6483
7456
|
await new Promise((resolve2) => {
|
|
6484
7457
|
const { unmount } = render2(
|
|
6485
|
-
/* @__PURE__ */
|
|
7458
|
+
/* @__PURE__ */ jsx12(BrickBreakerGame, { onExit: () => {
|
|
6486
7459
|
unmount();
|
|
6487
7460
|
resolve2();
|
|
6488
7461
|
} })
|
|
@@ -6492,9 +7465,9 @@ var brick_breaker_default = {
|
|
|
6492
7465
|
};
|
|
6493
7466
|
|
|
6494
7467
|
// src/game/coder-check/index.tsx
|
|
6495
|
-
import { Box as
|
|
7468
|
+
import { Box as Box13, Text as Text14, useInput as useInput4, render as render3 } from "ink";
|
|
6496
7469
|
import { useState as useState7, useEffect as useEffect6, useRef as useRef5, useCallback as useCallback5 } from "react";
|
|
6497
|
-
import { jsx as
|
|
7470
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6498
7471
|
var GAME_W = 66;
|
|
6499
7472
|
var GAME_H = 20;
|
|
6500
7473
|
var SCORE_H = 6;
|
|
@@ -6965,44 +7938,44 @@ function CoderCheck({ onExit: _onExit }) {
|
|
|
6965
7938
|
const scoreLines = buildScoreLines(scoreStr);
|
|
6966
7939
|
const view = buildGameView(s, scoreLines, scoreColor, s.message);
|
|
6967
7940
|
void tick2;
|
|
6968
|
-
return /* @__PURE__ */
|
|
6969
|
-
/* @__PURE__ */
|
|
7941
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingX: 1, children: [
|
|
7942
|
+
/* @__PURE__ */ jsx13(Box13, { flexDirection: "row", children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
6970
7943
|
"\u751F\u547D ",
|
|
6971
|
-
/* @__PURE__ */
|
|
7944
|
+
/* @__PURE__ */ jsx13(Text14, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
|
|
6972
7945
|
" ",
|
|
6973
7946
|
"\u901F\u5EA6 ",
|
|
6974
|
-
/* @__PURE__ */
|
|
7947
|
+
/* @__PURE__ */ jsxs13(Text14, { color: "cyan", children: [
|
|
6975
7948
|
"Lv.",
|
|
6976
7949
|
Math.floor(s.speed * 10)
|
|
6977
7950
|
] })
|
|
6978
7951
|
] }) }),
|
|
6979
|
-
!s.gameOver && s.target && /* @__PURE__ */
|
|
7952
|
+
!s.gameOver && s.target && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
6980
7953
|
"\u6253\u5B57: ",
|
|
6981
|
-
/* @__PURE__ */
|
|
6982
|
-
/* @__PURE__ */
|
|
7954
|
+
/* @__PURE__ */ jsx13(Text14, { color: "green", children: s.typed }),
|
|
7955
|
+
/* @__PURE__ */ jsx13(Text14, { color: "white", children: s.target.slice(s.typed.length) })
|
|
6983
7956
|
] }) }),
|
|
6984
|
-
/* @__PURE__ */
|
|
6985
|
-
/* @__PURE__ */
|
|
7957
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginTop: 1, children: [
|
|
7958
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
6986
7959
|
"\u250C",
|
|
6987
7960
|
"\u2500".repeat(GAME_W),
|
|
6988
7961
|
"\u2510"
|
|
6989
7962
|
] }),
|
|
6990
|
-
view.map((row, i) => /* @__PURE__ */
|
|
6991
|
-
/* @__PURE__ */
|
|
7963
|
+
view.map((row, i) => /* @__PURE__ */ jsx13(Text14, { children: `\u2502${row}\u2502` }, i)),
|
|
7964
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
6992
7965
|
"\u2514",
|
|
6993
7966
|
"\u2500".repeat(GAME_W),
|
|
6994
7967
|
"\u2518"
|
|
6995
7968
|
] })
|
|
6996
7969
|
] }),
|
|
6997
|
-
s.gameOver && /* @__PURE__ */
|
|
6998
|
-
/* @__PURE__ */
|
|
6999
|
-
/* @__PURE__ */
|
|
7970
|
+
s.gameOver && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
|
|
7971
|
+
/* @__PURE__ */ jsx13(Text14, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
|
|
7972
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
7000
7973
|
" \u5F97\u5206: ",
|
|
7001
|
-
/* @__PURE__ */
|
|
7974
|
+
/* @__PURE__ */ jsx13(Text14, { color: "yellow", children: s.score }),
|
|
7002
7975
|
" r \u91CD\u5F00 q \u9000\u51FA"
|
|
7003
7976
|
] })
|
|
7004
7977
|
] }),
|
|
7005
|
-
/* @__PURE__ */
|
|
7978
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
|
|
7006
7979
|
] });
|
|
7007
7980
|
}
|
|
7008
7981
|
var coder_check_default = {
|
|
@@ -7012,7 +7985,7 @@ var coder_check_default = {
|
|
|
7012
7985
|
play: async () => {
|
|
7013
7986
|
await new Promise((resolve2) => {
|
|
7014
7987
|
const { unmount } = render3(
|
|
7015
|
-
/* @__PURE__ */
|
|
7988
|
+
/* @__PURE__ */ jsx13(CoderCheck, { onExit: () => {
|
|
7016
7989
|
unmount();
|
|
7017
7990
|
resolve2();
|
|
7018
7991
|
} })
|
|
@@ -7392,12 +8365,12 @@ import { render as render4 } from "ink";
|
|
|
7392
8365
|
import chalk5 from "chalk";
|
|
7393
8366
|
|
|
7394
8367
|
// src/stock/StockList.tsx
|
|
7395
|
-
import { Box as
|
|
8368
|
+
import { Box as Box14, Text as Text15, useInput as useInput5 } from "ink";
|
|
7396
8369
|
import { useState as useState8, useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo2 } from "react";
|
|
7397
8370
|
import asciichart from "asciichart";
|
|
7398
8371
|
import os from "os";
|
|
7399
8372
|
import { join as join10 } from "path";
|
|
7400
|
-
import { jsx as
|
|
8373
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7401
8374
|
var SETTINGS_PATH = join10(os.homedir(), ".dskcode", "settings.json");
|
|
7402
8375
|
function toFileUrl(p) {
|
|
7403
8376
|
const norm = p.replace(/\\/g, "/");
|
|
@@ -7616,64 +8589,64 @@ function StockList({ codes, onExit, onBackToChat }) {
|
|
|
7616
8589
|
);
|
|
7617
8590
|
if (detailView) {
|
|
7618
8591
|
if (detailLoading) {
|
|
7619
|
-
return /* @__PURE__ */
|
|
8592
|
+
return /* @__PURE__ */ jsx14(Box14, { paddingLeft: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
|
|
7620
8593
|
}
|
|
7621
8594
|
return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
|
|
7622
8595
|
}
|
|
7623
8596
|
const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
|
|
7624
|
-
return /* @__PURE__ */
|
|
7625
|
-
/* @__PURE__ */
|
|
7626
|
-
/* @__PURE__ */
|
|
7627
|
-
/* @__PURE__ */
|
|
8597
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
8598
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
8599
|
+
/* @__PURE__ */ jsx14(Text15, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
|
|
8600
|
+
/* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
|
|
7628
8601
|
" \u{1F550} ",
|
|
7629
8602
|
currentTime
|
|
7630
8603
|
] }),
|
|
7631
|
-
/* @__PURE__ */
|
|
8604
|
+
/* @__PURE__ */ jsx14(Text15, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
|
|
7632
8605
|
] }),
|
|
7633
|
-
/* @__PURE__ */
|
|
7634
|
-
/* @__PURE__ */
|
|
7635
|
-
/* @__PURE__ */
|
|
7636
|
-
/* @__PURE__ */
|
|
7637
|
-
/* @__PURE__ */
|
|
7638
|
-
/* @__PURE__ */
|
|
8606
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8607
|
+
/* @__PURE__ */ jsx14(Box14, { width: 3 }),
|
|
8608
|
+
/* @__PURE__ */ jsx14(Box14, { width: 9, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u4EE3\u7801" }) }),
|
|
8609
|
+
/* @__PURE__ */ jsx14(Box14, { width: 16, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u540D\u79F0" }) }),
|
|
8610
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
|
|
8611
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
|
|
7639
8612
|
"\u6DA8\u8DCC\u5E45",
|
|
7640
8613
|
sortOrder === "desc" ? " \u25BC" : sortOrder === "asc" ? " \u25B2" : ""
|
|
7641
8614
|
] }) }),
|
|
7642
|
-
/* @__PURE__ */
|
|
7643
|
-
/* @__PURE__ */
|
|
7644
|
-
/* @__PURE__ */
|
|
7645
|
-
/* @__PURE__ */
|
|
8615
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
|
|
8616
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6700\u9AD8" }) }),
|
|
8617
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6700\u4F4E" }) }),
|
|
8618
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
|
|
7646
8619
|
] }),
|
|
7647
|
-
/* @__PURE__ */
|
|
7648
|
-
/* @__PURE__ */
|
|
8620
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
|
|
8621
|
+
/* @__PURE__ */ jsx14(Box14, { flexDirection: "column", children: sortedStocks.map((stock, index) => {
|
|
7649
8622
|
const isSelected = index === selectedIndex;
|
|
7650
8623
|
const isUp = stock.changePercent >= 0;
|
|
7651
8624
|
const color = isUp ? "#ff1493" : "#00ff41";
|
|
7652
|
-
return /* @__PURE__ */
|
|
7653
|
-
/* @__PURE__ */
|
|
7654
|
-
/* @__PURE__ */
|
|
7655
|
-
/* @__PURE__ */
|
|
7656
|
-
/* @__PURE__ */
|
|
7657
|
-
/* @__PURE__ */
|
|
8625
|
+
return /* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8626
|
+
/* @__PURE__ */ jsx14(Box14, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx14(Text15, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx14(Text15, { children: " " }) }),
|
|
8627
|
+
/* @__PURE__ */ jsx14(Box14, { width: 9, children: /* @__PURE__ */ jsx14(Text15, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
|
|
8628
|
+
/* @__PURE__ */ jsx14(Box14, { width: 16, children: /* @__PURE__ */ jsx14(Text15, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
|
|
8629
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
|
|
8630
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { ...cp2(color), children: [
|
|
7658
8631
|
isUp ? "+" : "",
|
|
7659
8632
|
stock.changePercent.toFixed(2),
|
|
7660
8633
|
"%"
|
|
7661
8634
|
] }) }),
|
|
7662
|
-
/* @__PURE__ */
|
|
8635
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { ...cp2(color), children: [
|
|
7663
8636
|
isUp ? "+" : "",
|
|
7664
8637
|
stock.changeAmount.toFixed(3)
|
|
7665
8638
|
] }) }),
|
|
7666
|
-
/* @__PURE__ */
|
|
7667
|
-
/* @__PURE__ */
|
|
7668
|
-
/* @__PURE__ */
|
|
8639
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
|
|
8640
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsx14(Text15, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
|
|
8641
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(Text15, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
|
|
7669
8642
|
] }, stock.code);
|
|
7670
8643
|
}) }),
|
|
7671
|
-
/* @__PURE__ */
|
|
7672
|
-
/* @__PURE__ */
|
|
7673
|
-
/* @__PURE__ */
|
|
7674
|
-
/* @__PURE__ */
|
|
8644
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 o \u6392\u5E8F h \u7F6E\u7070/\u6062\u590D q \u8FD4\u56DE` }) }),
|
|
8645
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8646
|
+
/* @__PURE__ */ jsx14(Text15, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
|
|
8647
|
+
/* @__PURE__ */ jsx14(Text15, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
|
|
7675
8648
|
] }),
|
|
7676
|
-
doubleCtrlC && /* @__PURE__ */
|
|
8649
|
+
doubleCtrlC && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
7677
8650
|
] });
|
|
7678
8651
|
}
|
|
7679
8652
|
function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
@@ -7691,33 +8664,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
7691
8664
|
raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
|
|
7692
8665
|
chartLines = raw.split("\n");
|
|
7693
8666
|
}
|
|
7694
|
-
return /* @__PURE__ */
|
|
7695
|
-
/* @__PURE__ */
|
|
7696
|
-
/* @__PURE__ */
|
|
7697
|
-
/* @__PURE__ */
|
|
8667
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingLeft: 1, children: [
|
|
8668
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
8669
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8670
|
+
/* @__PURE__ */ jsxs14(Text15, { bold: true, color: "#00ffff", children: [
|
|
7698
8671
|
" \u{1F4CA} ",
|
|
7699
8672
|
stock.name,
|
|
7700
8673
|
" "
|
|
7701
8674
|
] }),
|
|
7702
|
-
/* @__PURE__ */
|
|
7703
|
-
currentTime && /* @__PURE__ */
|
|
8675
|
+
/* @__PURE__ */ jsx14(Text15, { dimColor: true, children: stock.code }),
|
|
8676
|
+
currentTime && /* @__PURE__ */ jsxs14(Text15, { dimColor: true, children: [
|
|
7704
8677
|
" \u{1F550} ",
|
|
7705
8678
|
currentTime
|
|
7706
8679
|
] })
|
|
7707
8680
|
] }),
|
|
7708
|
-
/* @__PURE__ */
|
|
8681
|
+
/* @__PURE__ */ jsx14(Text15, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
|
|
7709
8682
|
] }),
|
|
7710
|
-
/* @__PURE__ */
|
|
7711
|
-
/* @__PURE__ */
|
|
7712
|
-
/* @__PURE__ */
|
|
8683
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8684
|
+
/* @__PURE__ */ jsx14(Box14, { width: 16, children: /* @__PURE__ */ jsx14(Text15, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
|
|
8685
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { bold: true, color: colorCode, children: [
|
|
7713
8686
|
arrow,
|
|
7714
8687
|
" ",
|
|
7715
8688
|
formatPrice(stock.price)
|
|
7716
8689
|
] }) })
|
|
7717
8690
|
] }),
|
|
7718
|
-
/* @__PURE__ */
|
|
7719
|
-
/* @__PURE__ */
|
|
7720
|
-
/* @__PURE__ */
|
|
8691
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
8692
|
+
/* @__PURE__ */ jsx14(Box14, { width: 16, children: /* @__PURE__ */ jsx14(Text15, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
8693
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: colorCode, children: [
|
|
7721
8694
|
isUp ? "+" : "",
|
|
7722
8695
|
stock.changePercent.toFixed(2),
|
|
7723
8696
|
"%",
|
|
@@ -7726,8 +8699,8 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
7726
8699
|
stock.changeAmount.toFixed(3)
|
|
7727
8700
|
] }) })
|
|
7728
8701
|
] }),
|
|
7729
|
-
chartLines.length > 0 && /* @__PURE__ */
|
|
7730
|
-
/* @__PURE__ */
|
|
8702
|
+
chartLines.length > 0 && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsx14(Text15, { color: colorCode, children: line || " " }) }, i)) }),
|
|
8703
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
|
|
7731
8704
|
] });
|
|
7732
8705
|
}
|
|
7733
8706
|
|
|
@@ -7812,7 +8785,7 @@ async function scanProjectFiles(baseDir, dir) {
|
|
|
7812
8785
|
}
|
|
7813
8786
|
|
|
7814
8787
|
// src/cli/index.tsx
|
|
7815
|
-
import { jsx as
|
|
8788
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
7816
8789
|
var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
|
|
7817
8790
|
function createCli() {
|
|
7818
8791
|
const program2 = new Command();
|
|
@@ -7914,7 +8887,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
7914
8887
|
const freshResult = await loadAndValidate();
|
|
7915
8888
|
const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
7916
8889
|
const app = renderApp(
|
|
7917
|
-
/* @__PURE__ */
|
|
8890
|
+
/* @__PURE__ */ jsx15(
|
|
7918
8891
|
StockList,
|
|
7919
8892
|
{
|
|
7920
8893
|
codes: codeList,
|
|
@@ -7943,7 +8916,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
7943
8916
|
}
|
|
7944
8917
|
const selectedGame = await new Promise((resolve2) => {
|
|
7945
8918
|
const { unmount } = render4(
|
|
7946
|
-
/* @__PURE__ */
|
|
8919
|
+
/* @__PURE__ */ jsx15(
|
|
7947
8920
|
GamePicker,
|
|
7948
8921
|
{
|
|
7949
8922
|
games,
|
|
@@ -7983,7 +8956,7 @@ async function startChat(ctx, costTracker) {
|
|
|
7983
8956
|
);
|
|
7984
8957
|
const model = defaultProvider?.model ?? "deepseek-v4-flash";
|
|
7985
8958
|
const chatApp = renderApp(
|
|
7986
|
-
/* @__PURE__ */
|
|
8959
|
+
/* @__PURE__ */ jsx15(
|
|
7987
8960
|
ChatSession,
|
|
7988
8961
|
{
|
|
7989
8962
|
skillCount,
|
|
@@ -8001,7 +8974,7 @@ async function startChat(ctx, costTracker) {
|
|
|
8001
8974
|
initGames();
|
|
8002
8975
|
const games = listGames();
|
|
8003
8976
|
const { unmount } = render4(
|
|
8004
|
-
/* @__PURE__ */
|
|
8977
|
+
/* @__PURE__ */ jsx15(
|
|
8005
8978
|
GamePicker,
|
|
8006
8979
|
{
|
|
8007
8980
|
games,
|
|
@@ -8025,7 +8998,7 @@ async function startChat(ctx, costTracker) {
|
|
|
8025
8998
|
setImmediate(() => {
|
|
8026
8999
|
const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
8027
9000
|
const stockApp = renderApp(
|
|
8028
|
-
/* @__PURE__ */
|
|
9001
|
+
/* @__PURE__ */ jsx15(
|
|
8029
9002
|
StockList,
|
|
8030
9003
|
{
|
|
8031
9004
|
codes: defaultStockCodes,
|