dskcode 0.1.25 → 0.1.27
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/README.md +54 -16
- package/dist/{chunk-EF6NIFOH.js → chunk-UV4IWYHZ.js} +1 -1
- package/dist/{chunk-EF6NIFOH.js.map → chunk-UV4IWYHZ.js.map} +1 -1
- package/dist/deepseek-PGX76BK5.js +7 -0
- package/dist/index.js +1112 -336
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/deepseek-MG4NT5YC.js +0 -7
- /package/dist/{deepseek-MG4NT5YC.js.map → deepseek-PGX76BK5.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-UV4IWYHZ.js";
|
|
11
11
|
|
|
12
12
|
// src/cli/index.tsx
|
|
13
13
|
import { Command } from "commander";
|
|
@@ -771,8 +771,8 @@ async function getAllSkills(cwd) {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
// src/cli/index.tsx
|
|
774
|
-
import { readFile as
|
|
775
|
-
import { join as
|
|
774
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
775
|
+
import { join as join10 } from "path";
|
|
776
776
|
|
|
777
777
|
// src/ui/RenderScope.tsx
|
|
778
778
|
import { render } from "ink";
|
|
@@ -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 Box9, Text as Text10, useInput, Static } from "ink";
|
|
809
809
|
import TextInput from "ink-text-input";
|
|
810
810
|
import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useMemo, useRef as useRef2 } from "react";
|
|
811
811
|
|
|
@@ -841,7 +841,7 @@ function useDoubleCtrlC(onExit) {
|
|
|
841
841
|
import InkSpinner2 from "ink-spinner";
|
|
842
842
|
|
|
843
843
|
// src/ui/AssistantMessage.tsx
|
|
844
|
-
import { Box as
|
|
844
|
+
import { Box as Box5, Text as Text6 } from "ink";
|
|
845
845
|
|
|
846
846
|
// src/provider/cost-tracker.ts
|
|
847
847
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
@@ -1248,8 +1248,69 @@ function formatUsageSummary(usage) {
|
|
|
1248
1248
|
}
|
|
1249
1249
|
|
|
1250
1250
|
// src/ui/HighlightedText.tsx
|
|
1251
|
-
import { Text as Text5 } from "ink";
|
|
1252
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1251
|
+
import { Box as Box4, Text as Text5 } from "ink";
|
|
1252
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1253
|
+
function parseCodeBlocks(text) {
|
|
1254
|
+
const segments = [];
|
|
1255
|
+
let current = 0;
|
|
1256
|
+
while (current < text.length) {
|
|
1257
|
+
const openIdx = text.indexOf("```", current);
|
|
1258
|
+
if (openIdx === -1) {
|
|
1259
|
+
segments.push({ text: text.slice(current), type: "plain" });
|
|
1260
|
+
break;
|
|
1261
|
+
}
|
|
1262
|
+
if (openIdx > current) {
|
|
1263
|
+
segments.push({ text: text.slice(current, openIdx), type: "plain" });
|
|
1264
|
+
}
|
|
1265
|
+
const closeIdx = text.indexOf("```", openIdx + 3);
|
|
1266
|
+
if (closeIdx === -1) {
|
|
1267
|
+
segments.push({ text: text.slice(openIdx), type: "plain" });
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
const codeContent = text.slice(openIdx + 3, closeIdx);
|
|
1271
|
+
segments.push({ text: codeContent, type: "code_block" });
|
|
1272
|
+
current = closeIdx + 3;
|
|
1273
|
+
}
|
|
1274
|
+
return segments;
|
|
1275
|
+
}
|
|
1276
|
+
function isTableRow(line) {
|
|
1277
|
+
const t = line.trim();
|
|
1278
|
+
return /^\|.+\|$/.test(t);
|
|
1279
|
+
}
|
|
1280
|
+
function isTableSepRow(line) {
|
|
1281
|
+
const t = line.trim();
|
|
1282
|
+
return /^\|[-: |]+\|$/.test(t) && t.includes("-");
|
|
1283
|
+
}
|
|
1284
|
+
function parseTables(text) {
|
|
1285
|
+
const lines = text.split("\n");
|
|
1286
|
+
const result = [];
|
|
1287
|
+
let plainBuf = "";
|
|
1288
|
+
function flushPlain() {
|
|
1289
|
+
if (plainBuf) {
|
|
1290
|
+
result.push({ text: plainBuf, type: "plain" });
|
|
1291
|
+
plainBuf = "";
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1295
|
+
const line = lines[i] ?? "";
|
|
1296
|
+
if (isTableRow(line) && i + 1 < lines.length && isTableSepRow(lines[i + 1] ?? "") && i + 2 < lines.length && isTableRow(lines[i + 2] ?? "")) {
|
|
1297
|
+
flushPlain();
|
|
1298
|
+
const tableLineList = [];
|
|
1299
|
+
let j = i;
|
|
1300
|
+
while (j < lines.length && isTableRow(lines[j] ?? "")) {
|
|
1301
|
+
tableLineList.push(lines[j]);
|
|
1302
|
+
j++;
|
|
1303
|
+
}
|
|
1304
|
+
result.push({ text: tableLineList.join("\n"), type: "table" });
|
|
1305
|
+
i = j - 1;
|
|
1306
|
+
} else {
|
|
1307
|
+
if (plainBuf) plainBuf += "\n" + line;
|
|
1308
|
+
else plainBuf = line;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
flushPlain();
|
|
1312
|
+
return result;
|
|
1313
|
+
}
|
|
1253
1314
|
function parseBoldPairs(text) {
|
|
1254
1315
|
const segments = [];
|
|
1255
1316
|
let current = 0;
|
|
@@ -1272,24 +1333,23 @@ function parseBoldPairs(text) {
|
|
|
1272
1333
|
}
|
|
1273
1334
|
return segments;
|
|
1274
1335
|
}
|
|
1275
|
-
function
|
|
1336
|
+
function parseInlineCode(text) {
|
|
1276
1337
|
const result = [];
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1338
|
+
let current = 0;
|
|
1339
|
+
while (current < text.length) {
|
|
1340
|
+
const openIdx = text.indexOf("`", current);
|
|
1341
|
+
if (openIdx === -1) {
|
|
1342
|
+
result.push({ text: text.slice(current), type: "plain" });
|
|
1343
|
+
break;
|
|
1281
1344
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
if (openIdx > current) {
|
|
1291
|
-
result.push({ text: text.slice(current, openIdx), type: "plain" });
|
|
1292
|
-
}
|
|
1345
|
+
if (openIdx > current) {
|
|
1346
|
+
result.push({ text: text.slice(current, openIdx), type: "plain" });
|
|
1347
|
+
}
|
|
1348
|
+
let runLength = 1;
|
|
1349
|
+
while (openIdx + runLength < text.length && text[openIdx + runLength] === "`") {
|
|
1350
|
+
runLength++;
|
|
1351
|
+
}
|
|
1352
|
+
if (runLength === 1) {
|
|
1293
1353
|
const closeIdx = text.indexOf("`", openIdx + 1);
|
|
1294
1354
|
if (closeIdx === -1) {
|
|
1295
1355
|
result.push({ text: text.slice(openIdx), type: "plain" });
|
|
@@ -1297,32 +1357,296 @@ function parseCodePairs(segments) {
|
|
|
1297
1357
|
}
|
|
1298
1358
|
result.push({ text: text.slice(openIdx + 1, closeIdx), type: "code" });
|
|
1299
1359
|
current = closeIdx + 1;
|
|
1360
|
+
} else {
|
|
1361
|
+
result.push({
|
|
1362
|
+
text: text.slice(openIdx, openIdx + runLength),
|
|
1363
|
+
type: "plain"
|
|
1364
|
+
});
|
|
1365
|
+
current = openIdx + runLength;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return result;
|
|
1369
|
+
}
|
|
1370
|
+
function parseCodePairs(segments) {
|
|
1371
|
+
const result = [];
|
|
1372
|
+
for (const seg of segments) {
|
|
1373
|
+
if (seg.type === "code_block" || seg.type === "table") {
|
|
1374
|
+
result.push(seg);
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
const parts = parseInlineCode(seg.text);
|
|
1378
|
+
for (const part of parts) {
|
|
1379
|
+
if (part.type === "code") {
|
|
1380
|
+
result.push(part);
|
|
1381
|
+
} else if (seg.type === "bold") {
|
|
1382
|
+
result.push({ text: part.text, type: "bold" });
|
|
1383
|
+
} else {
|
|
1384
|
+
result.push(part);
|
|
1385
|
+
}
|
|
1300
1386
|
}
|
|
1301
1387
|
}
|
|
1302
1388
|
return result;
|
|
1303
1389
|
}
|
|
1390
|
+
var DIFF_ADD_COLOR = "#22c55e";
|
|
1391
|
+
var DIFF_DEL_COLOR = "#ef4444";
|
|
1392
|
+
var DIFF_HUNK_COLOR = "#00cccc";
|
|
1393
|
+
function CodeBlockRenderer({ code }) {
|
|
1394
|
+
const lines = code.split("\n");
|
|
1395
|
+
const firstLine = lines[0] ?? "";
|
|
1396
|
+
const hasLangLine = firstLine.trim().length > 0 && !firstLine.startsWith("+") && !firstLine.startsWith("-") && !firstLine.startsWith("@@") && !firstLine.startsWith(" ");
|
|
1397
|
+
const lang = hasLangLine ? firstLine : void 0;
|
|
1398
|
+
const codeLines = hasLangLine ? lines.slice(1) : lines;
|
|
1399
|
+
if (codeLines.length === 0) {
|
|
1400
|
+
return hasLangLine ? /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, children: /* @__PURE__ */ jsxs4(Text5, { color: "#888888", children: [
|
|
1401
|
+
"\u250C ",
|
|
1402
|
+
lang
|
|
1403
|
+
] }) }) : null;
|
|
1404
|
+
}
|
|
1405
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: [
|
|
1406
|
+
lang && /* @__PURE__ */ jsxs4(Text5, { color: "#888888", children: [
|
|
1407
|
+
"\u250C ",
|
|
1408
|
+
lang
|
|
1409
|
+
] }),
|
|
1410
|
+
codeLines.map((line, i) => {
|
|
1411
|
+
if (line.startsWith("+")) {
|
|
1412
|
+
return /* @__PURE__ */ jsx4(Text5, { color: DIFF_ADD_COLOR, children: line }, i);
|
|
1413
|
+
}
|
|
1414
|
+
if (line.startsWith("-")) {
|
|
1415
|
+
return /* @__PURE__ */ jsx4(Text5, { color: DIFF_DEL_COLOR, children: line }, i);
|
|
1416
|
+
}
|
|
1417
|
+
if (line.startsWith("@@")) {
|
|
1418
|
+
return /* @__PURE__ */ jsx4(Text5, { color: DIFF_HUNK_COLOR, children: line }, i);
|
|
1419
|
+
}
|
|
1420
|
+
return /* @__PURE__ */ jsx4(Text5, { children: line }, i);
|
|
1421
|
+
})
|
|
1422
|
+
] });
|
|
1423
|
+
}
|
|
1424
|
+
var TABLE_MAX_WIDTH = 90;
|
|
1425
|
+
var TABLE_MIN_COL_WIDTH = 3;
|
|
1426
|
+
function charWidth(ch) {
|
|
1427
|
+
const cp2 = ch.codePointAt(0);
|
|
1428
|
+
if (cp2 === void 0) return 0;
|
|
1429
|
+
if (cp2 >= 4352 && cp2 <= 4447 || // Hangul Jamo
|
|
1430
|
+
cp2 === 9001 || cp2 === 9002 || cp2 >= 11904 && cp2 <= 42191 || // CJK Radicals ~ Yi
|
|
1431
|
+
cp2 >= 43360 && cp2 <= 43391 || // Hangul Extended
|
|
1432
|
+
cp2 >= 44032 && cp2 <= 55215 || // Hangul Syllables
|
|
1433
|
+
cp2 >= 63744 && cp2 <= 64255 || // CJK Compat
|
|
1434
|
+
cp2 >= 65040 && cp2 <= 65055 || // Vertical forms
|
|
1435
|
+
cp2 >= 65281 && cp2 <= 65376 || // Fullwidth
|
|
1436
|
+
cp2 >= 65504 && cp2 <= 65510 || cp2 >= 126976 && cp2 <= 131071) {
|
|
1437
|
+
return 2;
|
|
1438
|
+
}
|
|
1439
|
+
return 1;
|
|
1440
|
+
}
|
|
1441
|
+
function visualWidth(text) {
|
|
1442
|
+
let w = 0;
|
|
1443
|
+
for (const ch of text) {
|
|
1444
|
+
w += charWidth(ch);
|
|
1445
|
+
}
|
|
1446
|
+
return w;
|
|
1447
|
+
}
|
|
1448
|
+
function padToWidth(text, targetWidth, align) {
|
|
1449
|
+
const vw = visualWidth(text);
|
|
1450
|
+
const delta = targetWidth - vw;
|
|
1451
|
+
if (delta <= 0) return text;
|
|
1452
|
+
const leftPad = align === "right" ? delta : align === "center" ? Math.floor(delta / 2) : 0;
|
|
1453
|
+
const rightPad = delta - leftPad;
|
|
1454
|
+
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
|
1455
|
+
}
|
|
1456
|
+
function parseTableCells(line) {
|
|
1457
|
+
const t = line.trim();
|
|
1458
|
+
const inner = t.slice(1, t.length - 1);
|
|
1459
|
+
return inner.split("|").map((c) => c.trim());
|
|
1460
|
+
}
|
|
1461
|
+
function parseAlignments(sepLine) {
|
|
1462
|
+
const cells = parseTableCells(sepLine);
|
|
1463
|
+
return cells.map((c) => {
|
|
1464
|
+
const l = c.startsWith(":");
|
|
1465
|
+
const r = c.endsWith(":");
|
|
1466
|
+
if (l && r) return "center";
|
|
1467
|
+
if (r) return "right";
|
|
1468
|
+
return "left";
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
function TableRenderer({ text }) {
|
|
1472
|
+
const rawLines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
1473
|
+
if (rawLines.length < 2) return /* @__PURE__ */ jsx4(Text5, { children: text });
|
|
1474
|
+
let sepIdx = -1;
|
|
1475
|
+
for (let k = 0; k < rawLines.length; k++) {
|
|
1476
|
+
if (isTableSepRow(rawLines[k])) {
|
|
1477
|
+
sepIdx = k;
|
|
1478
|
+
break;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
if (sepIdx === -1) return /* @__PURE__ */ jsx4(Text5, { children: text });
|
|
1482
|
+
const headerText = rawLines.slice(0, sepIdx).join("");
|
|
1483
|
+
const headerCells = parseTableCells(headerText);
|
|
1484
|
+
const alignments = parseAlignments(rawLines[sepIdx]);
|
|
1485
|
+
const dataRows = rawLines.slice(sepIdx + 1).map(parseTableCells);
|
|
1486
|
+
const colCount = headerCells.length;
|
|
1487
|
+
const colMaxWidths = headerCells.map((_, ci) => {
|
|
1488
|
+
let max = visualWidth(headerCells[ci] ?? "");
|
|
1489
|
+
for (const row of dataRows) {
|
|
1490
|
+
const w = visualWidth(row[ci] ?? "");
|
|
1491
|
+
if (w > max) max = w;
|
|
1492
|
+
}
|
|
1493
|
+
return Math.max(max, TABLE_MIN_COL_WIDTH);
|
|
1494
|
+
});
|
|
1495
|
+
const margin = 2;
|
|
1496
|
+
const totalMinWidth = colMaxWidths.reduce((s, w) => s + w + margin, 1);
|
|
1497
|
+
let colWidths;
|
|
1498
|
+
if (totalMinWidth <= TABLE_MAX_WIDTH) {
|
|
1499
|
+
colWidths = colMaxWidths;
|
|
1500
|
+
} else {
|
|
1501
|
+
const available = TABLE_MAX_WIDTH - 1 - margin * colCount;
|
|
1502
|
+
const sum = colMaxWidths.reduce((s, w) => s + w, 0);
|
|
1503
|
+
colWidths = colMaxWidths.map((w) => Math.max(TABLE_MIN_COL_WIDTH, Math.floor(w / sum * available)));
|
|
1504
|
+
}
|
|
1505
|
+
const H = "\u2500";
|
|
1506
|
+
const makeSep = (l, m, r) => l + colWidths.map((w) => H.repeat(w + margin)).join(m) + r;
|
|
1507
|
+
const topBorder = makeSep("\u250C", "\u252C", "\u2510");
|
|
1508
|
+
const midBorder = makeSep("\u251C", "\u253C", "\u2524");
|
|
1509
|
+
const botBorder = makeSep("\u2514", "\u2534", "\u2518");
|
|
1510
|
+
function rowLine(cells, keyBase) {
|
|
1511
|
+
return /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
1512
|
+
"\u2502",
|
|
1513
|
+
cells.map((cell, ci) => /* @__PURE__ */ jsxs4(Text5, { children: [
|
|
1514
|
+
" ",
|
|
1515
|
+
padToWidth(cell.slice(0, colWidths[ci] ?? TABLE_MIN_COL_WIDTH), colWidths[ci] ?? TABLE_MIN_COL_WIDTH, alignments[ci] ?? "left"),
|
|
1516
|
+
" ",
|
|
1517
|
+
"\u2502"
|
|
1518
|
+
] }, ci))
|
|
1519
|
+
] }, keyBase);
|
|
1520
|
+
}
|
|
1521
|
+
const rows = [
|
|
1522
|
+
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: topBorder }, "top"),
|
|
1523
|
+
rowLine(headerCells, "hdr"),
|
|
1524
|
+
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: midBorder }, "mid"),
|
|
1525
|
+
...dataRows.map((cells, ri) => rowLine(cells, `d${ri}`)),
|
|
1526
|
+
/* @__PURE__ */ jsx4(Text5, { color: "#888888", children: botBorder }, "bot")
|
|
1527
|
+
];
|
|
1528
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginTop: 1, children: rows });
|
|
1529
|
+
}
|
|
1530
|
+
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;
|
|
1531
|
+
function isEmojiCluster(text) {
|
|
1532
|
+
return EMOJI_CP_RE.test(text);
|
|
1533
|
+
}
|
|
1534
|
+
function splitEmojiClusters(text) {
|
|
1535
|
+
try {
|
|
1536
|
+
const segmenter = new Intl.Segmenter("en", {
|
|
1537
|
+
granularity: "grapheme"
|
|
1538
|
+
});
|
|
1539
|
+
const segments = [...segmenter.segment(text)];
|
|
1540
|
+
return segments.map((s) => ({
|
|
1541
|
+
text: s.segment,
|
|
1542
|
+
isEmoji: isEmojiCluster(s.segment)
|
|
1543
|
+
}));
|
|
1544
|
+
} catch {
|
|
1545
|
+
return [{ text, isEmoji: false }];
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
function renderBoldText(text, key) {
|
|
1549
|
+
const clusters = splitEmojiClusters(text);
|
|
1550
|
+
if (clusters.length === 1 && !clusters[0].isEmoji) {
|
|
1551
|
+
return /* @__PURE__ */ jsx4(Text5, { color: BOLD_COLOR, children: text }, key);
|
|
1552
|
+
}
|
|
1553
|
+
const groups = [];
|
|
1554
|
+
for (const c of clusters) {
|
|
1555
|
+
const last = groups[groups.length - 1];
|
|
1556
|
+
if (last && last.isEmoji === c.isEmoji) {
|
|
1557
|
+
last.text += c.text;
|
|
1558
|
+
} else {
|
|
1559
|
+
groups.push({ text: c.text, isEmoji: c.isEmoji });
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
return /* @__PURE__ */ jsx4(Text5, { children: groups.map(
|
|
1563
|
+
(g, i) => g.isEmoji ? g.text : /* @__PURE__ */ jsx4(Text5, { color: BOLD_COLOR, children: g.text }, i)
|
|
1564
|
+
) }, key);
|
|
1565
|
+
}
|
|
1304
1566
|
var CODE_COLOR = "#00BFFF";
|
|
1305
1567
|
var BOLD_COLOR = "#A855F7";
|
|
1306
1568
|
function HighlightedText({ children: text }) {
|
|
1307
|
-
const
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
1310
|
-
|
|
1311
|
-
|
|
1569
|
+
const codeBlockSegments = parseCodeBlocks(text);
|
|
1570
|
+
const tableSegments = [];
|
|
1571
|
+
for (const seg of codeBlockSegments) {
|
|
1572
|
+
if (seg.type === "code_block") {
|
|
1573
|
+
tableSegments.push(seg);
|
|
1574
|
+
} else {
|
|
1575
|
+
tableSegments.push(...parseTables(seg.text));
|
|
1576
|
+
}
|
|
1312
1577
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1578
|
+
const boldSegments = [];
|
|
1579
|
+
for (const seg of tableSegments) {
|
|
1580
|
+
if (seg.type === "code_block" || seg.type === "table") {
|
|
1581
|
+
boldSegments.push(seg);
|
|
1582
|
+
} else {
|
|
1583
|
+
boldSegments.push(...parseBoldPairs(seg.text));
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
const segments = parseCodePairs(boldSegments);
|
|
1587
|
+
const hasBlock = segments.some(
|
|
1588
|
+
(s) => s.type === "code_block" || s.type === "table"
|
|
1589
|
+
);
|
|
1590
|
+
if (!hasBlock) {
|
|
1591
|
+
const isSimple = segments.length === 1 && segments[0].type === "plain";
|
|
1592
|
+
if (isSimple) {
|
|
1593
|
+
return /* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: text });
|
|
1594
|
+
}
|
|
1595
|
+
return /* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: segments.map((seg, i) => {
|
|
1596
|
+
if (seg.type === "code") {
|
|
1597
|
+
return /* @__PURE__ */ jsx4(Text5, { color: CODE_COLOR, children: seg.text }, i);
|
|
1598
|
+
}
|
|
1599
|
+
if (seg.type === "bold") {
|
|
1600
|
+
return renderBoldText(seg.text, i);
|
|
1601
|
+
}
|
|
1602
|
+
return seg.text;
|
|
1603
|
+
}) });
|
|
1604
|
+
}
|
|
1605
|
+
const rendered = [];
|
|
1606
|
+
let inlineGroup = [];
|
|
1607
|
+
function flushInline(groupIdx) {
|
|
1608
|
+
if (inlineGroup.length === 0) return;
|
|
1609
|
+
const isSimpleInline = inlineGroup.length === 1 && inlineGroup[0].type === "plain";
|
|
1610
|
+
if (isSimpleInline) {
|
|
1611
|
+
rendered.push(
|
|
1612
|
+
/* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: inlineGroup[0].text }, groupIdx)
|
|
1613
|
+
);
|
|
1614
|
+
} else {
|
|
1615
|
+
rendered.push(
|
|
1616
|
+
/* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: inlineGroup.map((seg, j) => {
|
|
1617
|
+
if (seg.type === "code") {
|
|
1618
|
+
return /* @__PURE__ */ jsx4(Text5, { color: CODE_COLOR, children: seg.text }, j);
|
|
1619
|
+
}
|
|
1620
|
+
if (seg.type === "bold") {
|
|
1621
|
+
return renderBoldText(seg.text, j);
|
|
1622
|
+
}
|
|
1623
|
+
return seg.text;
|
|
1624
|
+
}) }, groupIdx)
|
|
1625
|
+
);
|
|
1316
1626
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1627
|
+
inlineGroup = [];
|
|
1628
|
+
}
|
|
1629
|
+
for (const seg of segments) {
|
|
1630
|
+
if (seg.type === "code_block") {
|
|
1631
|
+
flushInline(rendered.length);
|
|
1632
|
+
rendered.push(
|
|
1633
|
+
/* @__PURE__ */ jsx4(CodeBlockRenderer, { code: seg.text }, `b${rendered.length}`)
|
|
1634
|
+
);
|
|
1635
|
+
} else if (seg.type === "table") {
|
|
1636
|
+
flushInline(rendered.length);
|
|
1637
|
+
rendered.push(
|
|
1638
|
+
/* @__PURE__ */ jsx4(TableRenderer, { text: seg.text }, `t${rendered.length}`)
|
|
1639
|
+
);
|
|
1640
|
+
} else {
|
|
1641
|
+
inlineGroup.push(seg);
|
|
1319
1642
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1643
|
+
}
|
|
1644
|
+
flushInline(rendered.length);
|
|
1645
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: rendered });
|
|
1322
1646
|
}
|
|
1323
1647
|
|
|
1324
1648
|
// src/ui/AssistantMessage.tsx
|
|
1325
|
-
import { jsx as jsx5, jsxs as
|
|
1649
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1326
1650
|
function formatElapsed(ms) {
|
|
1327
1651
|
if (ms < 1e3) return `${ms}ms`;
|
|
1328
1652
|
const seconds = (ms / 1e3).toFixed(1);
|
|
@@ -1340,23 +1664,23 @@ function AssistantMessage({
|
|
|
1340
1664
|
if (!content && (!toolCalls || toolCalls.length === 0) && !isStreaming) {
|
|
1341
1665
|
return null;
|
|
1342
1666
|
}
|
|
1343
|
-
return /* @__PURE__ */
|
|
1344
|
-
/* @__PURE__ */
|
|
1345
|
-
/* @__PURE__ */ jsx5(
|
|
1346
|
-
/* @__PURE__ */
|
|
1667
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
|
|
1668
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", children: [
|
|
1669
|
+
/* @__PURE__ */ jsx5(Box5, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#ff00ff", children: "\u{1F916}" }) }),
|
|
1670
|
+
/* @__PURE__ */ jsxs5(Box5, { flexGrow: 1, flexDirection: "column", children: [
|
|
1347
1671
|
content && /* @__PURE__ */ jsx5(HighlightedText, { children: content }),
|
|
1348
1672
|
isStreaming && !content && /* @__PURE__ */ jsx5(Text6, { color: "#888888", children: "..." })
|
|
1349
1673
|
] })
|
|
1350
1674
|
] }),
|
|
1351
|
-
toolCalls && toolCalls.length > 0 && /* @__PURE__ */ jsx5(
|
|
1352
|
-
!isStreaming && (usage || elapsed !== void 0) && /* @__PURE__ */
|
|
1675
|
+
toolCalls && toolCalls.length > 0 && /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", children: toolCalls.map((tc, i) => /* @__PURE__ */ jsx5(ToolCallBlock, { call: tc }, tc.id ?? i)) }),
|
|
1676
|
+
!isStreaming && (usage || elapsed !== void 0) && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, marginLeft: 3, children: [
|
|
1353
1677
|
/* @__PURE__ */ jsx5(Text6, { color: "#555555", children: "\u2500".repeat(36) }),
|
|
1354
|
-
/* @__PURE__ */
|
|
1355
|
-
cost !== void 0 && cost > 0 && /* @__PURE__ */
|
|
1678
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 2, children: [
|
|
1679
|
+
cost !== void 0 && cost > 0 && /* @__PURE__ */ jsxs5(Text6, { color: "yellow", children: [
|
|
1356
1680
|
"\u{1F4B0} \u672C\u6B21 ",
|
|
1357
1681
|
formatMoney(cost)
|
|
1358
1682
|
] }),
|
|
1359
|
-
elapsed !== void 0 && /* @__PURE__ */
|
|
1683
|
+
elapsed !== void 0 && /* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
|
|
1360
1684
|
"\u{1F550} ",
|
|
1361
1685
|
formatElapsed(elapsed)
|
|
1362
1686
|
] }),
|
|
@@ -1367,8 +1691,8 @@ function AssistantMessage({
|
|
|
1367
1691
|
}
|
|
1368
1692
|
|
|
1369
1693
|
// src/ui/DiffPreview.tsx
|
|
1370
|
-
import { Box as
|
|
1371
|
-
import { jsx as jsx6, jsxs as
|
|
1694
|
+
import { Box as Box6, Text as Text7 } from "ink";
|
|
1695
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1372
1696
|
function DiffPreview({ diff }) {
|
|
1373
1697
|
const { patch, additions, deletions, existedBefore, filePath } = diff;
|
|
1374
1698
|
if (!patch || patch.length === 0) {
|
|
@@ -1376,15 +1700,15 @@ function DiffPreview({ diff }) {
|
|
|
1376
1700
|
}
|
|
1377
1701
|
const lines = patch.split("\n");
|
|
1378
1702
|
const fileName = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
|
|
1379
|
-
return /* @__PURE__ */
|
|
1380
|
-
/* @__PURE__ */
|
|
1381
|
-
/* @__PURE__ */
|
|
1703
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, children: [
|
|
1704
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "row", gap: 1, children: [
|
|
1705
|
+
/* @__PURE__ */ jsxs6(Text7, { bold: true, color: "#00ffff", children: [
|
|
1382
1706
|
"\u{1F4DD} ",
|
|
1383
1707
|
existedBefore ? "\u4FEE\u6539" : "\u65B0\u5EFA",
|
|
1384
1708
|
":"
|
|
1385
1709
|
] }),
|
|
1386
1710
|
/* @__PURE__ */ jsx6(Text7, { bold: true, children: fileName }),
|
|
1387
|
-
/* @__PURE__ */
|
|
1711
|
+
/* @__PURE__ */ jsxs6(Text7, { color: "#555555", children: [
|
|
1388
1712
|
"(+",
|
|
1389
1713
|
additions,
|
|
1390
1714
|
" -",
|
|
@@ -1392,7 +1716,7 @@ function DiffPreview({ diff }) {
|
|
|
1392
1716
|
")"
|
|
1393
1717
|
] })
|
|
1394
1718
|
] }),
|
|
1395
|
-
/* @__PURE__ */ jsx6(
|
|
1719
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", marginLeft: 2, children: lines.filter((line) => !line.startsWith("---") && !line.startsWith("+++")).map((line, i) => /* @__PURE__ */ jsx6(DiffLine, { line }, i)) })
|
|
1396
1720
|
] });
|
|
1397
1721
|
}
|
|
1398
1722
|
function DiffLine({ line }) {
|
|
@@ -1412,8 +1736,8 @@ function DiffLine({ line }) {
|
|
|
1412
1736
|
}
|
|
1413
1737
|
|
|
1414
1738
|
// src/ui/SkillSelector.tsx
|
|
1415
|
-
import { Box as
|
|
1416
|
-
import { jsx as jsx7, jsxs as
|
|
1739
|
+
import { Box as Box7, Text as Text8 } from "ink";
|
|
1740
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1417
1741
|
var HIGHLIGHT_COLOR = "#00bfff";
|
|
1418
1742
|
function SkillSelector({ skills, input, selectedIndex }) {
|
|
1419
1743
|
const match = input.match(/(?:^|\s)\/([^/]*)$/);
|
|
@@ -1423,19 +1747,19 @@ function SkillSelector({ skills, input, selectedIndex }) {
|
|
|
1423
1747
|
const matched = !query && input.startsWith("/") ? skills.slice(0, 3) : skills.filter((s) => s.name.toLowerCase().includes(query)).slice(0, 3);
|
|
1424
1748
|
if (query && matched.some((s) => s.name.toLowerCase() === query)) return null;
|
|
1425
1749
|
if (matched.length === 0) return null;
|
|
1426
|
-
return /* @__PURE__ */
|
|
1750
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
|
|
1427
1751
|
/* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
|
|
1428
|
-
matched.map((skill, i) => /* @__PURE__ */ jsx7(
|
|
1752
|
+
matched.map((skill, i) => /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
|
|
1429
1753
|
i === selectedIndex ? " \u203A " : " ",
|
|
1430
1754
|
skill.name
|
|
1431
1755
|
] }) }, skill.name)),
|
|
1432
|
-
/* @__PURE__ */ jsx7(
|
|
1756
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
|
|
1433
1757
|
] });
|
|
1434
1758
|
}
|
|
1435
1759
|
|
|
1436
1760
|
// src/ui/FileSelector.tsx
|
|
1437
|
-
import { Box as
|
|
1438
|
-
import { jsx as jsx8, jsxs as
|
|
1761
|
+
import { Box as Box8, Text as Text9 } from "ink";
|
|
1762
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1439
1763
|
var HIGHLIGHT_COLOR2 = "#00ff41";
|
|
1440
1764
|
function FileSelector({ files, input, selectedIndex }) {
|
|
1441
1765
|
const match = input.match(/(?:^|\s)@([^@]*)$/);
|
|
@@ -1445,13 +1769,13 @@ function FileSelector({ files, input, selectedIndex }) {
|
|
|
1445
1769
|
const matched = !query && input.startsWith("@") ? files.slice(0, 5) : files.filter((f) => f.toLowerCase().includes(query)).slice(0, 5);
|
|
1446
1770
|
if (query && matched.some((f) => f.toLowerCase() === query)) return null;
|
|
1447
1771
|
if (matched.length === 0) return null;
|
|
1448
|
-
return /* @__PURE__ */
|
|
1772
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
|
|
1449
1773
|
/* @__PURE__ */ jsx8(Text9, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
|
|
1450
|
-
matched.map((file, i) => /* @__PURE__ */ jsx8(
|
|
1774
|
+
matched.map((file, i) => /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text9, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
|
|
1451
1775
|
i === selectedIndex ? " \u203A " : " ",
|
|
1452
1776
|
file
|
|
1453
1777
|
] }) }, file)),
|
|
1454
|
-
/* @__PURE__ */ jsx8(
|
|
1778
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
|
|
1455
1779
|
] });
|
|
1456
1780
|
}
|
|
1457
1781
|
|
|
@@ -1549,10 +1873,10 @@ var AlwaysAllowGate = class {
|
|
|
1549
1873
|
import Handlebars from "handlebars";
|
|
1550
1874
|
|
|
1551
1875
|
// src/agent/prompts/system-prompt.hbs
|
|
1552
|
-
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\
|
|
1876
|
+
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';
|
|
1553
1877
|
|
|
1554
1878
|
// src/agent/prompts/plan-prompt.hbs
|
|
1555
|
-
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\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";
|
|
1879
|
+
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";
|
|
1556
1880
|
|
|
1557
1881
|
// src/agent/system-prompt.ts
|
|
1558
1882
|
var compiledTemplate = Handlebars.compile(system_prompt_default);
|
|
@@ -1762,17 +2086,183 @@ var ToolRegistry = class {
|
|
|
1762
2086
|
}
|
|
1763
2087
|
};
|
|
1764
2088
|
|
|
2089
|
+
// src/checkpoint/git-checkpoint.ts
|
|
2090
|
+
import { execFile } from "child_process";
|
|
2091
|
+
import { promisify } from "util";
|
|
2092
|
+
var execFileAsync = promisify(execFile);
|
|
2093
|
+
var EXEC_OPTIONS = { windowsHide: true };
|
|
2094
|
+
async function isGitRepo(cwd) {
|
|
2095
|
+
try {
|
|
2096
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], { cwd, ...EXEC_OPTIONS });
|
|
2097
|
+
return true;
|
|
2098
|
+
} catch {
|
|
2099
|
+
return false;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
async function hasCommits(cwd) {
|
|
2103
|
+
try {
|
|
2104
|
+
await execFileAsync("git", ["rev-parse", "--verify", "HEAD"], { cwd, ...EXEC_OPTIONS });
|
|
2105
|
+
return true;
|
|
2106
|
+
} catch {
|
|
2107
|
+
return false;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
async function hasWorkingChanges(cwd) {
|
|
2111
|
+
const out = await execFileAsync("git", ["status", "--porcelain"], { cwd, ...EXEC_OPTIONS });
|
|
2112
|
+
return out.stdout.trim().length > 0;
|
|
2113
|
+
}
|
|
2114
|
+
async function git(args, cwd) {
|
|
2115
|
+
try {
|
|
2116
|
+
const { stdout } = await execFileAsync("git", args, { cwd, ...EXEC_OPTIONS });
|
|
2117
|
+
return stdout;
|
|
2118
|
+
} catch (err) {
|
|
2119
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2120
|
+
throw new Error(`git ${args.join(" ")} \u5931\u8D25: ${msg}`);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
async function listStashShas(cwd) {
|
|
2124
|
+
const out = await git(["stash", "list", "--format=%H"], cwd);
|
|
2125
|
+
return out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
2126
|
+
}
|
|
2127
|
+
async function createCheckpoint(cwd) {
|
|
2128
|
+
const timestamp = Date.now();
|
|
2129
|
+
const inRepo = await isGitRepo(cwd);
|
|
2130
|
+
if (!inRepo) return { stashSha: "", timestamp, cwd, isGitRepo: false };
|
|
2131
|
+
if (!await hasCommits(cwd)) return { stashSha: "", timestamp, cwd, isGitRepo: true };
|
|
2132
|
+
if (!await hasWorkingChanges(cwd)) return { stashSha: "", timestamp, cwd, isGitRepo: true };
|
|
2133
|
+
const beforeShas = await listStashShas(cwd);
|
|
2134
|
+
await git(["stash", "push", "-m", `dskcode-cp-${timestamp}`, "-u"], cwd);
|
|
2135
|
+
const newShas = await listStashShas(cwd);
|
|
2136
|
+
if (newShas.length === 0) throw new Error("git stash push \u672A\u80FD\u521B\u5EFA stash entry");
|
|
2137
|
+
const newSha = newShas.find((s) => !beforeShas.includes(s)) ?? newShas[0];
|
|
2138
|
+
await git(["stash", "apply", newSha], cwd);
|
|
2139
|
+
return { stashSha: newSha, timestamp, cwd, isGitRepo: true };
|
|
2140
|
+
}
|
|
2141
|
+
async function restoreCheckpointForce(checkpoint) {
|
|
2142
|
+
if (!checkpoint.isGitRepo) throw new Error("\u975E git \u4ED3\u5E93\uFF0C\u65E0\u6CD5\u6062\u590D\u6587\u4EF6\u72B6\u6001");
|
|
2143
|
+
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");
|
|
2144
|
+
const { cwd, stashSha } = checkpoint;
|
|
2145
|
+
const currentShas = await listStashShas(cwd);
|
|
2146
|
+
if (!currentShas.includes(stashSha)) {
|
|
2147
|
+
throw new Error("\u68C0\u67E5\u70B9\u5DF2\u5931\u6548\uFF08stash entry \u5DF2\u88AB\u6D88\u8D39\u6216 GC\uFF09\uFF0C\u65E0\u6CD5\u6062\u590D");
|
|
2148
|
+
}
|
|
2149
|
+
await git(["checkout", "--", "."], cwd);
|
|
2150
|
+
await git(["clean", "-fd"], cwd);
|
|
2151
|
+
await git(["stash", "apply", stashSha], cwd);
|
|
2152
|
+
const refIndex = currentShas.indexOf(stashSha);
|
|
2153
|
+
if (refIndex >= 0) await git(["stash", "drop", `stash@{${refIndex}}`], cwd);
|
|
2154
|
+
}
|
|
2155
|
+
async function restoreToClean(cwd) {
|
|
2156
|
+
const inRepo = await isGitRepo(cwd);
|
|
2157
|
+
if (!inRepo) throw new Error("\u975E git \u4ED3\u5E93\uFF0C\u65E0\u6CD5\u6062\u590D\u6587\u4EF6\u72B6\u6001");
|
|
2158
|
+
if (!await hasCommits(cwd)) throw new Error("\u4ED3\u5E93\u65E0 commit\uFF0C\u65E0\u6CD5\u6062\u590D");
|
|
2159
|
+
await git(["checkout", "--", "."], cwd);
|
|
2160
|
+
await git(["clean", "-fd"], cwd);
|
|
2161
|
+
}
|
|
2162
|
+
async function discardCheckpoint(checkpoint) {
|
|
2163
|
+
if (!checkpoint.isGitRepo || !checkpoint.stashSha) return;
|
|
2164
|
+
const { cwd, stashSha } = checkpoint;
|
|
2165
|
+
const shas = await listStashShas(cwd);
|
|
2166
|
+
const idx = shas.indexOf(stashSha);
|
|
2167
|
+
if (idx < 0) return;
|
|
2168
|
+
try {
|
|
2169
|
+
await git(["stash", "drop", `stash@{${idx}}`], cwd);
|
|
2170
|
+
} catch {
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
// src/session-store/session-store.ts
|
|
2175
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3, readdir as readdir2, unlink, rename } from "fs/promises";
|
|
2176
|
+
import { join as join4 } from "path";
|
|
2177
|
+
import { randomUUID } from "crypto";
|
|
2178
|
+
function defaultSessionsDir() {
|
|
2179
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
2180
|
+
return join4(home, ".dskcode", "sessions");
|
|
2181
|
+
}
|
|
2182
|
+
var SessionStore = class {
|
|
2183
|
+
#dir;
|
|
2184
|
+
constructor(dir) {
|
|
2185
|
+
this.#dir = dir ?? defaultSessionsDir();
|
|
2186
|
+
}
|
|
2187
|
+
get dir() {
|
|
2188
|
+
return this.#dir;
|
|
2189
|
+
}
|
|
2190
|
+
async save(session) {
|
|
2191
|
+
await mkdir4(this.#dir, { recursive: true });
|
|
2192
|
+
const finalPath = join4(this.#dir, `${session.id}.json`);
|
|
2193
|
+
const tmpPath = join4(this.#dir, `.${session.id}.json.tmp`);
|
|
2194
|
+
await writeFile3(tmpPath, JSON.stringify(session, null, 2), "utf-8");
|
|
2195
|
+
await rename(tmpPath, finalPath);
|
|
2196
|
+
}
|
|
2197
|
+
async load(id) {
|
|
2198
|
+
const path = join4(this.#dir, `${id}.json`);
|
|
2199
|
+
try {
|
|
2200
|
+
const content = await readFile4(path, "utf-8");
|
|
2201
|
+
return JSON.parse(content);
|
|
2202
|
+
} catch (err) {
|
|
2203
|
+
if (isENOENT(err)) return null;
|
|
2204
|
+
throw err;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
async list() {
|
|
2208
|
+
let files;
|
|
2209
|
+
try {
|
|
2210
|
+
files = await readdir2(this.#dir);
|
|
2211
|
+
} catch (err) {
|
|
2212
|
+
if (isENOENT(err)) return [];
|
|
2213
|
+
throw err;
|
|
2214
|
+
}
|
|
2215
|
+
const results = [];
|
|
2216
|
+
for (const file of files) {
|
|
2217
|
+
if (!file.endsWith(".json") || file.startsWith(".")) continue;
|
|
2218
|
+
try {
|
|
2219
|
+
const content = await readFile4(join4(this.#dir, file), "utf-8");
|
|
2220
|
+
const s = JSON.parse(content);
|
|
2221
|
+
results.push({
|
|
2222
|
+
id: s.id,
|
|
2223
|
+
title: s.title || "\uFF08\u65E0\u6807\u9898\uFF09",
|
|
2224
|
+
updatedAt: s.updatedAt,
|
|
2225
|
+
cwd: s.cwd,
|
|
2226
|
+
messageCount: s.messages?.length ?? 0
|
|
2227
|
+
});
|
|
2228
|
+
} catch {
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
return results.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
2232
|
+
}
|
|
2233
|
+
async delete(id) {
|
|
2234
|
+
const path = join4(this.#dir, `${id}.json`);
|
|
2235
|
+
try {
|
|
2236
|
+
await unlink(path);
|
|
2237
|
+
} catch (err) {
|
|
2238
|
+
if (!isENOENT(err)) throw err;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
async exists(id) {
|
|
2242
|
+
return await this.load(id) !== null;
|
|
2243
|
+
}
|
|
2244
|
+
static newId() {
|
|
2245
|
+
return randomUUID();
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2248
|
+
function isENOENT(err) {
|
|
2249
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
2250
|
+
}
|
|
2251
|
+
|
|
1765
2252
|
// src/agent/index.ts
|
|
1766
|
-
var Session = class {
|
|
2253
|
+
var Session = class _Session {
|
|
1767
2254
|
#messages = [];
|
|
1768
2255
|
#provider;
|
|
1769
2256
|
#toolRegistry;
|
|
1770
2257
|
#costTracker;
|
|
1771
2258
|
#options;
|
|
1772
2259
|
#abortController = new AbortController();
|
|
1773
|
-
|
|
2260
|
+
#sessionId;
|
|
2261
|
+
#store;
|
|
2262
|
+
#createdAt;
|
|
2263
|
+
#persistTimer = null;
|
|
2264
|
+
#checkpoints = /* @__PURE__ */ new Map();
|
|
1774
2265
|
#stormRecords = [];
|
|
1775
|
-
/** 当前会话模式:code(代码模式)或 plan(计划模式) */
|
|
1776
2266
|
#mode = "code";
|
|
1777
2267
|
constructor(provider, tools = [], costTracker, options) {
|
|
1778
2268
|
this.#provider = provider;
|
|
@@ -1790,12 +2280,13 @@ var Session = class {
|
|
|
1790
2280
|
preserveRecentRounds: options?.preserveRecentRounds ?? 10,
|
|
1791
2281
|
projectContext: options?.projectContext,
|
|
1792
2282
|
gate: options?.gate ?? new AlwaysAllowGate(),
|
|
1793
|
-
writeRoots: options?.writeRoots ?? [options?.cwd ?? process.cwd()]
|
|
2283
|
+
writeRoots: options?.writeRoots ?? [options?.cwd ?? process.cwd()],
|
|
2284
|
+
enableCheckpoint: options?.enableCheckpoint ?? true
|
|
1794
2285
|
};
|
|
2286
|
+
this.#sessionId = options?.sessionId ?? SessionStore.newId();
|
|
2287
|
+
this.#store = options?.store === false ? null : options?.store ?? new SessionStore();
|
|
2288
|
+
this.#createdAt = Date.now();
|
|
1795
2289
|
}
|
|
1796
|
-
// -------------------------------------------------------------------------
|
|
1797
|
-
// 公共只读属性
|
|
1798
|
-
// -------------------------------------------------------------------------
|
|
1799
2290
|
get messages() {
|
|
1800
2291
|
return this.#messages;
|
|
1801
2292
|
}
|
|
@@ -1808,36 +2299,35 @@ var Session = class {
|
|
|
1808
2299
|
get model() {
|
|
1809
2300
|
return this.#provider.model();
|
|
1810
2301
|
}
|
|
1811
|
-
/** 获取工具注册表(只读视图) */
|
|
1812
2302
|
get toolRegistry() {
|
|
1813
2303
|
return this.#toolRegistry;
|
|
1814
2304
|
}
|
|
1815
|
-
/** 获取当前会话模式 */
|
|
1816
2305
|
get mode() {
|
|
1817
2306
|
return this.#mode;
|
|
1818
2307
|
}
|
|
1819
|
-
|
|
2308
|
+
get id() {
|
|
2309
|
+
return this.#sessionId;
|
|
2310
|
+
}
|
|
2311
|
+
get store() {
|
|
2312
|
+
return this.#store;
|
|
2313
|
+
}
|
|
2314
|
+
get createdAt() {
|
|
2315
|
+
return this.#createdAt;
|
|
2316
|
+
}
|
|
1820
2317
|
setMode(mode) {
|
|
1821
2318
|
this.#mode = mode;
|
|
1822
2319
|
return this.#mode;
|
|
1823
2320
|
}
|
|
1824
|
-
// -------------------------------------------------------------------------
|
|
1825
|
-
// 流式对话 — Agent 主循环
|
|
1826
|
-
// -------------------------------------------------------------------------
|
|
1827
|
-
/**
|
|
1828
|
-
* 执行一轮用户对话,以 AsyncGenerator 形式逐步 yield 事件。
|
|
1829
|
-
*
|
|
1830
|
-
* 主循环流程:
|
|
1831
|
-
* 1. 追加用户消息
|
|
1832
|
-
* 2. 进入 Agent 循环(最多 maxToolRounds 轮)
|
|
1833
|
-
* a. 构建消息 → 裁剪 → 调用 Provider 流式接口
|
|
1834
|
-
* b. 解析响应:文本增量、工具调用、使用量
|
|
1835
|
-
* c. 如果有工具调用 → 执行工具 → 追加结果 → 继续循环
|
|
1836
|
-
* d. 如果没有工具调用 → 退出循环
|
|
1837
|
-
* 3. yield done 事件
|
|
1838
|
-
*/
|
|
1839
2321
|
async *chat(userInput, opts) {
|
|
1840
2322
|
this.#messages.push({ role: "user", content: userInput });
|
|
2323
|
+
const userMsgIndex = this.#messages.length - 1;
|
|
2324
|
+
if (this.#options.enableCheckpoint) {
|
|
2325
|
+
try {
|
|
2326
|
+
const checkpoint = await createCheckpoint(this.#options.cwd);
|
|
2327
|
+
this.#checkpoints.set(userMsgIndex, checkpoint);
|
|
2328
|
+
} catch {
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
1841
2331
|
const startTime = Date.now();
|
|
1842
2332
|
let toolRounds = 0;
|
|
1843
2333
|
try {
|
|
@@ -1846,7 +2336,6 @@ var Session = class {
|
|
|
1846
2336
|
const [trimmed] = trimMessages(
|
|
1847
2337
|
[...this.#messages],
|
|
1848
2338
|
{
|
|
1849
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1850
2339
|
model: this.#provider.model(),
|
|
1851
2340
|
reservedForOutput: this.#options.reservedForOutput,
|
|
1852
2341
|
systemPrompt,
|
|
@@ -1872,28 +2361,17 @@ var Session = class {
|
|
|
1872
2361
|
accumulatedText += chunk.content;
|
|
1873
2362
|
yield { type: "text_delta", content: chunk.content };
|
|
1874
2363
|
}
|
|
1875
|
-
if (chunk.toolCalls && chunk.toolCalls.length > 0)
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
if (chunk.usage) {
|
|
1879
|
-
lastUsage = chunk.usage;
|
|
1880
|
-
}
|
|
1881
|
-
if (chunk.finishReason) {
|
|
1882
|
-
_lastFinishReason = chunk.finishReason;
|
|
1883
|
-
}
|
|
2364
|
+
if (chunk.toolCalls && chunk.toolCalls.length > 0) lastToolCalls = chunk.toolCalls;
|
|
2365
|
+
if (chunk.usage) lastUsage = chunk.usage;
|
|
2366
|
+
if (chunk.finishReason) _lastFinishReason = chunk.finishReason;
|
|
1884
2367
|
}
|
|
1885
2368
|
if (lastUsage) {
|
|
1886
2369
|
const modelId = this.#provider.model();
|
|
1887
2370
|
this.#costTracker.record(lastUsage, modelId);
|
|
1888
2371
|
yield { type: "usage", usage: lastUsage, model: modelId };
|
|
1889
2372
|
}
|
|
1890
|
-
const assistantMsg = {
|
|
1891
|
-
|
|
1892
|
-
content: accumulatedText
|
|
1893
|
-
};
|
|
1894
|
-
if (lastToolCalls && lastToolCalls.length > 0) {
|
|
1895
|
-
assistantMsg.toolCalls = lastToolCalls;
|
|
1896
|
-
}
|
|
2373
|
+
const assistantMsg = { role: "assistant", content: accumulatedText };
|
|
2374
|
+
if (lastToolCalls && lastToolCalls.length > 0) assistantMsg.toolCalls = lastToolCalls;
|
|
1897
2375
|
this.#messages.push(assistantMsg);
|
|
1898
2376
|
if (lastToolCalls && lastToolCalls.length > 0) {
|
|
1899
2377
|
yield { type: "tool_calls", calls: lastToolCalls };
|
|
@@ -1912,11 +2390,9 @@ var Session = class {
|
|
|
1912
2390
|
for (const item of results.items) {
|
|
1913
2391
|
yield { type: "tool_result", name: item.name, result: item.result };
|
|
1914
2392
|
let toolContent = item.result.data;
|
|
1915
|
-
if (item.result.diff && item.result.diff.patch)
|
|
1916
|
-
toolContent += `
|
|
2393
|
+
if (item.result.diff && item.result.diff.patch) toolContent += `
|
|
1917
2394
|
|
|
1918
2395
|
${item.result.diff.patch}`;
|
|
1919
|
-
}
|
|
1920
2396
|
this.#messages.push({
|
|
1921
2397
|
role: "tool",
|
|
1922
2398
|
content: toolContent,
|
|
@@ -1930,31 +2406,15 @@ ${item.result.diff.patch}`;
|
|
|
1930
2406
|
break;
|
|
1931
2407
|
}
|
|
1932
2408
|
} catch (err) {
|
|
1933
|
-
if (err instanceof DOMException && err.name === "AbortError")
|
|
1934
|
-
|
|
1935
|
-
}
|
|
1936
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
1937
|
-
return;
|
|
1938
|
-
}
|
|
1939
|
-
yield {
|
|
1940
|
-
type: "error",
|
|
1941
|
-
error: err instanceof Error ? err : new Error(String(err))
|
|
1942
|
-
};
|
|
2409
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
2410
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
2411
|
+
yield { type: "error", error: err instanceof Error ? err : new Error(String(err)) };
|
|
1943
2412
|
return;
|
|
1944
2413
|
}
|
|
1945
2414
|
const elapsed = Date.now() - startTime;
|
|
2415
|
+
void this.#persist();
|
|
1946
2416
|
yield { type: "done", elapsed };
|
|
1947
2417
|
}
|
|
1948
|
-
// -------------------------------------------------------------------------
|
|
1949
|
-
// 工具执行 — 批量、并行/串行、Gate、风暴检测
|
|
1950
|
-
// -------------------------------------------------------------------------
|
|
1951
|
-
/**
|
|
1952
|
-
* 执行一批工具调用。
|
|
1953
|
-
*
|
|
1954
|
-
* 并行策略:
|
|
1955
|
-
* - 如果这批工具全部是 ReadOnly 的,并行执行(最多 8 并发)
|
|
1956
|
-
* - 否则按顺序串行执行,保证写/读顺序
|
|
1957
|
-
*/
|
|
1958
2418
|
async #executeBatch(calls) {
|
|
1959
2419
|
const toolCtx = {
|
|
1960
2420
|
cwd: this.#options.cwd,
|
|
@@ -1989,9 +2449,6 @@ ${item.result.diff.patch}`;
|
|
|
1989
2449
|
}
|
|
1990
2450
|
return { items, records };
|
|
1991
2451
|
}
|
|
1992
|
-
/**
|
|
1993
|
-
* 执行单个工具调用,包含 Gate 检查和预览。
|
|
1994
|
-
*/
|
|
1995
2452
|
async #executeOne(tc, ctx) {
|
|
1996
2453
|
const toolName = tc.name;
|
|
1997
2454
|
const timestamp = Date.now();
|
|
@@ -2030,12 +2487,7 @@ ${item.result.diff.patch}`;
|
|
|
2030
2487
|
const result = await tool.execute(toolArgs, ctx);
|
|
2031
2488
|
return {
|
|
2032
2489
|
item: { name: toolName, callId: tc.id, result },
|
|
2033
|
-
record: {
|
|
2034
|
-
name: toolName,
|
|
2035
|
-
success: result.success,
|
|
2036
|
-
error: result.error,
|
|
2037
|
-
timestamp
|
|
2038
|
-
}
|
|
2490
|
+
record: { name: toolName, success: result.success, error: result.error, timestamp }
|
|
2039
2491
|
};
|
|
2040
2492
|
} catch (err) {
|
|
2041
2493
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -2046,46 +2498,172 @@ ${item.result.diff.patch}`;
|
|
|
2046
2498
|
};
|
|
2047
2499
|
}
|
|
2048
2500
|
}
|
|
2049
|
-
// -------------------------------------------------------------------------
|
|
2050
|
-
// 风暴检测 — 同一工具同一错误连续 3 次 → 强制换策略
|
|
2051
|
-
// -------------------------------------------------------------------------
|
|
2052
|
-
/**
|
|
2053
|
-
* 连续 3 次同一工具同一错误 → 触发风暴中断。
|
|
2054
|
-
*/
|
|
2055
2501
|
#checkStormBreak(currentCalls) {
|
|
2056
2502
|
if (this.#stormRecords.length < 3) return false;
|
|
2057
2503
|
const recentErrors = this.#stormRecords.slice(-3);
|
|
2058
2504
|
if (recentErrors.length < 3) return false;
|
|
2059
2505
|
const first = recentErrors[0];
|
|
2060
|
-
const allSame = recentErrors.every(
|
|
2061
|
-
(r) => r.name === first.name && r.error === first.error && !r.success
|
|
2062
|
-
);
|
|
2506
|
+
const allSame = recentErrors.every((r) => r.name === first.name && r.error === first.error && !r.success);
|
|
2063
2507
|
if (!allSame) return false;
|
|
2064
2508
|
return currentCalls.some((tc) => tc.name === first.name);
|
|
2065
2509
|
}
|
|
2066
|
-
// -------------------------------------------------------------------------
|
|
2067
|
-
// 会话管理
|
|
2068
|
-
// -------------------------------------------------------------------------
|
|
2069
|
-
/** 取消正在进行的流式请求 */
|
|
2070
2510
|
abort() {
|
|
2071
2511
|
this.#abortController.abort();
|
|
2512
|
+
if (this.#persistTimer) {
|
|
2513
|
+
clearTimeout(this.#persistTimer);
|
|
2514
|
+
this.#persistTimer = null;
|
|
2515
|
+
}
|
|
2072
2516
|
}
|
|
2073
|
-
/** 重置会话历史(保留 provider/tools 配置,重置成本追踪) */
|
|
2074
2517
|
reset() {
|
|
2075
2518
|
this.#messages.length = 0;
|
|
2076
2519
|
this.#costTracker.resetSession();
|
|
2077
2520
|
this.#stormRecords = [];
|
|
2521
|
+
this.#checkpoints.clear();
|
|
2522
|
+
}
|
|
2523
|
+
// -------------------------------------------------------------------------
|
|
2524
|
+
// 持久化与恢复
|
|
2525
|
+
// -------------------------------------------------------------------------
|
|
2526
|
+
async persistNow() {
|
|
2527
|
+
if (this.#persistTimer) {
|
|
2528
|
+
clearTimeout(this.#persistTimer);
|
|
2529
|
+
this.#persistTimer = null;
|
|
2530
|
+
}
|
|
2531
|
+
await this.#doPersist();
|
|
2532
|
+
}
|
|
2533
|
+
#persist() {
|
|
2534
|
+
if (!this.#store) return;
|
|
2535
|
+
if (this.#persistTimer) {
|
|
2536
|
+
this.#persistTimer.refresh();
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2539
|
+
this.#persistTimer = setTimeout(() => {
|
|
2540
|
+
this.#persistTimer = null;
|
|
2541
|
+
void this.#doPersist();
|
|
2542
|
+
}, 500);
|
|
2543
|
+
this.#persistTimer.unref();
|
|
2544
|
+
}
|
|
2545
|
+
async #doPersist() {
|
|
2546
|
+
if (!this.#store) return;
|
|
2547
|
+
const stored = {
|
|
2548
|
+
id: this.#sessionId,
|
|
2549
|
+
title: this.#deriveTitle(),
|
|
2550
|
+
createdAt: this.#createdAt,
|
|
2551
|
+
updatedAt: Date.now(),
|
|
2552
|
+
cwd: this.#options.cwd,
|
|
2553
|
+
model: this.#provider.model(),
|
|
2554
|
+
messages: this.#serializeMessages(),
|
|
2555
|
+
totalCost: this.#costTracker.sessionTotalCost
|
|
2556
|
+
};
|
|
2557
|
+
try {
|
|
2558
|
+
await this.#store.save(stored);
|
|
2559
|
+
} catch (err) {
|
|
2560
|
+
console.error("[Session] \u6301\u4E45\u5316\u5931\u8D25:", err);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
#deriveTitle() {
|
|
2564
|
+
for (const m of this.#messages) {
|
|
2565
|
+
if (m.role === "user" && m.content.trim()) return m.content.trim().slice(0, 40);
|
|
2566
|
+
}
|
|
2567
|
+
return "\u65B0\u4F1A\u8BDD";
|
|
2568
|
+
}
|
|
2569
|
+
#serializeMessages() {
|
|
2570
|
+
return this.#messages.map((msg, idx) => {
|
|
2571
|
+
const checkpoint = this.#checkpoints.get(idx);
|
|
2572
|
+
if (msg.role === "user" && checkpoint) return { ...msg, checkpoint };
|
|
2573
|
+
return { ...msg };
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
static async resume(id, provider, tools = [], costTracker, options) {
|
|
2577
|
+
const store = options?.store === false ? null : options?.store ?? new SessionStore();
|
|
2578
|
+
if (!store) throw new Error("resume \u9700\u8981\u542F\u7528\u6301\u4E45\u5316\uFF08options.store \u4E0D\u80FD\u4E3A false\uFF09");
|
|
2579
|
+
const stored = await store.load(id);
|
|
2580
|
+
if (!stored) throw new Error(`\u4F1A\u8BDD ${id} \u4E0D\u5B58\u5728`);
|
|
2581
|
+
const session = new _Session(provider, tools, costTracker, { ...options, sessionId: id, store });
|
|
2582
|
+
for (const m of stored.messages) {
|
|
2583
|
+
session.#messages.push({
|
|
2584
|
+
role: m.role,
|
|
2585
|
+
content: m.content,
|
|
2586
|
+
toolCallId: m.toolCallId,
|
|
2587
|
+
name: m.name,
|
|
2588
|
+
toolCalls: m.toolCalls
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
for (let i = 0; i < stored.messages.length; i++) {
|
|
2592
|
+
const cp2 = stored.messages[i]?.checkpoint;
|
|
2593
|
+
if (cp2) session.#checkpoints.set(i, cp2);
|
|
2594
|
+
}
|
|
2595
|
+
session.#createdAt = stored.createdAt;
|
|
2596
|
+
return session;
|
|
2597
|
+
}
|
|
2598
|
+
// -------------------------------------------------------------------------
|
|
2599
|
+
// 检查点与 Rewind
|
|
2600
|
+
// -------------------------------------------------------------------------
|
|
2601
|
+
listCheckpoints() {
|
|
2602
|
+
const result = [];
|
|
2603
|
+
for (const [index, checkpoint] of this.#checkpoints) {
|
|
2604
|
+
const msg = this.#messages[index];
|
|
2605
|
+
if (!msg || msg.role !== "user") continue;
|
|
2606
|
+
result.push({ index, preview: msg.content.slice(0, 80), timestamp: checkpoint.timestamp, isGitRepo: checkpoint.isGitRepo });
|
|
2607
|
+
}
|
|
2608
|
+
return result.sort((a, b) => a.index - b.index);
|
|
2609
|
+
}
|
|
2610
|
+
async rewind(targetIndex) {
|
|
2611
|
+
if (targetIndex < 0 || targetIndex >= this.#messages.length) {
|
|
2612
|
+
return { ok: false, error: `\u65E0\u6548\u7684\u6D88\u606F\u7D22\u5F15 ${targetIndex}` };
|
|
2613
|
+
}
|
|
2614
|
+
const target = this.#messages[targetIndex];
|
|
2615
|
+
if (!target || target.role !== "user") {
|
|
2616
|
+
return { ok: false, error: `\u7D22\u5F15 ${targetIndex} \u4E0D\u662F user \u6D88\u606F` };
|
|
2617
|
+
}
|
|
2618
|
+
const checkpoint = this.#checkpoints.get(targetIndex);
|
|
2619
|
+
if (!checkpoint) return { ok: false, error: "\u8BE5\u6D88\u606F\u6CA1\u6709\u68C0\u67E5\u70B9" };
|
|
2620
|
+
this.#messages.length = targetIndex + 1;
|
|
2621
|
+
const toDiscard = [];
|
|
2622
|
+
for (const [idx, cp2] of this.#checkpoints) {
|
|
2623
|
+
if (idx > targetIndex) {
|
|
2624
|
+
toDiscard.push(cp2);
|
|
2625
|
+
this.#checkpoints.delete(idx);
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
let fileRestored = false;
|
|
2629
|
+
if (checkpoint.isGitRepo) {
|
|
2630
|
+
try {
|
|
2631
|
+
if (checkpoint.stashSha) {
|
|
2632
|
+
await restoreCheckpointForce(checkpoint);
|
|
2633
|
+
} else {
|
|
2634
|
+
await restoreToClean(this.#options.cwd);
|
|
2635
|
+
}
|
|
2636
|
+
fileRestored = true;
|
|
2637
|
+
} catch (err) {
|
|
2638
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2639
|
+
return { ok: false, error: `\u5BF9\u8BDD\u5DF2\u622A\u65AD\u4F46\u6587\u4EF6\u6062\u590D\u5931\u8D25\uFF1A${msg}` };
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
this.#checkpoints.delete(targetIndex);
|
|
2643
|
+
for (const cp2 of toDiscard) {
|
|
2644
|
+
void discardCheckpoint(cp2);
|
|
2645
|
+
}
|
|
2646
|
+
this.#persist();
|
|
2647
|
+
return { ok: true, fileRestored };
|
|
2648
|
+
}
|
|
2649
|
+
hasCheckpoints() {
|
|
2650
|
+
return this.listCheckpoints().length > 0;
|
|
2651
|
+
}
|
|
2652
|
+
async delete() {
|
|
2653
|
+
if (this.#store) await this.#store.delete(this.#sessionId);
|
|
2654
|
+
for (const cp2 of this.#checkpoints.values()) {
|
|
2655
|
+
void discardCheckpoint(cp2);
|
|
2656
|
+
}
|
|
2657
|
+
this.#checkpoints.clear();
|
|
2078
2658
|
}
|
|
2079
2659
|
// -------------------------------------------------------------------------
|
|
2080
2660
|
// 内部方法
|
|
2081
2661
|
// -------------------------------------------------------------------------
|
|
2082
|
-
/** 构建系统提示词 */
|
|
2083
2662
|
#buildSystemPrompt() {
|
|
2084
2663
|
const enabledTools = this.#toolRegistry.list();
|
|
2085
2664
|
const toolDescs = enabledTools.map((t) => ({
|
|
2086
2665
|
name: t.name,
|
|
2087
2666
|
description: t.description,
|
|
2088
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2089
2667
|
parameters: t.parameters
|
|
2090
2668
|
}));
|
|
2091
2669
|
const opts = {
|
|
@@ -2095,25 +2673,14 @@ ${item.result.diff.patch}`;
|
|
|
2095
2673
|
projectContext: this.#options.projectContext ?? void 0,
|
|
2096
2674
|
cwd: this.#options.cwd
|
|
2097
2675
|
};
|
|
2098
|
-
if (this.#mode === "plan")
|
|
2099
|
-
return buildPlanSystemPrompt(opts);
|
|
2100
|
-
}
|
|
2676
|
+
if (this.#mode === "plan") return buildPlanSystemPrompt(opts);
|
|
2101
2677
|
return buildSystemPrompt(opts);
|
|
2102
2678
|
}
|
|
2103
|
-
/**
|
|
2104
|
-
* 将注册的工具转为 ToolDefinition 格式(预留给 function calling)。
|
|
2105
|
-
* 计划模式下只返回读工具,禁止非读工具暴露给 LLM。
|
|
2106
|
-
*/
|
|
2107
2679
|
#buildToolDefinitions() {
|
|
2108
2680
|
const tools = this.#mode === "plan" ? this.#toolRegistry.listReadTools() : this.#toolRegistry.list();
|
|
2109
2681
|
return tools.map((t) => ({
|
|
2110
2682
|
type: "function",
|
|
2111
|
-
function: {
|
|
2112
|
-
name: t.name,
|
|
2113
|
-
description: t.description,
|
|
2114
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2115
|
-
parameters: t.parameters
|
|
2116
|
-
}
|
|
2683
|
+
function: { name: t.name, description: t.description, parameters: t.parameters }
|
|
2117
2684
|
}));
|
|
2118
2685
|
}
|
|
2119
2686
|
};
|
|
@@ -2507,7 +3074,7 @@ function computeFileDiff(oldContent, newContent, filePath) {
|
|
|
2507
3074
|
}
|
|
2508
3075
|
|
|
2509
3076
|
// src/tool/eol.ts
|
|
2510
|
-
import { writeFile as
|
|
3077
|
+
import { writeFile as writeFile4 } from "fs/promises";
|
|
2511
3078
|
function detectEol(text) {
|
|
2512
3079
|
if (text.length === 0) return "\n";
|
|
2513
3080
|
const crlfIdx = text.indexOf("\r\n");
|
|
@@ -2538,11 +3105,11 @@ function normalizeEol(originalContent, newContent) {
|
|
|
2538
3105
|
}
|
|
2539
3106
|
async function writeFileWithEol(filePath, originalContent, newContent) {
|
|
2540
3107
|
const content = originalContent.length > 0 ? normalizeEol(originalContent, newContent) : newContent;
|
|
2541
|
-
await
|
|
3108
|
+
await writeFile4(filePath, content, "utf-8");
|
|
2542
3109
|
}
|
|
2543
3110
|
|
|
2544
3111
|
// src/tool/builtins/read-file.ts
|
|
2545
|
-
import { readFile as
|
|
3112
|
+
import { readFile as readFile5, stat } from "fs/promises";
|
|
2546
3113
|
import { open } from "fs/promises";
|
|
2547
3114
|
import { relative as relative2 } from "path";
|
|
2548
3115
|
async function checkBinary(filePath) {
|
|
@@ -2610,7 +3177,7 @@ var readFileTool = {
|
|
|
2610
3177
|
};
|
|
2611
3178
|
}
|
|
2612
3179
|
}
|
|
2613
|
-
const content = await
|
|
3180
|
+
const content = await readFile5(filePath, "utf-8");
|
|
2614
3181
|
const lines = content.split("\n");
|
|
2615
3182
|
if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
|
|
2616
3183
|
lines.pop();
|
|
@@ -2646,7 +3213,7 @@ var readFileTool = {
|
|
|
2646
3213
|
};
|
|
2647
3214
|
|
|
2648
3215
|
// src/tool/builtins/write-file.ts
|
|
2649
|
-
import { mkdir as
|
|
3216
|
+
import { mkdir as mkdir5, readFile as readFile6 } from "fs/promises";
|
|
2650
3217
|
import { dirname, relative as relative3, basename } from "path";
|
|
2651
3218
|
var writeFileTool = {
|
|
2652
3219
|
name: "write_file",
|
|
@@ -2685,11 +3252,11 @@ var writeFileTool = {
|
|
|
2685
3252
|
let oldContent = "";
|
|
2686
3253
|
let existedBefore = false;
|
|
2687
3254
|
try {
|
|
2688
|
-
oldContent = await
|
|
3255
|
+
oldContent = await readFile6(filePath, "utf-8");
|
|
2689
3256
|
existedBefore = true;
|
|
2690
3257
|
} catch {
|
|
2691
3258
|
}
|
|
2692
|
-
await
|
|
3259
|
+
await mkdir5(dirname(filePath), { recursive: true });
|
|
2693
3260
|
const content = args.content;
|
|
2694
3261
|
await writeFileWithEol(filePath, oldContent, content);
|
|
2695
3262
|
const diff = computeFileDiff(oldContent, content, filePath);
|
|
@@ -2718,7 +3285,7 @@ var writeFileTool = {
|
|
|
2718
3285
|
};
|
|
2719
3286
|
|
|
2720
3287
|
// src/tool/builtins/edit-file.ts
|
|
2721
|
-
import { readFile as
|
|
3288
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
2722
3289
|
import { basename as basename2 } from "path";
|
|
2723
3290
|
var editFileTool = {
|
|
2724
3291
|
name: "edit_file",
|
|
@@ -2761,7 +3328,7 @@ var editFileTool = {
|
|
|
2761
3328
|
}
|
|
2762
3329
|
}
|
|
2763
3330
|
try {
|
|
2764
|
-
const content = await
|
|
3331
|
+
const content = await readFile7(filePath, "utf-8");
|
|
2765
3332
|
const firstIndex = content.indexOf(args.old_text);
|
|
2766
3333
|
if (firstIndex === -1) {
|
|
2767
3334
|
return {
|
|
@@ -2809,7 +3376,7 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
|
|
|
2809
3376
|
};
|
|
2810
3377
|
|
|
2811
3378
|
// src/tool/builtins/multi-edit.ts
|
|
2812
|
-
import { readFile as
|
|
3379
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
2813
3380
|
import { basename as basename3 } from "path";
|
|
2814
3381
|
var multiEditTool = {
|
|
2815
3382
|
name: "multi_edit",
|
|
@@ -2855,7 +3422,7 @@ var multiEditTool = {
|
|
|
2855
3422
|
}
|
|
2856
3423
|
}
|
|
2857
3424
|
try {
|
|
2858
|
-
const originalContent = await
|
|
3425
|
+
const originalContent = await readFile8(filePath, "utf-8");
|
|
2859
3426
|
let currentContent = originalContent;
|
|
2860
3427
|
for (let idx = 0; idx < args.edits.length; idx++) {
|
|
2861
3428
|
const step = args.edits[idx];
|
|
@@ -2923,7 +3490,7 @@ var multiEditTool = {
|
|
|
2923
3490
|
};
|
|
2924
3491
|
|
|
2925
3492
|
// src/tool/builtins/delete-range.ts
|
|
2926
|
-
import { readFile as
|
|
3493
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
2927
3494
|
import { basename as basename4 } from "path";
|
|
2928
3495
|
function findUniqueLine(lines, anchor, label) {
|
|
2929
3496
|
const matches = [];
|
|
@@ -2986,7 +3553,7 @@ var deleteRangeTool = {
|
|
|
2986
3553
|
}
|
|
2987
3554
|
}
|
|
2988
3555
|
try {
|
|
2989
|
-
const content = await
|
|
3556
|
+
const content = await readFile9(filePath, "utf-8");
|
|
2990
3557
|
const lines = content.split("\n");
|
|
2991
3558
|
const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
|
|
2992
3559
|
if ("error" in startResult) {
|
|
@@ -3109,8 +3676,8 @@ ${truncateOutput(result.stderr)}`);
|
|
|
3109
3676
|
};
|
|
3110
3677
|
|
|
3111
3678
|
// src/tool/builtins/glob.ts
|
|
3112
|
-
import { readdir as
|
|
3113
|
-
import { join as
|
|
3679
|
+
import { readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
3680
|
+
import { join as join5, relative as relative4, isAbsolute as isAbsolute2 } from "path";
|
|
3114
3681
|
function globToRegex(pattern) {
|
|
3115
3682
|
let regexStr = pattern;
|
|
3116
3683
|
regexStr = regexStr.replace(/\*\*\//g, "<<GLOBSTAR_SLASH>>");
|
|
@@ -3127,7 +3694,7 @@ async function walkDir(dir, baseDir) {
|
|
|
3127
3694
|
const results = [];
|
|
3128
3695
|
let entries;
|
|
3129
3696
|
try {
|
|
3130
|
-
entries = await
|
|
3697
|
+
entries = await readdir3(dir, { withFileTypes: true });
|
|
3131
3698
|
} catch {
|
|
3132
3699
|
return results;
|
|
3133
3700
|
}
|
|
@@ -3135,7 +3702,7 @@ async function walkDir(dir, baseDir) {
|
|
|
3135
3702
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
3136
3703
|
continue;
|
|
3137
3704
|
}
|
|
3138
|
-
const fullPath =
|
|
3705
|
+
const fullPath = join5(dir, entry.name);
|
|
3139
3706
|
const relPath = relative4(baseDir, fullPath);
|
|
3140
3707
|
if (entry.isDirectory()) {
|
|
3141
3708
|
results.push(...await walkDir(fullPath, baseDir));
|
|
@@ -3168,7 +3735,7 @@ var globTool = {
|
|
|
3168
3735
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
3169
3736
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
3170
3737
|
}
|
|
3171
|
-
const searchDir = args.directory ? isAbsolute2(args.directory) ? args.directory :
|
|
3738
|
+
const searchDir = args.directory ? isAbsolute2(args.directory) ? args.directory : join5(ctx.cwd, args.directory) : ctx.cwd;
|
|
3172
3739
|
const regex = globToRegex(args.pattern);
|
|
3173
3740
|
try {
|
|
3174
3741
|
const dirStat = await stat2(searchDir);
|
|
@@ -3207,13 +3774,13 @@ var globTool = {
|
|
|
3207
3774
|
};
|
|
3208
3775
|
|
|
3209
3776
|
// src/tool/builtins/grep.ts
|
|
3210
|
-
import { readdir as
|
|
3211
|
-
import { join as
|
|
3777
|
+
import { readdir as readdir4, readFile as readFile10, stat as stat3 } from "fs/promises";
|
|
3778
|
+
import { join as join6, relative as relative5, isAbsolute as isAbsolute3 } from "path";
|
|
3212
3779
|
async function collectFiles(dir, extension, maxFiles = 200) {
|
|
3213
3780
|
const results = [];
|
|
3214
3781
|
let entries;
|
|
3215
3782
|
try {
|
|
3216
|
-
entries = await
|
|
3783
|
+
entries = await readdir4(dir, { withFileTypes: true });
|
|
3217
3784
|
} catch {
|
|
3218
3785
|
return results;
|
|
3219
3786
|
}
|
|
@@ -3222,7 +3789,7 @@ async function collectFiles(dir, extension, maxFiles = 200) {
|
|
|
3222
3789
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")) {
|
|
3223
3790
|
continue;
|
|
3224
3791
|
}
|
|
3225
|
-
const fullPath =
|
|
3792
|
+
const fullPath = join6(dir, entry.name);
|
|
3226
3793
|
if (entry.isDirectory()) {
|
|
3227
3794
|
results.push(...await collectFiles(fullPath, extension, maxFiles - results.length));
|
|
3228
3795
|
} else {
|
|
@@ -3269,7 +3836,7 @@ var grepTool = {
|
|
|
3269
3836
|
if (!args?.pattern || typeof args.pattern !== "string") {
|
|
3270
3837
|
return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
|
|
3271
3838
|
}
|
|
3272
|
-
const searchDir = args.directory ? isAbsolute3(args.directory) ? args.directory :
|
|
3839
|
+
const searchDir = args.directory ? isAbsolute3(args.directory) ? args.directory : join6(ctx.cwd, args.directory) : ctx.cwd;
|
|
3273
3840
|
const maxFiles = args.max_files ?? 200;
|
|
3274
3841
|
try {
|
|
3275
3842
|
const flags = args.case_sensitive ? "g" : "gi";
|
|
@@ -3282,7 +3849,7 @@ var grepTool = {
|
|
|
3282
3849
|
const matches = [];
|
|
3283
3850
|
for (const filePath of files) {
|
|
3284
3851
|
try {
|
|
3285
|
-
const content = await
|
|
3852
|
+
const content = await readFile10(filePath, "utf-8");
|
|
3286
3853
|
const lines = content.split("\n");
|
|
3287
3854
|
const relPath = relative5(searchDir, filePath);
|
|
3288
3855
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -3328,8 +3895,8 @@ var grepTool = {
|
|
|
3328
3895
|
};
|
|
3329
3896
|
|
|
3330
3897
|
// src/tool/builtins/ls.ts
|
|
3331
|
-
import { readdir as
|
|
3332
|
-
import { join as
|
|
3898
|
+
import { readdir as readdir5, stat as stat4 } from "fs/promises";
|
|
3899
|
+
import { join as join7, relative as relative6 } from "path";
|
|
3333
3900
|
var lsTool = {
|
|
3334
3901
|
name: "ls",
|
|
3335
3902
|
kind: "read" /* Read */,
|
|
@@ -3353,7 +3920,7 @@ var lsTool = {
|
|
|
3353
3920
|
const dirPath = args.path ? resolvePath(args.path, ctx.cwd) : ctx.cwd;
|
|
3354
3921
|
const showAll = args.all ?? false;
|
|
3355
3922
|
try {
|
|
3356
|
-
const entries = await
|
|
3923
|
+
const entries = await readdir5(dirPath, { withFileTypes: true });
|
|
3357
3924
|
const lines = [];
|
|
3358
3925
|
const sorted = [...entries].toSorted((a, b) => {
|
|
3359
3926
|
if (a.isDirectory() !== b.isDirectory()) {
|
|
@@ -3367,7 +3934,7 @@ var lsTool = {
|
|
|
3367
3934
|
let sizeStr = "";
|
|
3368
3935
|
if (typeMark === "FILE") {
|
|
3369
3936
|
try {
|
|
3370
|
-
const fileStat = await stat4(
|
|
3937
|
+
const fileStat = await stat4(join7(dirPath, entry.name));
|
|
3371
3938
|
if (fileStat.size < 1024) {
|
|
3372
3939
|
sizeStr = `${fileStat.size}B`;
|
|
3373
3940
|
} else if (fileStat.size < 1024 * 1024) {
|
|
@@ -3569,13 +4136,16 @@ function getGradientColors(text, phase, stops) {
|
|
|
3569
4136
|
}
|
|
3570
4137
|
|
|
3571
4138
|
// src/ui/ChatSession.tsx
|
|
3572
|
-
import { Fragment, jsx as jsx9, jsxs as
|
|
4139
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3573
4140
|
var PHASE_CONFIG = {
|
|
3574
4141
|
thinking: { icon: "\u{1F9E0}", label: "\u601D\u8003\u4E2D", color: "#ff9800" },
|
|
3575
4142
|
generating: { icon: "\u2728", label: "\u751F\u6210\u4E2D", color: "#00ff41" },
|
|
3576
4143
|
calling_tools: { icon: "\u{1F6E0}", label: "\u8C03\u7528\u5DE5\u5177", color: "#f59e0b" },
|
|
3577
4144
|
executing_tools: { icon: "\u26A1", label: "\u6267\u884C\u5DE5\u5177", color: "#00ffff" }
|
|
3578
4145
|
};
|
|
4146
|
+
function isFileMutatingTool(name) {
|
|
4147
|
+
return name === "edit_file" || name === "write_file" || name === "multi_edit" || name === "delete_range";
|
|
4148
|
+
}
|
|
3579
4149
|
var commandRegistry = /* @__PURE__ */ new Map();
|
|
3580
4150
|
function registerCommand(name, cmd) {
|
|
3581
4151
|
commandRegistry.set(name, cmd);
|
|
@@ -3605,6 +4175,7 @@ registerCommand("/game", { desc: "\u542F\u52A8\u6E38\u620F", handler: () => ({ k
|
|
|
3605
4175
|
registerCommand("/stock", { desc: "\u67E5\u770B\u80A1\u7968\u884C\u60C5", handler: () => ({ kind: "navigate", target: "stock" }) });
|
|
3606
4176
|
registerCommand("/plan", { desc: "\u5207\u6362\u4E3A\u8BA1\u5212\u6A21\u5F0F\uFF08Shift+Tab\uFF09", handler: () => ({ kind: "text", content: "\u8F93\u5165 /plan \u6216\u6309 Shift+Tab \u5207\u6362\u4E3A\u8BA1\u5212\u6A21\u5F0F" }) });
|
|
3607
4177
|
registerCommand("/code", { desc: "\u5207\u6362\u56DE\u4EE3\u7801\u6A21\u5F0F\uFF08Shift+Tab\uFF09", handler: () => ({ kind: "text", content: "\u8F93\u5165 /code \u6216\u6309 Shift+Tab \u5207\u6362\u56DE\u4EE3\u7801\u6A21\u5F0F" }) });
|
|
4178
|
+
registerCommand("/rewind", { desc: "\u56DE\u9000\u5230\u5386\u53F2\u68C0\u67E5\u70B9\uFF081 = \u6700\u65B0\uFF09", handler: () => ({ kind: "text", 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" }) });
|
|
3608
4179
|
var STREAMING_PLACEHOLDERS = [
|
|
3609
4180
|
"\u8BA9\u5B50\u5F39\u98DE\u4E00\u4F1A\u513F...",
|
|
3610
4181
|
"\u9A6C\u4E0A\u5C31\u597D...",
|
|
@@ -3683,6 +4254,13 @@ function ChatSession({
|
|
|
3683
4254
|
const [skillSelectIndex, setSkillSelectIndex] = useState3(0);
|
|
3684
4255
|
const [fileSelectIndex, setFileSelectIndex] = useState3(0);
|
|
3685
4256
|
const [inputKey, setInputKey] = useState3(0);
|
|
4257
|
+
const [rewindSelecting, setRewindSelecting] = useState3(false);
|
|
4258
|
+
const [rewindSelectIndex, setRewindSelectIndex] = useState3(0);
|
|
4259
|
+
const [rewindList, setRewindList] = useState3([]);
|
|
4260
|
+
const [rewinding, setRewinding] = useState3(false);
|
|
4261
|
+
const [rewindHintPhase, setRewindHintPhase] = useState3("idle");
|
|
4262
|
+
const currentRoundModifiedRef = useRef2(false);
|
|
4263
|
+
const rewindHintTimerRef = useRef2(null);
|
|
3686
4264
|
const [selectingModel, setSelectingModel] = useState3(false);
|
|
3687
4265
|
const [modelSelectIndex, setModelSelectIndex] = useState3(0);
|
|
3688
4266
|
const modelOptions = ["deepseek-v4-flash", "deepseek-v4-pro"];
|
|
@@ -3699,6 +4277,14 @@ function ChatSession({
|
|
|
3699
4277
|
setSkillSelectIndex(0);
|
|
3700
4278
|
setFileSelectIndex(0);
|
|
3701
4279
|
}, [input]);
|
|
4280
|
+
useEffect3(() => {
|
|
4281
|
+
return () => {
|
|
4282
|
+
if (rewindHintTimerRef.current) {
|
|
4283
|
+
clearTimeout(rewindHintTimerRef.current);
|
|
4284
|
+
rewindHintTimerRef.current = null;
|
|
4285
|
+
}
|
|
4286
|
+
};
|
|
4287
|
+
}, []);
|
|
3702
4288
|
const getFilteredSkills = useCallback2(
|
|
3703
4289
|
(value) => {
|
|
3704
4290
|
const match = value.match(/(?:^|\s)\/([^/]*)$/);
|
|
@@ -3729,12 +4315,89 @@ function ChatSession({
|
|
|
3729
4315
|
},
|
|
3730
4316
|
[files]
|
|
3731
4317
|
);
|
|
4318
|
+
function rebuildDisplayFromSession(sess) {
|
|
4319
|
+
const next = [];
|
|
4320
|
+
for (const m of sess.messages) {
|
|
4321
|
+
if (m.role === "user") {
|
|
4322
|
+
next.push({ role: "user", content: m.content });
|
|
4323
|
+
} else if (m.role === "assistant") {
|
|
4324
|
+
next.push({
|
|
4325
|
+
role: "assistant",
|
|
4326
|
+
content: m.content,
|
|
4327
|
+
assistantDetail: {
|
|
4328
|
+
content: m.content,
|
|
4329
|
+
toolCalls: m.toolCalls
|
|
4330
|
+
}
|
|
4331
|
+
});
|
|
4332
|
+
} else if (m.role === "tool") {
|
|
4333
|
+
next.push({ role: "tool", content: m.content });
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
setDisplayMessages(next);
|
|
4337
|
+
setStaticKey((prev) => prev + 1);
|
|
4338
|
+
}
|
|
4339
|
+
const doRewind = useCallback2(async (target, displayNumber) => {
|
|
4340
|
+
const session = sessionRef.current;
|
|
4341
|
+
if (!session) return;
|
|
4342
|
+
setRewinding(true);
|
|
4343
|
+
setIsStreaming(true);
|
|
4344
|
+
setStreamingPhase("thinking");
|
|
4345
|
+
setStreamingPlaceholder("\u23EA \u6B63\u5728\u56DE\u9000\u5230\u68C0\u67E5\u70B9\u2026");
|
|
4346
|
+
setInput("");
|
|
4347
|
+
try {
|
|
4348
|
+
const r = await session.rewind(target.index);
|
|
4349
|
+
if (r.ok) {
|
|
4350
|
+
rebuildDisplayFromSession(session);
|
|
4351
|
+
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";
|
|
4352
|
+
setDisplayMessages((prev) => [
|
|
4353
|
+
...prev,
|
|
4354
|
+
{ role: "assistant", content: `\u23EA \u5DF2\u56DE\u9000\u5230\u68C0\u67E5\u70B9 #${displayNumber}${tail}\u3002` }
|
|
4355
|
+
]);
|
|
4356
|
+
} else {
|
|
4357
|
+
setDisplayMessages((prev) => [
|
|
4358
|
+
...prev,
|
|
4359
|
+
{ role: "assistant", content: `\u26A0 \u56DE\u9000\u5931\u8D25\uFF1A${r.error}` }
|
|
4360
|
+
]);
|
|
4361
|
+
}
|
|
4362
|
+
} catch (err) {
|
|
4363
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4364
|
+
setDisplayMessages((prev) => [
|
|
4365
|
+
...prev,
|
|
4366
|
+
{ role: "assistant", content: `\u26A0 \u56DE\u9000\u5F02\u5E38\uFF1A${msg}` }
|
|
4367
|
+
]);
|
|
4368
|
+
} finally {
|
|
4369
|
+
setRewinding(false);
|
|
4370
|
+
setIsStreaming(false);
|
|
4371
|
+
setStreamingPhase(null);
|
|
4372
|
+
setStreamingPlaceholder("");
|
|
4373
|
+
}
|
|
4374
|
+
}, []);
|
|
3732
4375
|
const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(() => {
|
|
3733
4376
|
process.exit(0);
|
|
3734
4377
|
});
|
|
3735
4378
|
useInput(
|
|
3736
4379
|
useCallback2(
|
|
3737
4380
|
(_input, key) => {
|
|
4381
|
+
if (rewindSelecting) {
|
|
4382
|
+
if (key.upArrow) {
|
|
4383
|
+
setRewindSelectIndex((prev) => (prev - 1 + rewindList.length) % rewindList.length);
|
|
4384
|
+
} else if (key.downArrow) {
|
|
4385
|
+
setRewindSelectIndex((prev) => (prev + 1) % rewindList.length);
|
|
4386
|
+
} else if (key.return) {
|
|
4387
|
+
const target = rewindList[rewindSelectIndex];
|
|
4388
|
+
setRewindSelecting(false);
|
|
4389
|
+
if (target) {
|
|
4390
|
+
void doRewind(target, rewindSelectIndex + 1);
|
|
4391
|
+
}
|
|
4392
|
+
} else if (key.escape) {
|
|
4393
|
+
setRewindSelecting(false);
|
|
4394
|
+
setDisplayMessages((prev) => [
|
|
4395
|
+
...prev,
|
|
4396
|
+
{ role: "assistant", content: "\u5DF2\u53D6\u6D88\u56DE\u9000\u3002" }
|
|
4397
|
+
]);
|
|
4398
|
+
}
|
|
4399
|
+
return;
|
|
4400
|
+
}
|
|
3738
4401
|
if (selectingModel) {
|
|
3739
4402
|
if (key.upArrow) {
|
|
3740
4403
|
setModelSelectIndex((prev) => (prev - 1 + modelOptions.length) % modelOptions.length);
|
|
@@ -3841,7 +4504,7 @@ function ChatSession({
|
|
|
3841
4504
|
setInput(_input);
|
|
3842
4505
|
}
|
|
3843
4506
|
},
|
|
3844
|
-
[selectingModel, modelSelectIndex, modelOptions, activeModel, isStreaming, handleCtrlC, input, skills, skillSelectIndex, fileSelectIndex, getFilteredSkills, getFilteredFiles, sessionMode, setSessionMode]
|
|
4507
|
+
[selectingModel, modelSelectIndex, modelOptions, activeModel, isStreaming, handleCtrlC, input, skills, skillSelectIndex, fileSelectIndex, getFilteredSkills, getFilteredFiles, sessionMode, setSessionMode, rewindSelecting, rewindSelectIndex, rewindList, doRewind]
|
|
3845
4508
|
)
|
|
3846
4509
|
);
|
|
3847
4510
|
useEffect3(() => {
|
|
@@ -3895,7 +4558,7 @@ function ChatSession({
|
|
|
3895
4558
|
if (!apiKey || !baseUrl) return;
|
|
3896
4559
|
let cancelled = false;
|
|
3897
4560
|
setBalanceLoading(true);
|
|
3898
|
-
import("./deepseek-
|
|
4561
|
+
import("./deepseek-PGX76BK5.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
|
|
3899
4562
|
const provider = new DeepSeekProvider2({
|
|
3900
4563
|
apiKey,
|
|
3901
4564
|
baseUrl,
|
|
@@ -3965,6 +4628,63 @@ function ChatSession({
|
|
|
3965
4628
|
if (!trimmed) return;
|
|
3966
4629
|
if (trimmed.startsWith("/") && trimmed.length > 1) {
|
|
3967
4630
|
const cmdLower = trimmed.toLowerCase();
|
|
4631
|
+
if (cmdLower === "/rewind" || cmdLower.startsWith("/rewind ")) {
|
|
4632
|
+
if (isStreaming || rewinding) {
|
|
4633
|
+
setDisplayMessages((prev) => [
|
|
4634
|
+
...prev,
|
|
4635
|
+
{ role: "user", content: trimmed },
|
|
4636
|
+
{ role: "assistant", content: "\u26A0 \u6B63\u5728\u751F\u6210\u6216\u56DE\u9000\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 /rewind\u3002" }
|
|
4637
|
+
]);
|
|
4638
|
+
setInput("");
|
|
4639
|
+
return;
|
|
4640
|
+
}
|
|
4641
|
+
if (!sessionRef.current) {
|
|
4642
|
+
setDisplayMessages((prev) => [
|
|
4643
|
+
...prev,
|
|
4644
|
+
{ role: "user", content: trimmed },
|
|
4645
|
+
{ role: "assistant", content: "\u26A0 Session \u672A\u5C31\u7EEA\uFF0C\u65E0\u6CD5\u56DE\u9000\u3002" }
|
|
4646
|
+
]);
|
|
4647
|
+
setInput("");
|
|
4648
|
+
return;
|
|
4649
|
+
}
|
|
4650
|
+
const cps = sessionRef.current.listCheckpoints();
|
|
4651
|
+
if (cps.length === 0) {
|
|
4652
|
+
setDisplayMessages((prev) => [
|
|
4653
|
+
...prev,
|
|
4654
|
+
{ role: "user", content: trimmed },
|
|
4655
|
+
{ role: "assistant", 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" }
|
|
4656
|
+
]);
|
|
4657
|
+
setInput("");
|
|
4658
|
+
return;
|
|
4659
|
+
}
|
|
4660
|
+
const parts = trimmed.split(/\s+/);
|
|
4661
|
+
if (parts.length >= 2) {
|
|
4662
|
+
const n = Number(parts[1]);
|
|
4663
|
+
if (!Number.isInteger(n) || n < 1 || n > cps.length) {
|
|
4664
|
+
setDisplayMessages((prev) => [
|
|
4665
|
+
...prev,
|
|
4666
|
+
{ role: "user", content: trimmed },
|
|
4667
|
+
{ role: "assistant", 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` }
|
|
4668
|
+
]);
|
|
4669
|
+
setInput("");
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
const target = cps[cps.length - n];
|
|
4673
|
+
setInput("");
|
|
4674
|
+
await doRewind(target, n);
|
|
4675
|
+
return;
|
|
4676
|
+
}
|
|
4677
|
+
setRewindList([...cps].reverse());
|
|
4678
|
+
setRewindSelectIndex(0);
|
|
4679
|
+
setRewindSelecting(true);
|
|
4680
|
+
setDisplayMessages((prev) => [
|
|
4681
|
+
...prev,
|
|
4682
|
+
{ role: "user", content: trimmed },
|
|
4683
|
+
{ role: "assistant", 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` }
|
|
4684
|
+
]);
|
|
4685
|
+
setInput("");
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
3968
4688
|
if (cmdLower === "/model") {
|
|
3969
4689
|
const curIdx = modelOptions.indexOf(activeModel);
|
|
3970
4690
|
setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
|
|
@@ -4119,6 +4839,12 @@ function ChatSession({
|
|
|
4119
4839
|
currentCostRef.current = void 0;
|
|
4120
4840
|
currentModelRef.current = void 0;
|
|
4121
4841
|
streamErrorRef.current = void 0;
|
|
4842
|
+
currentRoundModifiedRef.current = false;
|
|
4843
|
+
setRewindHintPhase("idle");
|
|
4844
|
+
if (rewindHintTimerRef.current) {
|
|
4845
|
+
clearTimeout(rewindHintTimerRef.current);
|
|
4846
|
+
rewindHintTimerRef.current = null;
|
|
4847
|
+
}
|
|
4122
4848
|
const session = sessionRef.current;
|
|
4123
4849
|
const abortController = new AbortController();
|
|
4124
4850
|
abortRef.current = abortController;
|
|
@@ -4146,6 +4872,12 @@ function ChatSession({
|
|
|
4146
4872
|
currentToolCallsRef.current = next;
|
|
4147
4873
|
return next;
|
|
4148
4874
|
});
|
|
4875
|
+
for (const call of event.calls) {
|
|
4876
|
+
if (isFileMutatingTool(call.name)) {
|
|
4877
|
+
currentRoundModifiedRef.current = true;
|
|
4878
|
+
break;
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4149
4881
|
break;
|
|
4150
4882
|
case "tool_result":
|
|
4151
4883
|
setStreamingPhase("executing_tools");
|
|
@@ -4216,6 +4948,14 @@ function ChatSession({
|
|
|
4216
4948
|
}
|
|
4217
4949
|
]);
|
|
4218
4950
|
}
|
|
4951
|
+
if (currentRoundModifiedRef.current && !finStreamError) {
|
|
4952
|
+
setRewindHintPhase("pending");
|
|
4953
|
+
if (rewindHintTimerRef.current) clearTimeout(rewindHintTimerRef.current);
|
|
4954
|
+
rewindHintTimerRef.current = setTimeout(() => {
|
|
4955
|
+
setRewindHintPhase((prev) => prev === "pending" ? "visible" : prev);
|
|
4956
|
+
rewindHintTimerRef.current = null;
|
|
4957
|
+
}, 2e3);
|
|
4958
|
+
}
|
|
4219
4959
|
}
|
|
4220
4960
|
}, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills, thinkingEnabled, thinkingEffort, responseFormat, toolChoice, activeModel, sessionMode]);
|
|
4221
4961
|
useEffect3(() => {
|
|
@@ -4223,36 +4963,36 @@ function ChatSession({
|
|
|
4223
4963
|
setTodayCost(externalCostTracker.todayTotalCost);
|
|
4224
4964
|
}
|
|
4225
4965
|
}, [isStreaming, externalCostTracker]);
|
|
4226
|
-
return /* @__PURE__ */
|
|
4227
|
-
!hasConversationStarted && /* @__PURE__ */
|
|
4228
|
-
/* @__PURE__ */ jsx9(
|
|
4966
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
|
|
4967
|
+
!hasConversationStarted && /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", marginBottom: 1, children: [
|
|
4968
|
+
/* @__PURE__ */ jsx9(Box9, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
|
|
4229
4969
|
const colorIndex = (i + offset) % CYBER_PALETTE.length;
|
|
4230
|
-
return /* @__PURE__ */ jsx9(
|
|
4970
|
+
return /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
|
|
4231
4971
|
}) }),
|
|
4232
|
-
/* @__PURE__ */
|
|
4233
|
-
/* @__PURE__ */
|
|
4972
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", justifyContent: "center", children: [
|
|
4973
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "#00ff41", children: [
|
|
4234
4974
|
" \u2714 ",
|
|
4235
4975
|
"\u5DF2\u5C31\u7EEA ",
|
|
4236
4976
|
skillCount,
|
|
4237
4977
|
" \u4E2A Skill"
|
|
4238
4978
|
] }),
|
|
4239
|
-
/* @__PURE__ */
|
|
4979
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "#00ffff", children: [
|
|
4240
4980
|
" \u2139 ",
|
|
4241
4981
|
"\u5DF2\u5C31\u7EEA ",
|
|
4242
4982
|
toolCount,
|
|
4243
4983
|
" \u4E2A\u5DE5\u5177"
|
|
4244
4984
|
] }),
|
|
4245
|
-
/* @__PURE__ */
|
|
4985
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "#00ffff", children: [
|
|
4246
4986
|
" \u{1F527} \u6A21\u578B ",
|
|
4247
4987
|
SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
|
|
4248
4988
|
] }),
|
|
4249
|
-
thinkingEnabled && /* @__PURE__ */
|
|
4989
|
+
thinkingEnabled && /* @__PURE__ */ jsxs9(Text10, { color: "#ff9800", children: [
|
|
4250
4990
|
" \u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
|
|
4251
4991
|
thinkingEffort === "max" ? "Max" : "High"
|
|
4252
4992
|
] }),
|
|
4253
4993
|
sessionMode === "plan" && /* @__PURE__ */ jsx9(Text10, { color: "#ff69b4", bold: true, children: " \u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" }),
|
|
4254
4994
|
responseFormat === "json_object" && /* @__PURE__ */ jsx9(Text10, { color: "#4caf50", children: " \u{1F4C4} JSON" }),
|
|
4255
|
-
toolChoice !== void 0 && /* @__PURE__ */
|
|
4995
|
+
toolChoice !== void 0 && /* @__PURE__ */ jsxs9(Text10, { color: "#e91e63", children: [
|
|
4256
4996
|
" \u{1F6E0} ",
|
|
4257
4997
|
toolChoice === "none" ? "\u7981\u6B62\u5DE5\u5177" : toolChoice === "required" ? "\u5F3A\u5236\u5DE5\u5177" : ""
|
|
4258
4998
|
] }),
|
|
@@ -4260,43 +5000,43 @@ function ChatSession({
|
|
|
4260
5000
|
const tip = cmdTips[cmdTipIndex % cmdTips.length];
|
|
4261
5001
|
if (!tip) return null;
|
|
4262
5002
|
const text = `${tip.name} ${tip.desc}`;
|
|
4263
|
-
return /* @__PURE__ */
|
|
5003
|
+
return /* @__PURE__ */ jsxs9(Text10, { children: [
|
|
4264
5004
|
/* @__PURE__ */ jsx9(Text10, { color: "#808080", children: " \u{1F4A1} " }),
|
|
4265
5005
|
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx9(Text10, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx9(Text10, { color: "#808080", children: text })
|
|
4266
5006
|
] });
|
|
4267
5007
|
})(),
|
|
4268
5008
|
verbose ? /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
|
|
4269
5009
|
] }),
|
|
4270
|
-
/* @__PURE__ */
|
|
4271
|
-
balanceLoading && balance === null ? /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */
|
|
5010
|
+
/* @__PURE__ */ jsxs9(Box9, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
|
|
5011
|
+
balanceLoading && balance === null ? /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
|
|
4272
5012
|
/* @__PURE__ */ jsx9(Text10, { color: "yellow", children: "\u{1F4B0} " }),
|
|
4273
|
-
/* @__PURE__ */
|
|
5013
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "yellow", children: [
|
|
4274
5014
|
"\u4F59\u989D \xA5",
|
|
4275
5015
|
balance.toFixed(2)
|
|
4276
5016
|
] })
|
|
4277
5017
|
] }) : null,
|
|
4278
|
-
todayCost !== null ? /* @__PURE__ */
|
|
5018
|
+
todayCost !== null ? /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
|
|
4279
5019
|
/* @__PURE__ */ jsx9(Text10, { color: "cyan", children: "\u{1F4CA} " }),
|
|
4280
|
-
/* @__PURE__ */
|
|
5020
|
+
/* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
|
|
4281
5021
|
"\u4ECA\u65E5 \xA5",
|
|
4282
5022
|
todayCost.toFixed(2)
|
|
4283
5023
|
] })
|
|
4284
5024
|
] }) : null
|
|
4285
5025
|
] })
|
|
4286
5026
|
] }),
|
|
4287
|
-
/* @__PURE__ */
|
|
5027
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, children: [
|
|
4288
5028
|
/* @__PURE__ */ jsx9(Static, { items: displayMessages, children: (msg, i) => {
|
|
4289
5029
|
if (msg.role === "user") {
|
|
4290
|
-
return /* @__PURE__ */
|
|
4291
|
-
/* @__PURE__ */ jsx9(
|
|
4292
|
-
/* @__PURE__ */ jsx9(
|
|
5030
|
+
return /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
|
|
5031
|
+
/* @__PURE__ */ jsx9(Box9, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
|
|
5032
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text10, { wrap: "wrap", children: msg.content }) })
|
|
4293
5033
|
] }, i);
|
|
4294
5034
|
}
|
|
4295
5035
|
if (msg.role === "tool") {
|
|
4296
|
-
return /* @__PURE__ */
|
|
4297
|
-
/* @__PURE__ */
|
|
4298
|
-
/* @__PURE__ */ jsx9(
|
|
4299
|
-
/* @__PURE__ */ jsx9(
|
|
5036
|
+
return /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
5037
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
|
|
5038
|
+
/* @__PURE__ */ jsx9(Box9, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#f59e0b", children: "\u{1F527}" }) }),
|
|
5039
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text10, { wrap: "wrap", children: msg.content }) })
|
|
4300
5040
|
] }),
|
|
4301
5041
|
msg.diff && /* @__PURE__ */ jsx9(DiffPreview, { diff: msg.diff })
|
|
4302
5042
|
] }, i);
|
|
@@ -4324,14 +5064,14 @@ function ChatSession({
|
|
|
4324
5064
|
isStreaming: true
|
|
4325
5065
|
}
|
|
4326
5066
|
),
|
|
4327
|
-
!isStreaming && streamError && /* @__PURE__ */ jsx9(
|
|
5067
|
+
!isStreaming && streamError && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
|
|
4328
5068
|
"\u26A0 ",
|
|
4329
5069
|
streamError
|
|
4330
5070
|
] }) })
|
|
4331
5071
|
] }),
|
|
4332
|
-
selectingModel ? /* @__PURE__ */
|
|
5072
|
+
selectingModel ? /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
4333
5073
|
/* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
4334
|
-
/* @__PURE__ */
|
|
5074
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, children: [
|
|
4335
5075
|
/* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
|
|
4336
5076
|
modelOptions.map((id, i) => {
|
|
4337
5077
|
const meta = SUPPORTED_MODELS[id];
|
|
@@ -4339,8 +5079,8 @@ function ChatSession({
|
|
|
4339
5079
|
const isSelected = i === modelSelectIndex;
|
|
4340
5080
|
const marker = isSelected ? " > " : " ";
|
|
4341
5081
|
const suffix = isCurrent ? " (\u5F53\u524D)" : "";
|
|
4342
|
-
return /* @__PURE__ */
|
|
4343
|
-
/* @__PURE__ */
|
|
5082
|
+
return /* @__PURE__ */ jsxs9(Box9, { children: [
|
|
5083
|
+
/* @__PURE__ */ jsxs9(
|
|
4344
5084
|
Text10,
|
|
4345
5085
|
{
|
|
4346
5086
|
color: isSelected ? "#00ff41" : void 0,
|
|
@@ -4352,42 +5092,78 @@ function ChatSession({
|
|
|
4352
5092
|
]
|
|
4353
5093
|
}
|
|
4354
5094
|
),
|
|
4355
|
-
isSelected && /* @__PURE__ */
|
|
5095
|
+
isSelected && /* @__PURE__ */ jsxs9(Text10, { color: "#808080", children: [
|
|
4356
5096
|
" \u2014 ",
|
|
4357
5097
|
id
|
|
4358
5098
|
] })
|
|
4359
5099
|
] }, id);
|
|
4360
5100
|
}),
|
|
4361
|
-
/* @__PURE__ */ jsx9(
|
|
5101
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
5102
|
+
] }),
|
|
5103
|
+
/* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
|
|
5104
|
+
] }) : rewindSelecting ? /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
|
|
5105
|
+
/* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
|
|
5106
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", marginTop: 1, children: [
|
|
5107
|
+
/* @__PURE__ */ jsx9(Text10, { bold: true, color: "#ff9800", children: "\u9009\u62E9\u8981\u56DE\u9000\u7684\u68C0\u67E5\u70B9\uFF1A" }),
|
|
5108
|
+
rewindList.map((cp2, i) => {
|
|
5109
|
+
const isSelected = i === rewindSelectIndex;
|
|
5110
|
+
const marker = isSelected ? " > " : " ";
|
|
5111
|
+
const time = new Date(cp2.timestamp).toLocaleTimeString();
|
|
5112
|
+
const preview = cp2.preview || "(\u7A7A)";
|
|
5113
|
+
const tag = cp2.isGitRepo ? "" : " [\u975E git\uFF0C\u4EC5\u5BF9\u8BDD]";
|
|
5114
|
+
return /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(
|
|
5115
|
+
Text10,
|
|
5116
|
+
{
|
|
5117
|
+
color: isSelected ? "#ff9800" : void 0,
|
|
5118
|
+
bold: isSelected,
|
|
5119
|
+
children: [
|
|
5120
|
+
marker,
|
|
5121
|
+
"#",
|
|
5122
|
+
i + 1,
|
|
5123
|
+
" ",
|
|
5124
|
+
time,
|
|
5125
|
+
" `",
|
|
5126
|
+
preview,
|
|
5127
|
+
tag,
|
|
5128
|
+
"`"
|
|
5129
|
+
]
|
|
5130
|
+
}
|
|
5131
|
+
) }, cp2.index);
|
|
5132
|
+
}),
|
|
5133
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
4362
5134
|
] }),
|
|
4363
5135
|
/* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
|
|
4364
|
-
] }) : /* @__PURE__ */
|
|
4365
|
-
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx9(
|
|
5136
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
5137
|
+
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx9(Box9, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs9(Text10, { bold: true, color: PHASE_CONFIG[streamingPhase].color, children: [
|
|
4366
5138
|
PHASE_CONFIG[streamingPhase].icon,
|
|
4367
5139
|
" ",
|
|
4368
5140
|
PHASE_CONFIG[streamingPhase].label,
|
|
4369
5141
|
" ",
|
|
4370
5142
|
/* @__PURE__ */ jsx9(InkSpinner2, { type: "dots" })
|
|
4371
|
-
] }) }) :
|
|
4372
|
-
|
|
5143
|
+
] }) }) : rewindHintPhase === "visible" ? (
|
|
5144
|
+
// 本轮修改了文件时,流式结束后 2s 在原位置展示 /rewind 提示
|
|
5145
|
+
// 一直保留到下次对话开始,与 /rewind 1(最新检查点)配套
|
|
5146
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx9(Text10, { color: "#808080", children: "\u21A9 /rewind 1 \u53EF\u64A4\u56DE\u672C\u6B21\u4FEE\u6539" }) })
|
|
5147
|
+
) : null,
|
|
5148
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: hasConversationStarted || sessionMode === "plan" ? /* @__PURE__ */ jsxs9(Text10, { color: sessionMode === "plan" ? "#ff69b4" : "#00ffff", dimColor: sessionMode !== "plan", children: [
|
|
4373
5149
|
/* @__PURE__ */ jsx9(Text10, { children: sessionMode === "plan" ? "\u2500".repeat(Math.max(dividerWidth - 48, 1)) : "\u2500".repeat(Math.max(dividerWidth - 35, 10)) }),
|
|
4374
|
-
balance !== null && /* @__PURE__ */
|
|
5150
|
+
balance !== null && /* @__PURE__ */ jsxs9(Text10, { color: "yellow", children: [
|
|
4375
5151
|
" \u{1F4B0} \u4F59\u989D \xA5",
|
|
4376
5152
|
balance.toFixed(2)
|
|
4377
5153
|
] }),
|
|
4378
|
-
isStreaming ? /* @__PURE__ */
|
|
5154
|
+
isStreaming ? /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
|
|
4379
5155
|
" \u{1F4CA} \u672C\u6B21 \xA5",
|
|
4380
5156
|
sessionCost > 0 ? sessionCost.toFixed(4) + " " : "",
|
|
4381
5157
|
/* @__PURE__ */ jsx9(InkSpinner2, { type: "dots" })
|
|
4382
|
-
] }) : sessionCost > 0 ? /* @__PURE__ */
|
|
5158
|
+
] }) : sessionCost > 0 ? /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
|
|
4383
5159
|
" \u{1F4CA} \u672C\u6B21 \xA5",
|
|
4384
5160
|
sessionCost.toFixed(4)
|
|
4385
5161
|
] }) : null,
|
|
4386
5162
|
sessionMode === "plan" && /* @__PURE__ */ jsx9(Text10, { color: "#ff69b4", bold: true, children: " \u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" })
|
|
4387
5163
|
] }) : /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
4388
|
-
/* @__PURE__ */
|
|
4389
|
-
/* @__PURE__ */ jsx9(
|
|
4390
|
-
/* @__PURE__ */ jsx9(
|
|
5164
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
5165
|
+
/* @__PURE__ */ jsx9(Box9, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
|
|
5166
|
+
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx9(Text10, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx9(Text10, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx9(Text10, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx9(Text10, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx9(
|
|
4391
5167
|
TextInput,
|
|
4392
5168
|
{
|
|
4393
5169
|
value: input,
|
|
@@ -4398,19 +5174,19 @@ function ChatSession({
|
|
|
4398
5174
|
inputKey
|
|
4399
5175
|
) })
|
|
4400
5176
|
] }),
|
|
4401
|
-
/* @__PURE__ */ jsx9(
|
|
5177
|
+
/* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
|
|
4402
5178
|
/* @__PURE__ */ jsx9(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
|
|
4403
5179
|
/* @__PURE__ */ jsx9(FileSelector, { files, input, selectedIndex: fileSelectIndex })
|
|
4404
5180
|
] }),
|
|
4405
|
-
doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx9(
|
|
4406
|
-
isStreaming && /* @__PURE__ */ jsx9(
|
|
5181
|
+
doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
|
|
5182
|
+
isStreaming && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
|
|
4407
5183
|
] });
|
|
4408
5184
|
}
|
|
4409
5185
|
|
|
4410
5186
|
// src/ui/GamePicker.tsx
|
|
4411
|
-
import { Box as
|
|
5187
|
+
import { Box as Box10, Text as Text11, useInput as useInput2 } from "ink";
|
|
4412
5188
|
import { useState as useState4, useCallback as useCallback3 } from "react";
|
|
4413
|
-
import { jsx as jsx10, jsxs as
|
|
5189
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4414
5190
|
function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
4415
5191
|
const [selectedIndex, setSelectedIndex] = useState4(0);
|
|
4416
5192
|
const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
|
|
@@ -4438,18 +5214,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
|
4438
5214
|
[games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
|
|
4439
5215
|
)
|
|
4440
5216
|
);
|
|
4441
|
-
return /* @__PURE__ */
|
|
4442
|
-
/* @__PURE__ */ jsx10(
|
|
4443
|
-
/* @__PURE__ */ jsx10(
|
|
5217
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
|
|
5218
|
+
/* @__PURE__ */ jsx10(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
|
|
5219
|
+
/* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: games.map((game, index) => {
|
|
4444
5220
|
const isSelected = index === selectedIndex;
|
|
4445
|
-
return /* @__PURE__ */
|
|
4446
|
-
/* @__PURE__ */ jsx10(
|
|
4447
|
-
/* @__PURE__ */ jsx10(
|
|
4448
|
-
/* @__PURE__ */ jsx10(
|
|
5221
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
5222
|
+
/* @__PURE__ */ jsx10(Box10, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx10(Text11, { children: " " }) }),
|
|
5223
|
+
/* @__PURE__ */ jsx10(Box10, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
|
|
5224
|
+
/* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text11, { color: "#888888", children: game.description }) })
|
|
4449
5225
|
] }, game.id);
|
|
4450
5226
|
}) }),
|
|
4451
|
-
/* @__PURE__ */ jsx10(
|
|
4452
|
-
doubleCtrlC && /* @__PURE__ */ jsx10(
|
|
5227
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
|
|
5228
|
+
doubleCtrlC && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
4453
5229
|
] });
|
|
4454
5230
|
}
|
|
4455
5231
|
|
|
@@ -4466,9 +5242,9 @@ function listGames() {
|
|
|
4466
5242
|
}
|
|
4467
5243
|
|
|
4468
5244
|
// src/game/brick-breaker/index.tsx
|
|
4469
|
-
import { Box as
|
|
5245
|
+
import { Box as Box11, Text as Text12, useInput as useInput3, render as render2 } from "ink";
|
|
4470
5246
|
import { useState as useState5, useEffect as useEffect4, useRef as useRef3, useCallback as useCallback4 } from "react";
|
|
4471
|
-
import { jsx as jsx11, jsxs as
|
|
5247
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4472
5248
|
var GAME_WIDTH = 40;
|
|
4473
5249
|
var GAME_HEIGHT = 18;
|
|
4474
5250
|
var PADDLE_WIDTH = 9;
|
|
@@ -4658,48 +5434,48 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
4658
5434
|
const board = buildBoard(s);
|
|
4659
5435
|
const def = getLevel(s.level);
|
|
4660
5436
|
void tick2;
|
|
4661
|
-
return /* @__PURE__ */
|
|
4662
|
-
/* @__PURE__ */
|
|
4663
|
-
/* @__PURE__ */ jsx11(
|
|
5437
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
5438
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
|
|
5439
|
+
/* @__PURE__ */ jsx11(Box11, { width: 20, children: /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4664
5440
|
"\u5173\u5361 ",
|
|
4665
5441
|
s.level,
|
|
4666
5442
|
": ",
|
|
4667
5443
|
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: def.desc })
|
|
4668
5444
|
] }) }),
|
|
4669
|
-
/* @__PURE__ */ jsx11(
|
|
5445
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4670
5446
|
"\u5206\u6570: ",
|
|
4671
5447
|
/* @__PURE__ */ jsx11(Text12, { color: "yellow", children: String(s.score).padStart(3, "0") })
|
|
4672
5448
|
] }) }),
|
|
4673
|
-
/* @__PURE__ */ jsx11(
|
|
5449
|
+
/* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4674
5450
|
"\u751F\u547D: ",
|
|
4675
5451
|
/* @__PURE__ */ jsx11(Text12, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
|
|
4676
5452
|
] }) }),
|
|
4677
|
-
/* @__PURE__ */ jsx11(
|
|
5453
|
+
/* @__PURE__ */ jsx11(Box11, { width: 10, children: /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4678
5454
|
"\u7816\u5757: ",
|
|
4679
5455
|
/* @__PURE__ */ jsx11(Text12, { color: "cyan", children: aliveCount })
|
|
4680
5456
|
] }) }),
|
|
4681
|
-
/* @__PURE__ */ jsx11(
|
|
5457
|
+
/* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: s.paused ? "gray" : "green", children: [
|
|
4682
5458
|
"[",
|
|
4683
5459
|
s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
|
|
4684
5460
|
"]"
|
|
4685
5461
|
] }) })
|
|
4686
5462
|
] }),
|
|
4687
|
-
/* @__PURE__ */
|
|
4688
|
-
/* @__PURE__ */
|
|
5463
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
5464
|
+
/* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4689
5465
|
"\u250C",
|
|
4690
5466
|
"\u2500".repeat(GAME_WIDTH),
|
|
4691
5467
|
"\u2510"
|
|
4692
5468
|
] }),
|
|
4693
5469
|
/* @__PURE__ */ jsx11(Text12, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
|
|
4694
|
-
/* @__PURE__ */
|
|
5470
|
+
/* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4695
5471
|
"\u2514",
|
|
4696
5472
|
"\u2500".repeat(GAME_WIDTH),
|
|
4697
5473
|
"\u2518"
|
|
4698
5474
|
] })
|
|
4699
5475
|
] }),
|
|
4700
|
-
selectingLevel && /* @__PURE__ */
|
|
5476
|
+
selectingLevel && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
|
|
4701
5477
|
/* @__PURE__ */ jsx11(Text12, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
|
|
4702
|
-
/* @__PURE__ */ jsx11(
|
|
5478
|
+
/* @__PURE__ */ jsx11(Box11, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx11(Box11, { width: 22, children: /* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4703
5479
|
/* @__PURE__ */ jsx11(Text12, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
|
|
4704
5480
|
". ",
|
|
4705
5481
|
lv.desc,
|
|
@@ -4709,16 +5485,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
4709
5485
|
lv.cols,
|
|
4710
5486
|
")"
|
|
4711
5487
|
] }) }, i)) }),
|
|
4712
|
-
/* @__PURE__ */ jsx11(
|
|
5488
|
+
/* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
|
|
4713
5489
|
] }),
|
|
4714
|
-
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */
|
|
5490
|
+
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
|
|
4715
5491
|
/* @__PURE__ */ jsx11(Text12, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
|
|
4716
|
-
/* @__PURE__ */
|
|
5492
|
+
/* @__PURE__ */ jsxs11(Text12, { children: [
|
|
4717
5493
|
" \u5206\u6570: ",
|
|
4718
5494
|
/* @__PURE__ */ jsx11(Text12, { color: "yellow", children: s.score })
|
|
4719
5495
|
] })
|
|
4720
5496
|
] }),
|
|
4721
|
-
!selectingLevel && /* @__PURE__ */ jsx11(
|
|
5497
|
+
!selectingLevel && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
|
|
4722
5498
|
] });
|
|
4723
5499
|
}
|
|
4724
5500
|
var brick_breaker_default = {
|
|
@@ -4738,9 +5514,9 @@ var brick_breaker_default = {
|
|
|
4738
5514
|
};
|
|
4739
5515
|
|
|
4740
5516
|
// src/game/coder-check/index.tsx
|
|
4741
|
-
import { Box as
|
|
5517
|
+
import { Box as Box12, Text as Text13, useInput as useInput4, render as render3 } from "ink";
|
|
4742
5518
|
import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback5 } from "react";
|
|
4743
|
-
import { jsx as jsx12, jsxs as
|
|
5519
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4744
5520
|
var GAME_W = 66;
|
|
4745
5521
|
var GAME_H = 20;
|
|
4746
5522
|
var SCORE_H = 6;
|
|
@@ -5211,44 +5987,44 @@ function CoderCheck({ onExit: _onExit }) {
|
|
|
5211
5987
|
const scoreLines = buildScoreLines(scoreStr);
|
|
5212
5988
|
const view = buildGameView(s, scoreLines, scoreColor, s.message);
|
|
5213
5989
|
void tick2;
|
|
5214
|
-
return /* @__PURE__ */
|
|
5215
|
-
/* @__PURE__ */ jsx12(
|
|
5990
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingX: 1, children: [
|
|
5991
|
+
/* @__PURE__ */ jsx12(Box12, { flexDirection: "row", children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
5216
5992
|
"\u751F\u547D ",
|
|
5217
5993
|
/* @__PURE__ */ jsx12(Text13, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
|
|
5218
5994
|
" ",
|
|
5219
5995
|
"\u901F\u5EA6 ",
|
|
5220
|
-
/* @__PURE__ */
|
|
5996
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
|
|
5221
5997
|
"Lv.",
|
|
5222
5998
|
Math.floor(s.speed * 10)
|
|
5223
5999
|
] })
|
|
5224
6000
|
] }) }),
|
|
5225
|
-
!s.gameOver && s.target && /* @__PURE__ */ jsx12(
|
|
6001
|
+
!s.gameOver && s.target && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
5226
6002
|
"\u6253\u5B57: ",
|
|
5227
6003
|
/* @__PURE__ */ jsx12(Text13, { color: "green", children: s.typed }),
|
|
5228
6004
|
/* @__PURE__ */ jsx12(Text13, { color: "white", children: s.target.slice(s.typed.length) })
|
|
5229
6005
|
] }) }),
|
|
5230
|
-
/* @__PURE__ */
|
|
5231
|
-
/* @__PURE__ */
|
|
6006
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
6007
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
5232
6008
|
"\u250C",
|
|
5233
6009
|
"\u2500".repeat(GAME_W),
|
|
5234
6010
|
"\u2510"
|
|
5235
6011
|
] }),
|
|
5236
6012
|
view.map((row, i) => /* @__PURE__ */ jsx12(Text13, { children: `\u2502${row}\u2502` }, i)),
|
|
5237
|
-
/* @__PURE__ */
|
|
6013
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
5238
6014
|
"\u2514",
|
|
5239
6015
|
"\u2500".repeat(GAME_W),
|
|
5240
6016
|
"\u2518"
|
|
5241
6017
|
] })
|
|
5242
6018
|
] }),
|
|
5243
|
-
s.gameOver && /* @__PURE__ */
|
|
6019
|
+
s.gameOver && /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, children: [
|
|
5244
6020
|
/* @__PURE__ */ jsx12(Text13, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
|
|
5245
|
-
/* @__PURE__ */
|
|
6021
|
+
/* @__PURE__ */ jsxs12(Text13, { children: [
|
|
5246
6022
|
" \u5F97\u5206: ",
|
|
5247
6023
|
/* @__PURE__ */ jsx12(Text13, { color: "yellow", children: s.score }),
|
|
5248
6024
|
" r \u91CD\u5F00 q \u9000\u51FA"
|
|
5249
6025
|
] })
|
|
5250
6026
|
] }),
|
|
5251
|
-
/* @__PURE__ */ jsx12(
|
|
6027
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
|
|
5252
6028
|
] });
|
|
5253
6029
|
}
|
|
5254
6030
|
var coder_check_default = {
|
|
@@ -5638,13 +6414,13 @@ import { render as render4 } from "ink";
|
|
|
5638
6414
|
import chalk5 from "chalk";
|
|
5639
6415
|
|
|
5640
6416
|
// src/stock/StockList.tsx
|
|
5641
|
-
import { Box as
|
|
6417
|
+
import { Box as Box13, Text as Text14, useInput as useInput5 } from "ink";
|
|
5642
6418
|
import { useState as useState7, useCallback as useCallback6, useEffect as useEffect6, useMemo as useMemo2 } from "react";
|
|
5643
6419
|
import asciichart from "asciichart";
|
|
5644
6420
|
import os from "os";
|
|
5645
|
-
import { join as
|
|
5646
|
-
import { jsx as jsx13, jsxs as
|
|
5647
|
-
var SETTINGS_PATH =
|
|
6421
|
+
import { join as join8 } from "path";
|
|
6422
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6423
|
+
var SETTINGS_PATH = join8(os.homedir(), ".dskcode", "settings.json");
|
|
5648
6424
|
function toFileUrl(p) {
|
|
5649
6425
|
const norm = p.replace(/\\/g, "/");
|
|
5650
6426
|
if (process.platform === "win32") {
|
|
@@ -5862,64 +6638,64 @@ function StockList({ codes, onExit, onBackToChat }) {
|
|
|
5862
6638
|
);
|
|
5863
6639
|
if (detailView) {
|
|
5864
6640
|
if (detailLoading) {
|
|
5865
|
-
return /* @__PURE__ */ jsx13(
|
|
6641
|
+
return /* @__PURE__ */ jsx13(Box13, { paddingLeft: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
|
|
5866
6642
|
}
|
|
5867
6643
|
return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
|
|
5868
6644
|
}
|
|
5869
6645
|
const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
|
|
5870
|
-
return /* @__PURE__ */
|
|
5871
|
-
/* @__PURE__ */
|
|
6646
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
6647
|
+
/* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
5872
6648
|
/* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
|
|
5873
|
-
/* @__PURE__ */
|
|
6649
|
+
/* @__PURE__ */ jsxs13(Text14, { dimColor: true, children: [
|
|
5874
6650
|
" \u{1F550} ",
|
|
5875
6651
|
currentTime
|
|
5876
6652
|
] }),
|
|
5877
6653
|
/* @__PURE__ */ jsx13(Text14, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
|
|
5878
6654
|
] }),
|
|
5879
|
-
/* @__PURE__ */
|
|
5880
|
-
/* @__PURE__ */ jsx13(
|
|
5881
|
-
/* @__PURE__ */ jsx13(
|
|
5882
|
-
/* @__PURE__ */ jsx13(
|
|
5883
|
-
/* @__PURE__ */ jsx13(
|
|
5884
|
-
/* @__PURE__ */ jsx13(
|
|
6655
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
6656
|
+
/* @__PURE__ */ jsx13(Box13, { width: 3 }),
|
|
6657
|
+
/* @__PURE__ */ jsx13(Box13, { width: 9, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u4EE3\u7801" }) }),
|
|
6658
|
+
/* @__PURE__ */ jsx13(Box13, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u540D\u79F0" }) }),
|
|
6659
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
|
|
6660
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { dimColor: true, children: [
|
|
5885
6661
|
"\u6DA8\u8DCC\u5E45",
|
|
5886
6662
|
sortOrder === "desc" ? " \u25BC" : sortOrder === "asc" ? " \u25B2" : ""
|
|
5887
6663
|
] }) }),
|
|
5888
|
-
/* @__PURE__ */ jsx13(
|
|
5889
|
-
/* @__PURE__ */ jsx13(
|
|
5890
|
-
/* @__PURE__ */ jsx13(
|
|
5891
|
-
/* @__PURE__ */ jsx13(
|
|
6664
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
|
|
6665
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u9AD8" }) }),
|
|
6666
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u4F4E" }) }),
|
|
6667
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
|
|
5892
6668
|
] }),
|
|
5893
|
-
/* @__PURE__ */ jsx13(
|
|
5894
|
-
/* @__PURE__ */ jsx13(
|
|
6669
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
|
|
6670
|
+
/* @__PURE__ */ jsx13(Box13, { flexDirection: "column", children: sortedStocks.map((stock, index) => {
|
|
5895
6671
|
const isSelected = index === selectedIndex;
|
|
5896
6672
|
const isUp = stock.changePercent >= 0;
|
|
5897
6673
|
const color = isUp ? "#ff1493" : "#00ff41";
|
|
5898
|
-
return /* @__PURE__ */
|
|
5899
|
-
/* @__PURE__ */ jsx13(
|
|
5900
|
-
/* @__PURE__ */ jsx13(
|
|
5901
|
-
/* @__PURE__ */ jsx13(
|
|
5902
|
-
/* @__PURE__ */ jsx13(
|
|
5903
|
-
/* @__PURE__ */ jsx13(
|
|
6674
|
+
return /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
6675
|
+
/* @__PURE__ */ jsx13(Box13, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx13(Text14, { children: " " }) }),
|
|
6676
|
+
/* @__PURE__ */ jsx13(Box13, { width: 9, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
|
|
6677
|
+
/* @__PURE__ */ jsx13(Box13, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
|
|
6678
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
|
|
6679
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { ...cp2(color), children: [
|
|
5904
6680
|
isUp ? "+" : "",
|
|
5905
6681
|
stock.changePercent.toFixed(2),
|
|
5906
6682
|
"%"
|
|
5907
6683
|
] }) }),
|
|
5908
|
-
/* @__PURE__ */ jsx13(
|
|
6684
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { ...cp2(color), children: [
|
|
5909
6685
|
isUp ? "+" : "",
|
|
5910
6686
|
stock.changeAmount.toFixed(3)
|
|
5911
6687
|
] }) }),
|
|
5912
|
-
/* @__PURE__ */ jsx13(
|
|
5913
|
-
/* @__PURE__ */ jsx13(
|
|
5914
|
-
/* @__PURE__ */ jsx13(
|
|
6688
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
|
|
6689
|
+
/* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
|
|
6690
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
|
|
5915
6691
|
] }, stock.code);
|
|
5916
6692
|
}) }),
|
|
5917
|
-
/* @__PURE__ */ jsx13(
|
|
5918
|
-
/* @__PURE__ */
|
|
6693
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { 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` }) }),
|
|
6694
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
5919
6695
|
/* @__PURE__ */ jsx13(Text14, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
|
|
5920
6696
|
/* @__PURE__ */ jsx13(Text14, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
|
|
5921
6697
|
] }),
|
|
5922
|
-
doubleCtrlC && /* @__PURE__ */ jsx13(
|
|
6698
|
+
doubleCtrlC && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
5923
6699
|
] });
|
|
5924
6700
|
}
|
|
5925
6701
|
function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
@@ -5937,33 +6713,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
5937
6713
|
raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
|
|
5938
6714
|
chartLines = raw.split("\n");
|
|
5939
6715
|
}
|
|
5940
|
-
return /* @__PURE__ */
|
|
5941
|
-
/* @__PURE__ */
|
|
5942
|
-
/* @__PURE__ */
|
|
5943
|
-
/* @__PURE__ */
|
|
6716
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingLeft: 1, children: [
|
|
6717
|
+
/* @__PURE__ */ jsxs13(Box13, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
6718
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
6719
|
+
/* @__PURE__ */ jsxs13(Text14, { bold: true, color: "#00ffff", children: [
|
|
5944
6720
|
" \u{1F4CA} ",
|
|
5945
6721
|
stock.name,
|
|
5946
6722
|
" "
|
|
5947
6723
|
] }),
|
|
5948
6724
|
/* @__PURE__ */ jsx13(Text14, { dimColor: true, children: stock.code }),
|
|
5949
|
-
currentTime && /* @__PURE__ */
|
|
6725
|
+
currentTime && /* @__PURE__ */ jsxs13(Text14, { dimColor: true, children: [
|
|
5950
6726
|
" \u{1F550} ",
|
|
5951
6727
|
currentTime
|
|
5952
6728
|
] })
|
|
5953
6729
|
] }),
|
|
5954
6730
|
/* @__PURE__ */ jsx13(Text14, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
|
|
5955
6731
|
] }),
|
|
5956
|
-
/* @__PURE__ */
|
|
5957
|
-
/* @__PURE__ */ jsx13(
|
|
5958
|
-
/* @__PURE__ */ jsx13(
|
|
6732
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
6733
|
+
/* @__PURE__ */ jsx13(Box13, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
|
|
6734
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsxs13(Text14, { bold: true, color: colorCode, children: [
|
|
5959
6735
|
arrow,
|
|
5960
6736
|
" ",
|
|
5961
6737
|
formatPrice(stock.price)
|
|
5962
6738
|
] }) })
|
|
5963
6739
|
] }),
|
|
5964
|
-
/* @__PURE__ */
|
|
5965
|
-
/* @__PURE__ */ jsx13(
|
|
5966
|
-
/* @__PURE__ */ jsx13(
|
|
6740
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
6741
|
+
/* @__PURE__ */ jsx13(Box13, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
6742
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsxs13(Text14, { color: colorCode, children: [
|
|
5967
6743
|
isUp ? "+" : "",
|
|
5968
6744
|
stock.changePercent.toFixed(2),
|
|
5969
6745
|
"%",
|
|
@@ -5972,14 +6748,14 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
5972
6748
|
stock.changeAmount.toFixed(3)
|
|
5973
6749
|
] }) })
|
|
5974
6750
|
] }),
|
|
5975
|
-
chartLines.length > 0 && /* @__PURE__ */ jsx13(
|
|
5976
|
-
/* @__PURE__ */ jsx13(
|
|
6751
|
+
chartLines.length > 0 && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { color: colorCode, children: line || " " }) }, i)) }),
|
|
6752
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
|
|
5977
6753
|
] });
|
|
5978
6754
|
}
|
|
5979
6755
|
|
|
5980
6756
|
// src/utils/scan-files.ts
|
|
5981
|
-
import { readdir as
|
|
5982
|
-
import { join as
|
|
6757
|
+
import { readdir as readdir6 } from "fs/promises";
|
|
6758
|
+
import { join as join9, relative as relative7 } from "path";
|
|
5983
6759
|
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
5984
6760
|
"node_modules",
|
|
5985
6761
|
".git",
|
|
@@ -6030,7 +6806,7 @@ async function scanProjectFiles(baseDir, dir) {
|
|
|
6030
6806
|
const currentDir = dir ?? baseDir;
|
|
6031
6807
|
let entries;
|
|
6032
6808
|
try {
|
|
6033
|
-
entries = await
|
|
6809
|
+
entries = await readdir6(currentDir, { withFileTypes: true });
|
|
6034
6810
|
} catch {
|
|
6035
6811
|
return [];
|
|
6036
6812
|
}
|
|
@@ -6044,12 +6820,12 @@ async function scanProjectFiles(baseDir, dir) {
|
|
|
6044
6820
|
} else if (entry.isFile()) {
|
|
6045
6821
|
const ext = name.slice(name.lastIndexOf(".")).toLowerCase();
|
|
6046
6822
|
if (SOURCE_EXTS.has(ext)) {
|
|
6047
|
-
files.push(relative7(baseDir,
|
|
6823
|
+
files.push(relative7(baseDir, join9(currentDir, name)));
|
|
6048
6824
|
}
|
|
6049
6825
|
}
|
|
6050
6826
|
}
|
|
6051
6827
|
const nested = await Promise.all(
|
|
6052
|
-
dirs.map((d) => scanProjectFiles(baseDir,
|
|
6828
|
+
dirs.map((d) => scanProjectFiles(baseDir, join9(currentDir, d)))
|
|
6053
6829
|
);
|
|
6054
6830
|
for (const n of nested) {
|
|
6055
6831
|
files.push(...n);
|
|
@@ -6137,10 +6913,10 @@ compdef _dskcode_completion dskcode`);
|
|
|
6137
6913
|
program2.command("stock").description("\u67E5\u770B\u81EA\u9009\u80A1\u5B9E\u65F6\u884C\u60C5").argument("[codes...]", "\u80A1\u7968\u4EE3\u7801\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u5982 513090 600519").action(async function(codes) {
|
|
6138
6914
|
const _ctx = this.dskcodeCtx;
|
|
6139
6915
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
|
|
6140
|
-
const globalConfigPath =
|
|
6916
|
+
const globalConfigPath = join10(home, ".dskcode", "settings.json");
|
|
6141
6917
|
let globalConfigHasStock = false;
|
|
6142
6918
|
try {
|
|
6143
|
-
const raw = await
|
|
6919
|
+
const raw = await readFile11(globalConfigPath, "utf-8");
|
|
6144
6920
|
const parsed = JSON.parse(raw);
|
|
6145
6921
|
const stock = parsed.stock;
|
|
6146
6922
|
globalConfigHasStock = Array.isArray(stock?.symbols) && stock.symbols.length > 0;
|