dskcode 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,15 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DeepSeekProvider,
4
- ModelNotSupportedError
5
- } from "./chunk-BA7UJPKJ.js";
6
- import {
4
+ ModelNotSupportedError,
7
5
  SUPPORTED_MODELS,
8
6
  calculateCost,
9
7
  estimateTokens,
10
8
  getModelMeta,
11
9
  isSupportedModel
12
- } from "./chunk-7QS2XBBX.js";
10
+ } from "./chunk-I6HEIOSU.js";
13
11
 
14
12
  // src/cli/index.tsx
15
13
  import { Command } from "commander";
@@ -816,9 +814,9 @@ var LOGO_LINES = [
816
814
  ];
817
815
 
818
816
  // src/ui/ChatSession.tsx
819
- import { Box as Box8, Text as Text9, useInput, Static } from "ink";
817
+ import { Box as Box8, Text as Text10, useInput, Static } from "ink";
820
818
  import TextInput from "ink-text-input";
821
- import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useRef as useRef2 } from "react";
819
+ import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useMemo, useRef as useRef2 } from "react";
822
820
 
823
821
  // src/ui/useDoubleCtrlC.ts
824
822
  import { useState as useState2, useCallback, useEffect as useEffect2, useRef } from "react";
@@ -848,8 +846,11 @@ function useDoubleCtrlC(onExit) {
848
846
  return { doubleCtrlC, handleCtrlC };
849
847
  }
850
848
 
849
+ // src/ui/ChatSession.tsx
850
+ import InkSpinner2 from "ink-spinner";
851
+
851
852
  // src/ui/AssistantMessage.tsx
852
- import { Box as Box4, Text as Text5 } from "ink";
853
+ import { Box as Box4, Text as Text6 } from "ink";
853
854
 
854
855
  // src/provider/cost-tracker.ts
855
856
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
@@ -1255,8 +1256,82 @@ function formatUsageSummary(usage) {
1255
1256
  return summary;
1256
1257
  }
1257
1258
 
1259
+ // src/ui/HighlightedText.tsx
1260
+ import { Text as Text5 } from "ink";
1261
+ import { jsx as jsx4 } from "react/jsx-runtime";
1262
+ function parseBoldPairs(text) {
1263
+ const segments = [];
1264
+ let current = 0;
1265
+ while (current < text.length) {
1266
+ const openIdx = text.indexOf("**", current);
1267
+ if (openIdx === -1) {
1268
+ segments.push({ text: text.slice(current), type: "plain" });
1269
+ break;
1270
+ }
1271
+ if (openIdx > current) {
1272
+ segments.push({ text: text.slice(current, openIdx), type: "plain" });
1273
+ }
1274
+ const closeIdx = text.indexOf("**", openIdx + 2);
1275
+ if (closeIdx === -1) {
1276
+ segments.push({ text: text.slice(openIdx), type: "plain" });
1277
+ break;
1278
+ }
1279
+ segments.push({ text: text.slice(openIdx + 2, closeIdx), type: "bold" });
1280
+ current = closeIdx + 2;
1281
+ }
1282
+ return segments;
1283
+ }
1284
+ function parseCodePairs(segments) {
1285
+ const result = [];
1286
+ for (const seg of segments) {
1287
+ if (seg.type !== "plain") {
1288
+ result.push(seg);
1289
+ continue;
1290
+ }
1291
+ let current = 0;
1292
+ const text = seg.text;
1293
+ while (current < text.length) {
1294
+ const openIdx = text.indexOf("`", current);
1295
+ if (openIdx === -1) {
1296
+ result.push({ text: text.slice(current), type: "plain" });
1297
+ break;
1298
+ }
1299
+ if (openIdx > current) {
1300
+ result.push({ text: text.slice(current, openIdx), type: "plain" });
1301
+ }
1302
+ const closeIdx = text.indexOf("`", openIdx + 1);
1303
+ if (closeIdx === -1) {
1304
+ result.push({ text: text.slice(openIdx), type: "plain" });
1305
+ break;
1306
+ }
1307
+ result.push({ text: text.slice(openIdx + 1, closeIdx), type: "code" });
1308
+ current = closeIdx + 1;
1309
+ }
1310
+ }
1311
+ return result;
1312
+ }
1313
+ var CODE_COLOR = "#00BFFF";
1314
+ var BOLD_COLOR = "#A855F7";
1315
+ function HighlightedText({ children: text }) {
1316
+ const boldSegments = parseBoldPairs(text);
1317
+ const segments = parseCodePairs(boldSegments);
1318
+ const isSimple = segments.length === 1 && segments[0].type === "plain";
1319
+ if (isSimple) {
1320
+ return /* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: text });
1321
+ }
1322
+ return /* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: segments.map((seg, i) => {
1323
+ if (seg.type === "code") {
1324
+ return /* @__PURE__ */ jsx4(Text5, { color: CODE_COLOR, children: seg.text }, i);
1325
+ }
1326
+ if (seg.type === "bold") {
1327
+ return /* @__PURE__ */ jsx4(Text5, { color: BOLD_COLOR, children: seg.text }, i);
1328
+ }
1329
+ return seg.text;
1330
+ }) });
1331
+ }
1332
+
1258
1333
  // src/ui/AssistantMessage.tsx
1259
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1334
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1260
1335
  function formatElapsed(ms) {
1261
1336
  if (ms < 1e3) return `${ms}ms`;
1262
1337
  const seconds = (ms / 1e3).toFixed(1);
@@ -1276,33 +1351,33 @@ function AssistantMessage({
1276
1351
  }
1277
1352
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
1278
1353
  /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", children: [
1279
- /* @__PURE__ */ jsx4(Box4, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx4(Text5, { bold: true, color: "#ff00ff", children: "\u{1F916}" }) }),
1354
+ /* @__PURE__ */ jsx5(Box4, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx5(Text6, { bold: true, color: "#ff00ff", children: "\u{1F916}" }) }),
1280
1355
  /* @__PURE__ */ jsxs4(Box4, { flexGrow: 1, flexDirection: "column", children: [
1281
- content && /* @__PURE__ */ jsx4(Text5, { wrap: "wrap", children: content }),
1282
- isStreaming && !content && /* @__PURE__ */ jsx4(Text5, { color: "#888888", children: "..." })
1356
+ content && /* @__PURE__ */ jsx5(HighlightedText, { children: content }),
1357
+ isStreaming && !content && /* @__PURE__ */ jsx5(Text6, { color: "#888888", children: "..." })
1283
1358
  ] })
1284
1359
  ] }),
1285
- toolCalls && toolCalls.length > 0 && /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: toolCalls.map((tc, i) => /* @__PURE__ */ jsx4(ToolCallBlock, { call: tc }, tc.id ?? i)) }),
1360
+ toolCalls && toolCalls.length > 0 && /* @__PURE__ */ jsx5(Box4, { flexDirection: "column", children: toolCalls.map((tc, i) => /* @__PURE__ */ jsx5(ToolCallBlock, { call: tc }, tc.id ?? i)) }),
1286
1361
  !isStreaming && (usage || elapsed !== void 0) && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, marginLeft: 3, children: [
1287
- /* @__PURE__ */ jsx4(Text5, { color: "#555555", children: "\u2500".repeat(36) }),
1362
+ /* @__PURE__ */ jsx5(Text6, { color: "#555555", children: "\u2500".repeat(36) }),
1288
1363
  /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", gap: 2, children: [
1289
- cost !== void 0 && cost > 0 && /* @__PURE__ */ jsxs4(Text5, { color: "yellow", children: [
1364
+ cost !== void 0 && cost > 0 && /* @__PURE__ */ jsxs4(Text6, { color: "yellow", children: [
1290
1365
  "\u{1F4B0} \u672C\u6B21 ",
1291
1366
  formatMoney(cost)
1292
1367
  ] }),
1293
- elapsed !== void 0 && /* @__PURE__ */ jsxs4(Text5, { color: "cyan", children: [
1368
+ elapsed !== void 0 && /* @__PURE__ */ jsxs4(Text6, { color: "cyan", children: [
1294
1369
  "\u{1F550} ",
1295
1370
  formatElapsed(elapsed)
1296
1371
  ] }),
1297
- usage && /* @__PURE__ */ jsx4(Text5, { color: "#888888", children: formatUsageSummary(usage) })
1372
+ usage && /* @__PURE__ */ jsx5(Text6, { color: "#888888", children: formatUsageSummary(usage) })
1298
1373
  ] })
1299
1374
  ] })
1300
1375
  ] });
1301
1376
  }
1302
1377
 
1303
1378
  // src/ui/DiffPreview.tsx
1304
- import { Box as Box5, Text as Text6 } from "ink";
1305
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1379
+ import { Box as Box5, Text as Text7 } from "ink";
1380
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1306
1381
  function DiffPreview({ diff }) {
1307
1382
  const { patch, additions, deletions, existedBefore, filePath } = diff;
1308
1383
  if (!patch || patch.length === 0) {
@@ -1312,13 +1387,13 @@ function DiffPreview({ diff }) {
1312
1387
  const fileName = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
1313
1388
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1314
1389
  /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
1315
- /* @__PURE__ */ jsxs5(Text6, { bold: true, color: "#00ffff", children: [
1390
+ /* @__PURE__ */ jsxs5(Text7, { bold: true, color: "#00ffff", children: [
1316
1391
  "\u{1F4DD} ",
1317
1392
  existedBefore ? "\u4FEE\u6539" : "\u65B0\u5EFA",
1318
1393
  ":"
1319
1394
  ] }),
1320
- /* @__PURE__ */ jsx5(Text6, { bold: true, children: fileName }),
1321
- /* @__PURE__ */ jsxs5(Text6, { color: "#555555", children: [
1395
+ /* @__PURE__ */ jsx6(Text7, { bold: true, children: fileName }),
1396
+ /* @__PURE__ */ jsxs5(Text7, { color: "#555555", children: [
1322
1397
  "(+",
1323
1398
  additions,
1324
1399
  " -",
@@ -1326,7 +1401,7 @@ function DiffPreview({ diff }) {
1326
1401
  ")"
1327
1402
  ] })
1328
1403
  ] }),
1329
- /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginLeft: 2, children: lines.filter((line) => !line.startsWith("---") && !line.startsWith("+++")).map((line, i) => /* @__PURE__ */ jsx5(DiffLine, { line }, i)) })
1404
+ /* @__PURE__ */ jsx6(Box5, { flexDirection: "column", marginLeft: 2, children: lines.filter((line) => !line.startsWith("---") && !line.startsWith("+++")).map((line, i) => /* @__PURE__ */ jsx6(DiffLine, { line }, i)) })
1330
1405
  ] });
1331
1406
  }
1332
1407
  function DiffLine({ line }) {
@@ -1334,20 +1409,20 @@ function DiffLine({ line }) {
1334
1409
  return null;
1335
1410
  }
1336
1411
  if (line.startsWith("@@")) {
1337
- return /* @__PURE__ */ jsx5(Text6, { color: "#00cccc", children: line });
1412
+ return /* @__PURE__ */ jsx6(Text7, { color: "#00cccc", children: line });
1338
1413
  }
1339
1414
  if (line.startsWith("+")) {
1340
- return /* @__PURE__ */ jsx5(Text6, { color: "#22c55e", children: line });
1415
+ return /* @__PURE__ */ jsx6(Text7, { color: "#22c55e", children: line });
1341
1416
  }
1342
1417
  if (line.startsWith("-")) {
1343
- return /* @__PURE__ */ jsx5(Text6, { color: "#ef4444", children: line });
1418
+ return /* @__PURE__ */ jsx6(Text7, { color: "#ef4444", children: line });
1344
1419
  }
1345
- return /* @__PURE__ */ jsx5(Text6, { color: "#6b7280", children: line });
1420
+ return /* @__PURE__ */ jsx6(Text7, { color: "#6b7280", children: line });
1346
1421
  }
1347
1422
 
1348
1423
  // src/ui/SkillSelector.tsx
1349
- import { Box as Box6, Text as Text7 } from "ink";
1350
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1424
+ import { Box as Box6, Text as Text8 } from "ink";
1425
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1351
1426
  var HIGHLIGHT_COLOR = "#00bfff";
1352
1427
  function SkillSelector({ skills, input, selectedIndex }) {
1353
1428
  const match = input.match(/(?:^|\s)\/([^/]*)$/);
@@ -1358,18 +1433,18 @@ function SkillSelector({ skills, input, selectedIndex }) {
1358
1433
  if (query && matched.length > 0 && matched.some((s) => s.name.toLowerCase() === query)) return null;
1359
1434
  if (matched.length === 0) return null;
1360
1435
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1361
- /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
1362
- matched.map((skill, i) => /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text7, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
1436
+ /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
1437
+ matched.map((skill, i) => /* @__PURE__ */ jsx7(Box6, { children: /* @__PURE__ */ jsxs6(Text8, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
1363
1438
  i === selectedIndex ? " \u203A " : " ",
1364
1439
  skill.name
1365
1440
  ] }) }, skill.name)),
1366
- /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1441
+ /* @__PURE__ */ jsx7(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1367
1442
  ] });
1368
1443
  }
1369
1444
 
1370
1445
  // src/ui/FileSelector.tsx
1371
- import { Box as Box7, Text as Text8 } from "ink";
1372
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1446
+ import { Box as Box7, Text as Text9 } from "ink";
1447
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1373
1448
  var HIGHLIGHT_COLOR2 = "#00ff41";
1374
1449
  function FileSelector({ files, input, selectedIndex }) {
1375
1450
  const match = input.match(/(?:^|\s)@([^@]*)$/);
@@ -1380,12 +1455,12 @@ function FileSelector({ files, input, selectedIndex }) {
1380
1455
  if (query && matched.some((f) => f.toLowerCase() === query)) return null;
1381
1456
  if (matched.length === 0) return null;
1382
1457
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1383
- /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
1384
- matched.map((file, i) => /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
1458
+ /* @__PURE__ */ jsx8(Text9, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
1459
+ matched.map((file, i) => /* @__PURE__ */ jsx8(Box7, { children: /* @__PURE__ */ jsxs7(Text9, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
1385
1460
  i === selectedIndex ? " \u203A " : " ",
1386
1461
  file
1387
1462
  ] }) }, file)),
1388
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1463
+ /* @__PURE__ */ jsx8(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1389
1464
  ] });
1390
1465
  }
1391
1466
 
@@ -1440,116 +1515,111 @@ function createProvider(config) {
1440
1515
  return defaultRegistry.get(config.name, config);
1441
1516
  }
1442
1517
 
1443
- // src/agent/extra-prompt.ts
1444
- var EXTRA_PROMPT = [
1445
- "\u3010\u7EC8\u7AEF\u8F93\u51FA\u7EA6\u675F\u3011",
1446
- "",
1447
- "\u4F60\u7684\u56DE\u590D\u5C06\u76F4\u63A5\u6E32\u67D3\u5728\u7528\u6237\u7EC8\u7AEF\u7684\u547D\u4EE4\u884C\u754C\u9762\u4E2D\uFF0C\u4E0D\u652F\u6301 Markdown \u6E32\u67D3\u3002",
1448
- "\u8BF7\u4E25\u683C\u9075\u5B88\u4EE5\u4E0B\u683C\u5F0F\u89C4\u5219\u3002",
1449
- "",
1450
- "\u4E00\u3001\u7981\u6B62\u4F7F\u7528\u7684\u7B26\u53F7",
1451
- " - \u4E0D\u8981\u4F7F\u7528 Markdown \u6807\u9898\u7B26\u53F7\uFF08\u5355\u72EC\u6216\u8FDE\u7EED\u7684\u4E95\u53F7\uFF09",
1452
- " - \u4E0D\u8981\u4F7F\u7528\u7C97\u4F53\u6216\u659C\u4F53\u7B26\u53F7\uFF08\u661F\u53F7\u3001\u4E0B\u5212\u7EBF\uFF09",
1453
- " - \u4E0D\u8981\u4F7F\u7528\u4EE3\u7801\u5757\u6807\u8BB0\uFF08\u8FDE\u7EED\u4E09\u4E2A\u53CD\u5F15\u53F7\uFF09",
1454
- " - \u4E0D\u8981\u4F7F\u7528\u5757\u5F15\u7528\u7B26\u53F7\uFF08\u5927\u4E8E\u53F7\uFF09",
1455
- " - \u4E0D\u8981\u4F7F\u7528\u5206\u9694\u7EBF\uFF08\u8FDE\u7EED\u4E09\u4E2A\u51CF\u53F7\u6216\u661F\u53F7\uFF09",
1456
- " - \u4E0D\u8981\u4F7F\u7528\u884C\u5185\u4EE3\u7801\u6807\u8BB0\uFF08\u5355\u4E2A\u53CD\u5F15\u53F7\uFF09",
1457
- "",
1458
- "\u4E8C\u3001\u63A8\u8350\u7684\u7EC4\u7EC7\u65B9\u5F0F",
1459
- ' - \u7528\u7EAF\u6587\u5B57\u63CF\u8FF0\u5C42\u7EA7\uFF0C\u4F8B\u5982"\u7B2C\u4E00\u70B9"\u3001"\u7B2C\u4E8C\u70B9"\u66FF\u4EE3\u6807\u9898\u7B26\u53F7',
1460
- " - \u7528 emoji \u7B26\u53F7\u505A\u89C6\u89C9\u6807\u8BB0\uFF08\u5982 \u{1F4CC} \u{1F4E6} \u{1F4DD} \u26A0\uFE0F \u7B49\uFF09",
1461
- " - \u7528\u6570\u5B57\u5E8F\u53F7\uFF081. 2. 3.\uFF09\u7EC4\u7EC7\u5217\u8868",
1462
- " - \u4EE3\u7801\u793A\u4F8B\u7528\u7F29\u8FDB\uFF08\u6BCF\u884C\u524D\u52A0 4 \u4E2A\u7A7A\u683C\uFF09\u66FF\u4EE3\u4EE3\u7801\u5757\u6807\u8BB0",
1463
- " - \u6587\u4EF6\u8DEF\u5F84\u3001\u547D\u4EE4\u3001\u53D8\u91CF\u540D\u76F4\u63A5\u4E66\u5199\uFF0C\u4E0D\u8981\u7528\u4EFB\u4F55\u7B26\u53F7\u5305\u88F9",
1464
- "",
1465
- "\u4E09\u3001\u6B63\u786E\u683C\u5F0F\u793A\u4F8B",
1466
- "",
1467
- " \u7B2C\u4E00\u70B9\uFF1A\u4F18\u5316\u6570\u636E\u5E93\u67E5\u8BE2",
1468
- " 1. \u6DFB\u52A0\u7D22\u5F15\u5230 user_id \u5B57\u6BB5",
1469
- " 2. \u7528\u8FDE\u63A5\u6C60\u66FF\u4EE3\u77ED\u8FDE\u63A5",
1470
- "",
1471
- " \u4EE3\u7801\u793A\u4F8B\uFF1A",
1472
- " const pool = new Pool({ max: 20 });",
1473
- ' await pool.query("SELECT * FROM users");',
1474
- "",
1475
- " \u8F93\u51FA\u63D0\u793A\uFF1A",
1476
- " \u{1F4CC} \u4F18\u5316\u524D\uFF1A\u67E5\u8BE2\u8017\u65F6 3.2 \u79D2",
1477
- "",
1478
- "\u56DB\u3001\u9519\u8BEF\u683C\u5F0F\u793A\u4F8B\uFF08\u7981\u6B62\u8FD9\u6837\u5199\uFF09",
1479
- "",
1480
- " \u4E95\u53F7\u4E32 \u4F18\u5316\u6570\u636E\u5E93\u67E5\u8BE2\uFF08\u8FD9\u662F\u9519\u8BEF\u7684\uFF09",
1481
- " \u661F\u53F7 \u6DFB\u52A0\u7D22\u5F15\u5230 user_id \u5B57\u6BB5\uFF08\u8FD9\u662F\u9519\u8BEF\u7684\uFF09",
1482
- " \u4E09\u4E2A\u53CD\u5F15\u53F7\u5F00\u59CB\u6216\u7ED3\u675F\uFF08\u8FD9\u662F\u9519\u8BEF\u7684\uFF09",
1483
- "",
1484
- "\u6CE8\u610F\uFF1A\u4E0A\u8FF0\u793A\u4F8B\u4E2D\u7684\u9519\u8BEF\u5199\u6CD5\u4EC5\u4F5C\u4E3A\u8BF4\u660E\uFF0C\u4F60\u7684\u56DE\u590D\u4E2D\u4E0D\u8981\u51FA\u73B0\u8FD9\u4E9B\u683C\u5F0F\u3002"
1485
- ].join("\n");
1518
+ // src/tool/types.ts
1519
+ function eraseTool(tool) {
1520
+ return {
1521
+ get name() {
1522
+ return tool.name;
1523
+ },
1524
+ get description() {
1525
+ return tool.description;
1526
+ },
1527
+ get kind() {
1528
+ return tool.kind;
1529
+ },
1530
+ get parameters() {
1531
+ return tool.parameters;
1532
+ },
1533
+ get supportsInputStreaming() {
1534
+ return tool.supportsInputStreaming ?? false;
1535
+ },
1536
+ get supportedProviders() {
1537
+ return tool.supportedProviders ?? [];
1538
+ },
1539
+ async execute(args, ctx) {
1540
+ return tool.execute(args, ctx);
1541
+ },
1542
+ initialTitle(args) {
1543
+ return tool.initialTitle?.(args) ?? `${tool.name}`;
1544
+ }
1545
+ };
1546
+ }
1547
+ function isReadOnly(kind) {
1548
+ return kind === "read" /* Read */;
1549
+ }
1550
+ var AlwaysAllowGate = class {
1551
+ check(_toolName, _args) {
1552
+ return true;
1553
+ }
1554
+ };
1486
1555
 
1487
1556
  // src/agent/system-prompt.ts
1488
- function buildSystemPrompt(opts) {
1489
- const sections = [];
1490
- sections.push(`\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
1557
+ import Handlebars from "handlebars";
1491
1558
 
1492
- ## \u6838\u5FC3\u539F\u5219
1493
- - \u56DE\u7B54\u4F7F\u7528\u4E2D\u6587\uFF0C\u4EE3\u7801\u6807\u8BC6\u7B26\u4FDD\u6301\u82F1\u6587
1494
- - \u63D0\u4F9B\u51C6\u786E\u3001\u5B9E\u7528\u3001\u53EF\u64CD\u4F5C\u7684\u5EFA\u8BAE
1495
- - \u5BF9\u4E0D\u786E\u5B9A\u7684\u5185\u5BB9\u660E\u786E\u6807\u6CE8\uFF0C\u4E0D\u7F16\u9020\u4E8B\u5B9E
1496
- - \u4EE3\u7801\u793A\u4F8B\u4FDD\u6301\u7B80\u6D01\uFF0C\u9644\u5E26\u5FC5\u8981\u7684\u6CE8\u91CA`);
1497
- sections.push(`## \u5F53\u524D\u6A21\u578B
1498
- - \u6A21\u578B\uFF1A${opts.model}`);
1559
+ // src/agent/prompts/system-prompt.hbs
1560
+ 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\uFF0C\u4E0D\u8981\u7528\u6807\u9898\u7B26\u53F7\r\n\r\n\u6B63\u786E\u793A\u4F8B\uFF1A\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';
1561
+
1562
+ // src/agent/system-prompt.ts
1563
+ var compiledTemplate = Handlebars.compile(system_prompt_default);
1564
+ function formatTools(tools) {
1565
+ return tools.map((t) => {
1566
+ const params = t.parameters && Object.keys(t.parameters.properties ?? {}).join(", ");
1567
+ return {
1568
+ name: t.name,
1569
+ description: t.description,
1570
+ params: params || void 0
1571
+ };
1572
+ });
1573
+ }
1574
+ function buildSystemPrompt(opts) {
1499
1575
  const now = /* @__PURE__ */ new Date();
1500
- const dateStr = now.toLocaleDateString("zh-CN", {
1576
+ const date = now.toLocaleDateString("zh-CN", {
1501
1577
  year: "numeric",
1502
1578
  month: "long",
1503
1579
  day: "numeric",
1504
1580
  weekday: "long"
1505
1581
  });
1506
- const timeStr = now.toLocaleTimeString("zh-CN", {
1582
+ const time = now.toLocaleTimeString("zh-CN", {
1507
1583
  hour: "2-digit",
1508
1584
  minute: "2-digit"
1509
1585
  });
1510
- sections.push(`## \u65F6\u95F4\u4E0A\u4E0B\u6587
1511
- - \u5F53\u524D\u65E5\u671F\uFF1A${dateStr}
1512
- - \u5F53\u524D\u65F6\u95F4\uFF1A${timeStr}
1513
- - \u5DE5\u4F5C\u76EE\u5F55\uFF1A${opts.cwd}`);
1514
- if (opts.tools && opts.tools.length > 0) {
1515
- const toolLines = opts.tools.map((t) => {
1516
- const paramInfo = t.parameters ? Object.keys(t.parameters.properties ?? {}).join(", ") : "";
1517
- return `- **${t.name}**\uFF1A${t.description}${paramInfo ? `\uFF08\u53C2\u6570\uFF1A${paramInfo}\uFF09` : ""}`;
1518
- }).join("\n");
1519
- sections.push(`## \u53EF\u7528\u5DE5\u5177
1520
-
1521
- \u4F60\u53EF\u4EE5\u901A\u8FC7\u5DE5\u5177\u8C03\u7528\u6267\u884C\u64CD\u4F5C\u3002\u5F53\u524D\u53EF\u7528\u7684\u5DE5\u5177\uFF1A
1522
-
1523
- ${toolLines}
1524
-
1525
- \u8C03\u7528\u5DE5\u5177\u65F6\uFF0C\u8BF7\u4F7F\u7528\u6807\u51C6 function_call \u683C\u5F0F\u3002\u5DE5\u5177\u5C06\u7531\u7CFB\u7EDF\u6267\u884C\u5E76\u8FD4\u56DE\u7ED3\u679C\u3002`);
1526
- }
1527
- if (opts.projectContext) {
1528
- sections.push(`## \u9879\u76EE\u4E0A\u4E0B\u6587
1529
-
1530
- ${opts.projectContext}`);
1531
- }
1532
- sections.push(`## \u884C\u4E3A\u7EA6\u675F
1533
- - \u5982\u679C\u7528\u6237\u8BF7\u6C42\u4E0D\u660E\u786E\uFF0C\u8BF7\u4E3B\u52A8\u8BE2\u95EE\u6F84\u6E05
1534
- - \u6D89\u53CA\u6587\u4EF6\u64CD\u4F5C\u65F6\uFF0C\u5148\u786E\u8BA4\u6587\u4EF6\u8DEF\u5F84
1535
- - \u4E0D\u6267\u884C\u53EF\u80FD\u9020\u6210\u4E0D\u53EF\u9006\u635F\u5BB3\u7684\u64CD\u4F5C\uFF08\u5982 rm -rf\uFF09\u9664\u975E\u7528\u6237\u660E\u786E\u786E\u8BA4
1536
- - \u5F53\u5DE5\u5177\u8C03\u7528\u8FD4\u56DE\u9519\u8BEF\u65F6\uFF0C\u5206\u6790\u539F\u56E0\u5E76\u5C1D\u8BD5\u4FEE\u590D`);
1537
- sections.push(EXTRA_PROMPT);
1538
- return sections.join("\n\n");
1586
+ return compiledTemplate({
1587
+ model: opts.model,
1588
+ maxToolRounds: opts.maxToolRounds,
1589
+ cwd: opts.cwd,
1590
+ date,
1591
+ time,
1592
+ tools: opts.tools ? formatTools(opts.tools) : void 0,
1593
+ projectContext: opts.projectContext ?? void 0
1594
+ });
1539
1595
  }
1540
1596
 
1541
1597
  // src/tool/registry.ts
1542
1598
  var ToolRegistry = class {
1543
1599
  #tools = /* @__PURE__ */ new Map();
1544
1600
  #disabledNames;
1601
+ #featureFlagChecker;
1602
+ #provider;
1603
+ /** 所有已注册工具的名称列表(编译期等效) */
1604
+ static ALL_TOOL_NAMES = [];
1545
1605
  constructor(opts) {
1546
1606
  this.#disabledNames = new Set(opts?.disabledTools ?? []);
1607
+ this.#featureFlagChecker = opts?.featureFlagChecker ?? (() => true);
1608
+ this.#provider = opts?.provider;
1547
1609
  }
1548
1610
  /**
1549
- * 注册一个工具。
1611
+ * 注册一个类型安全的 AgentTool。
1612
+ * 自动擦除类型参数后存储。
1550
1613
  * 如果同名工具已存在则抛出错误。
1551
1614
  */
1552
1615
  register(tool) {
1616
+ return this.registerErased(eraseTool(tool));
1617
+ }
1618
+ /**
1619
+ * 注册一个已经擦除类型 AnyAgentTool。
1620
+ * 如果同名工具已存在则抛出错误。
1621
+ */
1622
+ registerErased(tool) {
1553
1623
  if (this.#tools.has(tool.name)) {
1554
1624
  throw new Error(`\u5DE5\u5177 "${tool.name}" \u5DF2\u6CE8\u518C\uFF0C\u4E0D\u80FD\u91CD\u590D\u6CE8\u518C`);
1555
1625
  }
@@ -1561,7 +1631,7 @@ var ToolRegistry = class {
1561
1631
  */
1562
1632
  registerAll(tools) {
1563
1633
  for (const tool of tools) {
1564
- this.register(tool);
1634
+ this.registerErased(tool);
1565
1635
  }
1566
1636
  return this;
1567
1637
  }
@@ -1572,25 +1642,44 @@ var ToolRegistry = class {
1572
1642
  return this.#tools.delete(name);
1573
1643
  }
1574
1644
  /**
1575
- * 按名称获取工具。
1576
- * 如果工具被禁用或不存在,返回 undefined。
1645
+ * 按名称获取工具(未擦除类型版本,调用方自行断言类型)。
1646
+ * 如果工具被禁用、被 feature flag 拦截、或不支持当前 provider,返回 undefined。
1577
1647
  */
1578
1648
  get(name) {
1579
- if (this.#disabledNames.has(name)) return void 0;
1649
+ if (!this.#isToolEnabled(name)) return void 0;
1580
1650
  return this.#tools.get(name);
1581
1651
  }
1582
1652
  /**
1583
1653
  * 获取所有启用的工具列表。
1654
+ * 依次应用:禁用列表 → Feature Flag → Provider 过滤。
1584
1655
  */
1585
1656
  list() {
1586
1657
  const result = [];
1587
1658
  for (const [name, tool] of this.#tools) {
1588
- if (!this.#disabledNames.has(name)) {
1659
+ if (this.#isToolEnabled(name)) {
1589
1660
  result.push(tool);
1590
1661
  }
1591
1662
  }
1592
1663
  return result;
1593
1664
  }
1665
+ /**
1666
+ * 按 ToolKind 分类获取工具列表。
1667
+ */
1668
+ listByKind(kind) {
1669
+ return this.list().filter((t) => t.kind === kind);
1670
+ }
1671
+ /**
1672
+ * 获取读工具列表(可并行执行)。
1673
+ */
1674
+ listReadTools() {
1675
+ return this.listByKind("read" /* Read */);
1676
+ }
1677
+ /**
1678
+ * 获取写工具列表(需串行执行)。
1679
+ */
1680
+ listWriteTools() {
1681
+ return this.list().filter((t) => !isReadOnly(t.kind));
1682
+ }
1594
1683
  /**
1595
1684
  * 获取所有已注册的工具名称(含禁用的)。
1596
1685
  */
@@ -1604,10 +1693,10 @@ var ToolRegistry = class {
1604
1693
  return this.#tools.has(name);
1605
1694
  }
1606
1695
  /**
1607
- * 检查工具是否已启用。
1696
+ * 检查工具是否已启用(注册 + 未禁用 + 通过 feature flag + 支持 provider)。
1608
1697
  */
1609
1698
  isEnabled(name) {
1610
- return this.#tools.has(name) && !this.#disabledNames.has(name);
1699
+ return this.#tools.has(name) && this.#isToolEnabled(name);
1611
1700
  }
1612
1701
  /**
1613
1702
  * 禁用一个工具。
@@ -1621,6 +1710,12 @@ var ToolRegistry = class {
1621
1710
  enable(name) {
1622
1711
  this.#disabledNames.delete(name);
1623
1712
  }
1713
+ /**
1714
+ * 获取工具的分类语义。
1715
+ */
1716
+ kindOf(name) {
1717
+ return this.#tools.get(name)?.kind;
1718
+ }
1624
1719
  /**
1625
1720
  * 执行指定工具。
1626
1721
  *
@@ -1646,11 +1741,21 @@ var ToolRegistry = class {
1646
1741
  };
1647
1742
  }
1648
1743
  }
1649
- };
1650
-
1651
- // src/tool/types.ts
1652
- var AlwaysAllowGate = class {
1653
- check(_toolName, _args) {
1744
+ // ---------------------------------------------------------------------------
1745
+ // 内部方法
1746
+ // ---------------------------------------------------------------------------
1747
+ /**
1748
+ * 判断工具是否应该启用。
1749
+ * 依次检查:是否在禁用列表 → 是否通过 Feature Flag → 是否支持当前 Provider。
1750
+ */
1751
+ #isToolEnabled(name) {
1752
+ const tool = this.#tools.get(name);
1753
+ if (!tool) return false;
1754
+ if (this.#disabledNames.has(name)) return false;
1755
+ if (!this.#featureFlagChecker(name)) return false;
1756
+ if (this.#provider && tool.supportedProviders.length > 0) {
1757
+ if (!tool.supportedProviders.includes(this.#provider)) return false;
1758
+ }
1654
1759
  return true;
1655
1760
  }
1656
1761
  };
@@ -1718,7 +1823,7 @@ var Session = class {
1718
1823
  * d. 如果没有工具调用 → 退出循环
1719
1824
  * 3. yield done 事件
1720
1825
  */
1721
- async *chat(userInput) {
1826
+ async *chat(userInput, opts) {
1722
1827
  this.#messages.push({ role: "user", content: userInput });
1723
1828
  const startTime = Date.now();
1724
1829
  let toolRounds = 0;
@@ -1738,7 +1843,11 @@ var Session = class {
1738
1843
  const toolDefs = this.#buildToolDefinitions();
1739
1844
  const stream = this.#provider.chat(apiMessages, {
1740
1845
  signal: this.#abortController.signal,
1741
- tools: toolDefs.length > 0 ? toolDefs : void 0
1846
+ tools: toolDefs.length > 0 ? toolDefs : void 0,
1847
+ thinkingAllowed: opts?.thinkingAllowed,
1848
+ thinkingEffort: opts?.thinkingEffort,
1849
+ responseFormat: opts?.responseFormat,
1850
+ toolChoice: opts?.toolChoice
1742
1851
  });
1743
1852
  let accumulatedText = "";
1744
1853
  let lastUsage;
@@ -1840,7 +1949,7 @@ ${item.result.diff.patch}`;
1840
1949
  };
1841
1950
  const allReadOnly = calls.every((tc) => {
1842
1951
  const tool = this.#toolRegistry.get(tc.name);
1843
- return tool?.readOnly === true;
1952
+ return tool ? isReadOnly(tool.kind) : true;
1844
1953
  });
1845
1954
  if (allReadOnly && calls.length > 1) {
1846
1955
  const MAX_PARALLEL = 8;
@@ -1894,11 +2003,11 @@ ${item.result.diff.patch}`;
1894
2003
  record: { name: toolName, success: false, error: "GATE_DENIED", timestamp }
1895
2004
  };
1896
2005
  }
1897
- if (!tool.readOnly) {
1898
- const maybePreviewer = tool;
1899
- if (typeof maybePreviewer.preview === "function") {
2006
+ if (!isReadOnly(tool.kind)) {
2007
+ const maybePreview = tool.preview;
2008
+ if (typeof maybePreview === "function") {
1900
2009
  try {
1901
- await maybePreviewer.preview(toolArgs, ctx);
2010
+ await maybePreview(toolArgs, ctx);
1902
2011
  } catch {
1903
2012
  }
1904
2013
  }
@@ -1966,6 +2075,7 @@ ${item.result.diff.patch}`;
1966
2075
  }));
1967
2076
  const opts = {
1968
2077
  model: this.#provider.model(),
2078
+ maxToolRounds: this.#options.maxToolRounds,
1969
2079
  tools: toolDescs.length > 0 ? toolDescs : void 0,
1970
2080
  projectContext: this.#options.projectContext ?? void 0,
1971
2081
  cwd: this.#options.cwd
@@ -2413,25 +2523,6 @@ async function writeFileWithEol(filePath, originalContent, newContent) {
2413
2523
  import { readFile as readFile4, stat } from "fs/promises";
2414
2524
  import { open } from "fs/promises";
2415
2525
  import { relative as relative2 } from "path";
2416
- var readFileSchema = {
2417
- type: "object",
2418
- properties: {
2419
- path: {
2420
- type: "string",
2421
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2422
- },
2423
- startLine: {
2424
- type: "number",
2425
- description: "\u8D77\u59CB\u884C\u53F7\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u9ED8\u8BA4\u4E3A 1"
2426
- },
2427
- endLine: {
2428
- type: "number",
2429
- description: "\u7ED3\u675F\u884C\u53F7\uFF08\u5305\u542B\uFF09\uFF0C\u9ED8\u8BA4\u5230\u6587\u4EF6\u672B\u5C3E"
2430
- }
2431
- },
2432
- required: ["path"],
2433
- additionalProperties: false
2434
- };
2435
2526
  async function checkBinary(filePath) {
2436
2527
  const fileHandle = await open(filePath, "r");
2437
2528
  try {
@@ -2444,15 +2535,32 @@ async function checkBinary(filePath) {
2444
2535
  }
2445
2536
  var readFileTool = {
2446
2537
  name: "read_file",
2538
+ kind: "read" /* Read */,
2447
2539
  description: "\u8BFB\u53D6\u6307\u5B9A\u8DEF\u5F84\u7684\u6587\u4EF6\u5185\u5BB9\u3002\u652F\u6301\u884C\u53F7\u8303\u56F4\u9009\u62E9\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7\u3002\u9002\u7528\u4E8E\u67E5\u770B\u6E90\u4EE3\u7801\u3001\u914D\u7F6E\u6587\u4EF6\u7B49\u6587\u672C\u6587\u4EF6\u3002\u81EA\u52A8\u62D2\u7EDD\u4E8C\u8FDB\u5236\u6587\u4EF6\u3002",
2448
- parameters: readFileSchema,
2449
- readOnly: true,
2540
+ parameters: {
2541
+ type: "object",
2542
+ properties: {
2543
+ path: {
2544
+ type: "string",
2545
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2546
+ },
2547
+ startLine: {
2548
+ type: "number",
2549
+ description: "\u8D77\u59CB\u884C\u53F7\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u9ED8\u8BA4\u4E3A 1"
2550
+ },
2551
+ endLine: {
2552
+ type: "number",
2553
+ description: "\u7ED3\u675F\u884C\u53F7\uFF08\u5305\u542B\uFF09\uFF0C\u9ED8\u8BA4\u5230\u6587\u4EF6\u672B\u5C3E"
2554
+ }
2555
+ },
2556
+ required: ["path"],
2557
+ additionalProperties: false
2558
+ },
2450
2559
  async execute(args, ctx) {
2451
- const params = args;
2452
- if (!params?.path || typeof params.path !== "string") {
2560
+ if (!args?.path || typeof args.path !== "string") {
2453
2561
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2454
2562
  }
2455
- const filePath = resolvePath(params.path, ctx.cwd);
2563
+ const filePath = resolvePath(args.path, ctx.cwd);
2456
2564
  try {
2457
2565
  const fileStat = await stat(filePath);
2458
2566
  const maxSize = 10 * 1024 * 1024;
@@ -2485,8 +2593,8 @@ var readFileTool = {
2485
2593
  if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
2486
2594
  lines.pop();
2487
2595
  }
2488
- const startLine = Math.max(1, params.startLine ?? 1) - 1;
2489
- const endLine = params.endLine ? Math.min(params.endLine, lines.length) : lines.length;
2596
+ const startLine = Math.max(1, args.startLine ?? 1) - 1;
2597
+ const endLine = args.endLine ? Math.min(args.endLine, lines.length) : lines.length;
2490
2598
  const selectedLines = lines.slice(startLine, endLine);
2491
2599
  const lineNumWidth = String(endLine).length;
2492
2600
  const result = selectedLines.map((line, i) => {
@@ -2518,35 +2626,33 @@ var readFileTool = {
2518
2626
  // src/tool/builtins/write-file.ts
2519
2627
  import { mkdir as mkdir4, readFile as readFile5 } from "fs/promises";
2520
2628
  import { dirname, relative as relative3, basename } from "path";
2521
- var writeFileSchema = {
2522
- type: "object",
2523
- properties: {
2524
- path: {
2525
- type: "string",
2526
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2527
- },
2528
- content: {
2529
- type: "string",
2530
- description: "\u8981\u5199\u5165\u7684\u6587\u4EF6\u5185\u5BB9"
2531
- }
2532
- },
2533
- required: ["path", "content"],
2534
- additionalProperties: false
2535
- };
2536
2629
  var writeFileTool = {
2537
2630
  name: "write_file",
2631
+ kind: "edit" /* Edit */,
2538
2632
  description: "\u521B\u5EFA\u6216\u8986\u76D6\u6587\u4EF6\u3002\u5982\u679C\u7236\u76EE\u5F55\u4E0D\u5B58\u5728\u4F1A\u81EA\u52A8\u521B\u5EFA\u3002\u9002\u7528\u4E8E\u521B\u5EFA\u65B0\u6587\u4EF6\u6216\u5B8C\u5168\u66FF\u6362\u6587\u4EF6\u5185\u5BB9\u3002\u8BF7\u52FF\u7528\u6B64\u5DE5\u5177\u521B\u5EFA _temp_\u3001_debug_ \u7B49\u7528\u4E8E\u8BCA\u65AD/\u8C03\u8BD5\u7684\u4E34\u65F6\u6587\u4EF6\u2014\u2014\u5982\u9700\u8BCA\u65AD\u8BF7\u6539\u7528 bash \u5DE5\u5177\u5185\u8054\u811A\u672C\uFF08node -e\uFF09\u3002",
2539
- parameters: writeFileSchema,
2540
- readOnly: false,
2633
+ parameters: {
2634
+ type: "object",
2635
+ properties: {
2636
+ path: {
2637
+ type: "string",
2638
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2639
+ },
2640
+ content: {
2641
+ type: "string",
2642
+ description: "\u8981\u5199\u5165\u7684\u6587\u4EF6\u5185\u5BB9"
2643
+ }
2644
+ },
2645
+ required: ["path", "content"],
2646
+ additionalProperties: false
2647
+ },
2541
2648
  async execute(args, ctx) {
2542
- const params = args;
2543
- if (!params?.path || typeof params.path !== "string") {
2649
+ if (!args?.path || typeof args.path !== "string") {
2544
2650
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2545
2651
  }
2546
- if (params.content === void 0 || params.content === null) {
2652
+ if (args.content === void 0 || args.content === null) {
2547
2653
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 content", error: "INVALID_ARGS" };
2548
2654
  }
2549
- const filePath = resolvePath(params.path, ctx.cwd);
2655
+ const filePath = resolvePath(args.path, ctx.cwd);
2550
2656
  try {
2551
2657
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2552
2658
  const conf = await confine(ctx.writeRoots, filePath);
@@ -2562,7 +2668,7 @@ var writeFileTool = {
2562
2668
  } catch {
2563
2669
  }
2564
2670
  await mkdir4(dirname(filePath), { recursive: true });
2565
- const content = String(params.content);
2671
+ const content = String(args.content);
2566
2672
  await writeFileWithEol(filePath, oldContent, content);
2567
2673
  const diff = computeFileDiff(oldContent, content, filePath);
2568
2674
  diff.existedBefore = existedBefore;
@@ -2592,42 +2698,40 @@ var writeFileTool = {
2592
2698
  // src/tool/builtins/edit-file.ts
2593
2699
  import { readFile as readFile6 } from "fs/promises";
2594
2700
  import { basename as basename2 } from "path";
2595
- var editFileSchema = {
2596
- type: "object",
2597
- properties: {
2598
- path: {
2599
- type: "string",
2600
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2601
- },
2602
- old_text: {
2603
- type: "string",
2604
- description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09"
2605
- },
2606
- new_text: {
2607
- type: "string",
2608
- description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C"
2609
- }
2610
- },
2611
- required: ["path", "old_text", "new_text"],
2612
- additionalProperties: false
2613
- };
2614
2701
  var editFileTool = {
2615
2702
  name: "edit_file",
2703
+ kind: "edit" /* Edit */,
2616
2704
  description: "\u5BF9\u6587\u4EF6\u8FDB\u884C\u7CBE\u786E\u5B57\u7B26\u4E32\u66FF\u6362\u3002\u67E5\u627E\u6587\u4EF6\u4E2D\u7684 old_text \u5E76\u66FF\u6362\u4E3A new_text\u3002\u5982\u679C old_text \u51FA\u73B0\u591A\u6B21\u6216\u672A\u627E\u5230\u5219\u62A5\u9519\u3002\u9002\u7528\u4E8E\u5C0F\u8303\u56F4\u7CBE\u786E\u4FEE\u6539\u3002",
2617
- parameters: editFileSchema,
2618
- readOnly: false,
2705
+ parameters: {
2706
+ type: "object",
2707
+ properties: {
2708
+ path: {
2709
+ type: "string",
2710
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2711
+ },
2712
+ old_text: {
2713
+ type: "string",
2714
+ description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09"
2715
+ },
2716
+ new_text: {
2717
+ type: "string",
2718
+ description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C"
2719
+ }
2720
+ },
2721
+ required: ["path", "old_text", "new_text"],
2722
+ additionalProperties: false
2723
+ },
2619
2724
  async execute(args, ctx) {
2620
- const params = args;
2621
- if (!params?.path || typeof params.path !== "string") {
2725
+ if (!args?.path || typeof args.path !== "string") {
2622
2726
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2623
2727
  }
2624
- if (typeof params.old_text !== "string") {
2728
+ if (typeof args.old_text !== "string") {
2625
2729
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 old_text", error: "INVALID_ARGS" };
2626
2730
  }
2627
- if (typeof params.new_text !== "string") {
2731
+ if (typeof args.new_text !== "string") {
2628
2732
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 new_text", error: "INVALID_ARGS" };
2629
2733
  }
2630
- const filePath = resolvePath(params.path, ctx.cwd);
2734
+ const filePath = resolvePath(args.path, ctx.cwd);
2631
2735
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2632
2736
  const conf = await confine(ctx.writeRoots, filePath);
2633
2737
  if (!conf.ok) {
@@ -2636,7 +2740,7 @@ var editFileTool = {
2636
2740
  }
2637
2741
  try {
2638
2742
  const content = await readFile6(filePath, "utf-8");
2639
- const firstIndex = content.indexOf(params.old_text);
2743
+ const firstIndex = content.indexOf(args.old_text);
2640
2744
  if (firstIndex === -1) {
2641
2745
  return {
2642
2746
  success: false,
@@ -2644,7 +2748,7 @@ var editFileTool = {
2644
2748
  error: "TEXT_NOT_FOUND"
2645
2749
  };
2646
2750
  }
2647
- const secondIndex = content.indexOf(params.old_text, firstIndex + 1);
2751
+ const secondIndex = content.indexOf(args.old_text, firstIndex + 1);
2648
2752
  if (secondIndex !== -1) {
2649
2753
  return {
2650
2754
  success: false,
@@ -2652,14 +2756,14 @@ var editFileTool = {
2652
2756
  error: "TEXT_MULTIPLE_MATCHES"
2653
2757
  };
2654
2758
  }
2655
- const newContent = content.replace(params.old_text, params.new_text);
2759
+ const newContent = content.replace(args.old_text, args.new_text);
2656
2760
  await writeFileWithEol(filePath, content, newContent);
2657
2761
  const diff = computeFileDiff(content, newContent, filePath);
2658
2762
  diff.existedBefore = true;
2659
2763
  const beforeText = content.slice(0, firstIndex);
2660
2764
  const startLine = beforeText.split("\n").length;
2661
- const oldLines = params.old_text.split("\n").length;
2662
- const newLines = params.new_text.split("\n").length;
2765
+ const oldLines = args.old_text.split("\n").length;
2766
+ const newLines = args.new_text.split("\n").length;
2663
2767
  const diffSummary = `+${diff.additions} -${diff.deletions}`;
2664
2768
  const summary = `\u{1F4DD} \u4FEE\u6539: ${basename2(filePath)} (+${diff.additions} -${diff.deletions})`;
2665
2769
  return {
@@ -2685,45 +2789,43 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
2685
2789
  // src/tool/builtins/multi-edit.ts
2686
2790
  import { readFile as readFile7 } from "fs/promises";
2687
2791
  import { basename as basename3 } from "path";
2688
- var multiEditSchema = {
2689
- type: "object",
2690
- properties: {
2691
- path: {
2692
- type: "string",
2693
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2694
- },
2695
- edits: {
2696
- type: "array",
2697
- description: "\u6709\u5E8F\u7684\u7F16\u8F91\u6B65\u9AA4\u5217\u8868\u3002\u6BCF\u4E2A\u6B65\u9AA4\u5305\u542B oldText\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3001newText\uFF08\u66FF\u6362\u5185\u5BB9\uFF09\u548C\u53EF\u9009\u7684 replaceAll\uFF08\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF09",
2698
- items: {
2699
- type: "object",
2700
- properties: {
2701
- oldText: { type: "string", description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09" },
2702
- newText: { type: "string", description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C" },
2703
- replaceAll: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF0C\u9ED8\u8BA4 false" }
2704
- },
2705
- required: ["oldText", "newText"],
2706
- additionalProperties: false
2707
- }
2708
- }
2709
- },
2710
- required: ["path", "edits"],
2711
- additionalProperties: false
2712
- };
2713
2792
  var multiEditTool = {
2714
2793
  name: "multi_edit",
2794
+ kind: "edit" /* Edit */,
2715
2795
  description: "\u5BF9\u6587\u4EF6\u8FDB\u884C\u539F\u5B50\u6279\u91CF\u66FF\u6362\u7F16\u8F91\u3002\u5728\u4E00\u4E2A\u8BF7\u6C42\u4E2D\u6267\u884C\u591A\u4E2A\u7CBE\u786E\u66FF\u6362\uFF0C\u4EFB\u4E00\u5931\u8D25\u5219\u5168\u90E8\u56DE\u6EDA\u3002\u652F\u6301 replaceAll \u53C2\u6570\u505A\u5168\u5C40\u66FF\u6362\u3002\u9002\u7528\u4E8E\u9700\u8981\u540C\u65F6\u4FEE\u6539\u6587\u4EF6\u591A\u5904\u7684\u573A\u666F\u3002",
2716
- parameters: multiEditSchema,
2717
- readOnly: false,
2796
+ parameters: {
2797
+ type: "object",
2798
+ properties: {
2799
+ path: {
2800
+ type: "string",
2801
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2802
+ },
2803
+ edits: {
2804
+ type: "array",
2805
+ description: "\u6709\u5E8F\u7684\u7F16\u8F91\u6B65\u9AA4\u5217\u8868\u3002\u6BCF\u4E2A\u6B65\u9AA4\u5305\u542B oldText\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3001newText\uFF08\u66FF\u6362\u5185\u5BB9\uFF09\u548C\u53EF\u9009\u7684 replaceAll\uFF08\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF09",
2806
+ items: {
2807
+ type: "object",
2808
+ properties: {
2809
+ oldText: { type: "string", description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09" },
2810
+ newText: { type: "string", description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C" },
2811
+ replaceAll: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF0C\u9ED8\u8BA4 false" }
2812
+ },
2813
+ required: ["oldText", "newText"],
2814
+ additionalProperties: false
2815
+ }
2816
+ }
2817
+ },
2818
+ required: ["path", "edits"],
2819
+ additionalProperties: false
2820
+ },
2718
2821
  async execute(args, ctx) {
2719
- const params = args;
2720
- if (!params?.path || typeof params.path !== "string") {
2822
+ if (!args?.path || typeof args.path !== "string") {
2721
2823
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2722
2824
  }
2723
- if (!Array.isArray(params.edits) || params.edits.length === 0) {
2825
+ if (!Array.isArray(args.edits) || args.edits.length === 0) {
2724
2826
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 edits\uFF08\u975E\u7A7A\u6570\u7EC4\uFF09", error: "INVALID_ARGS" };
2725
2827
  }
2726
- const filePath = resolvePath(params.path, ctx.cwd);
2828
+ const filePath = resolvePath(args.path, ctx.cwd);
2727
2829
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2728
2830
  const conf = await confine(ctx.writeRoots, filePath);
2729
2831
  if (!conf.ok) {
@@ -2733,8 +2835,8 @@ var multiEditTool = {
2733
2835
  try {
2734
2836
  const originalContent = await readFile7(filePath, "utf-8");
2735
2837
  let currentContent = originalContent;
2736
- for (let idx = 0; idx < params.edits.length; idx++) {
2737
- const step = params.edits[idx];
2838
+ for (let idx = 0; idx < args.edits.length; idx++) {
2839
+ const step = args.edits[idx];
2738
2840
  if (typeof step.oldText !== "string") {
2739
2841
  return {
2740
2842
  success: false,
@@ -2782,9 +2884,9 @@ var multiEditTool = {
2782
2884
  return {
2783
2885
  success: true,
2784
2886
  data: `\u6587\u4EF6\u5DF2\u7F16\u8F91\uFF1A${filePath}
2785
- \u5171\u6267\u884C ${params.edits.length} \u6B65\u66FF\u6362
2887
+ \u5171\u6267\u884C ${args.edits.length} \u6B65\u66FF\u6362
2786
2888
  \u53D8\u66F4\uFF1A+${diff.additions} -${diff.deletions}`,
2787
- summary: `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (${params.edits.length} \u6B65, +${diff.additions} -${diff.deletions})`,
2889
+ summary: `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (${args.edits.length} \u6B65, +${diff.additions} -${diff.deletions})`,
2788
2890
  diff
2789
2891
  };
2790
2892
  } catch (err) {
@@ -2801,29 +2903,6 @@ var multiEditTool = {
2801
2903
  // src/tool/builtins/delete-range.ts
2802
2904
  import { readFile as readFile8 } from "fs/promises";
2803
2905
  import { basename as basename4 } from "path";
2804
- var deleteRangeSchema = {
2805
- type: "object",
2806
- properties: {
2807
- path: {
2808
- type: "string",
2809
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2810
- },
2811
- startAnchor: {
2812
- type: "string",
2813
- description: "\u5220\u9664\u8303\u56F4\u7684\u8D77\u59CB\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF09"
2814
- },
2815
- endAnchor: {
2816
- type: "string",
2817
- description: "\u5220\u9664\u8303\u56F4\u7684\u7ED3\u675F\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF0C\u987B\u5728 start_anchor \u4E4B\u540E\uFF09"
2818
- },
2819
- inclusive: {
2820
- type: "boolean",
2821
- description: "\u662F\u5426\u5305\u542B\u951A\u70B9\u884C\u672C\u8EAB\uFF0C\u9ED8\u8BA4 false\uFF08\u53EA\u5220\u9664\u4E24\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\uFF09"
2822
- }
2823
- },
2824
- required: ["path", "startAnchor", "endAnchor"],
2825
- additionalProperties: false
2826
- };
2827
2906
  function findUniqueLine(lines, anchor, label) {
2828
2907
  const matches = [];
2829
2908
  for (let i = 0; i < lines.length; i++) {
@@ -2841,22 +2920,43 @@ function findUniqueLine(lines, anchor, label) {
2841
2920
  }
2842
2921
  var deleteRangeTool = {
2843
2922
  name: "delete_range",
2923
+ kind: "edit" /* Edit */,
2844
2924
  description: "\u5220\u9664\u6587\u4EF6\u4E2D\u4E24\u4E2A\u951A\u70B9\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\u3002\u901A\u8FC7\u4E24\u4E2A\u552F\u4E00\u7684\u884C\u5185\u5BB9\u7CBE\u786E\u5B9A\u4F4D\u8303\u56F4\u3002\u9002\u7528\u4E8E\u5220\u9664\u65B9\u6CD5\u3001\u4EE3\u7801\u5757\u3001\u914D\u7F6E\u6BB5\u7B49\u3002",
2845
- parameters: deleteRangeSchema,
2846
- readOnly: false,
2925
+ parameters: {
2926
+ type: "object",
2927
+ properties: {
2928
+ path: {
2929
+ type: "string",
2930
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2931
+ },
2932
+ startAnchor: {
2933
+ type: "string",
2934
+ description: "\u5220\u9664\u8303\u56F4\u7684\u8D77\u59CB\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF09"
2935
+ },
2936
+ endAnchor: {
2937
+ type: "string",
2938
+ description: "\u5220\u9664\u8303\u56F4\u7684\u7ED3\u675F\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF0C\u987B\u5728 start_anchor \u4E4B\u540E\uFF09"
2939
+ },
2940
+ inclusive: {
2941
+ type: "boolean",
2942
+ description: "\u662F\u5426\u5305\u542B\u951A\u70B9\u884C\u672C\u8EAB\uFF0C\u9ED8\u8BA4 false\uFF08\u53EA\u5220\u9664\u4E24\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\uFF09"
2943
+ }
2944
+ },
2945
+ required: ["path", "startAnchor", "endAnchor"],
2946
+ additionalProperties: false
2947
+ },
2847
2948
  async execute(args, ctx) {
2848
- const params = args;
2849
- if (!params?.path || typeof params.path !== "string") {
2949
+ if (!args?.path || typeof args.path !== "string") {
2850
2950
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2851
2951
  }
2852
- if (typeof params.startAnchor !== "string") {
2952
+ if (typeof args.startAnchor !== "string") {
2853
2953
  return { success: false, data: "\u7F3A\u5C11\u6709\u6548\u53C2\u6570 startAnchor", error: "INVALID_ARGS" };
2854
2954
  }
2855
- if (typeof params.endAnchor !== "string") {
2955
+ if (typeof args.endAnchor !== "string") {
2856
2956
  return { success: false, data: "\u7F3A\u5C11\u6709\u6548\u53C2\u6570 endAnchor", error: "INVALID_ARGS" };
2857
2957
  }
2858
- const filePath = resolvePath(params.path, ctx.cwd);
2859
- const inclusive = params.inclusive ?? false;
2958
+ const filePath = resolvePath(args.path, ctx.cwd);
2959
+ const inclusive = args.inclusive ?? false;
2860
2960
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2861
2961
  const conf = await confine(ctx.writeRoots, filePath);
2862
2962
  if (!conf.ok) {
@@ -2866,11 +2966,11 @@ var deleteRangeTool = {
2866
2966
  try {
2867
2967
  const content = await readFile8(filePath, "utf-8");
2868
2968
  const lines = content.split("\n");
2869
- const startResult = findUniqueLine(lines, params.startAnchor, "start_anchor");
2969
+ const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
2870
2970
  if ("error" in startResult) {
2871
2971
  return { success: false, data: startResult.error, error: "ANCHOR_NOT_FOUND" };
2872
2972
  }
2873
- const endResult = findUniqueLine(lines, params.endAnchor, "end_anchor");
2973
+ const endResult = findUniqueLine(lines, args.endAnchor, "end_anchor");
2874
2974
  if ("error" in endResult) {
2875
2975
  return { success: false, data: endResult.error, error: "ANCHOR_NOT_FOUND" };
2876
2976
  }
@@ -2921,36 +3021,33 @@ var deleteRangeTool = {
2921
3021
  // src/tool/builtins/bash.ts
2922
3022
  import process3 from "process";
2923
3023
  var isWindows2 = process3.platform === "win32";
2924
- var bashSchema = {
2925
- type: "object",
2926
- properties: {
2927
- command: {
2928
- type: "string",
2929
- description: "\u8981\u6267\u884C\u7684 shell \u547D\u4EE4"
2930
- },
2931
- timeout: {
2932
- type: "number",
2933
- description: "\u6267\u884C\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 30000"
2934
- }
2935
- },
2936
- required: ["command"],
2937
- additionalProperties: false
2938
- };
2939
3024
  var bashTool = {
2940
3025
  name: "bash",
3026
+ kind: "other" /* Other */,
2941
3027
  description: "\u5728 shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002\u8FD4\u56DE\u6807\u51C6\u8F93\u51FA\u3001\u6807\u51C6\u9519\u8BEF\u548C\u9000\u51FA\u7801\u3002\u652F\u6301\u8D85\u65F6\u63A7\u5236\u548C\u4FE1\u53F7\u4E2D\u6B62\u3002\u9002\u7528\u4E8E\u8FD0\u884C\u6784\u5EFA\u3001\u6D4B\u8BD5\u3001Git \u64CD\u4F5C\u7B49\u547D\u4EE4\u3002",
2942
- parameters: bashSchema,
2943
- readOnly: false,
2944
- // bash 有副作用,不能并行执行
3028
+ parameters: {
3029
+ type: "object",
3030
+ properties: {
3031
+ command: {
3032
+ type: "string",
3033
+ description: "\u8981\u6267\u884C\u7684 shell \u547D\u4EE4"
3034
+ },
3035
+ timeout: {
3036
+ type: "number",
3037
+ description: "\u6267\u884C\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 30000"
3038
+ }
3039
+ },
3040
+ required: ["command"],
3041
+ additionalProperties: false
3042
+ },
2945
3043
  async execute(args, ctx) {
2946
- const params = args;
2947
- if (!params?.command || typeof params.command !== "string") {
3044
+ if (!args?.command || typeof args.command !== "string") {
2948
3045
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 command", error: "INVALID_ARGS" };
2949
3046
  }
2950
- const timeout = params.timeout ?? ctx.timeout ?? getDefaultTimeout();
3047
+ const timeout = args.timeout ?? ctx.timeout ?? getDefaultTimeout();
2951
3048
  try {
2952
3049
  const shellCommand = isWindows2 ? "cmd" : "sh";
2953
- const shellArgs = isWindows2 ? ["/c", params.command] : ["-c", params.command];
3050
+ const shellArgs = isWindows2 ? ["/c", args.command] : ["-c", args.command];
2954
3051
  const result = await execCommand(
2955
3052
  shellCommand,
2956
3053
  shellArgs,
@@ -2958,7 +3055,6 @@ var bashTool = {
2958
3055
  timeout,
2959
3056
  ctx.signal,
2960
3057
  true
2961
- // isShellCommand — 已指定 shell 程序,不需要二次包装
2962
3058
  );
2963
3059
  const parts = [];
2964
3060
  if (result.stdout) {
@@ -2970,7 +3066,7 @@ ${truncateOutput(result.stderr)}`);
2970
3066
  }
2971
3067
  const success = result.exitCode === 0;
2972
3068
  const output = parts.length > 0 ? parts.join("\n") : "(\u65E0\u8F93\u51FA)";
2973
- const cmdPreview = params.command.length > 60 ? params.command.slice(0, 57) + "..." : params.command;
3069
+ const cmdPreview = args.command.length > 60 ? args.command.slice(0, 57) + "..." : args.command;
2974
3070
  const summary = `\u{1F527} $ ${cmdPreview}\uFF08exit ${result.exitCode ?? "\u672A\u77E5"}\uFF09`;
2975
3071
  return {
2976
3072
  success,
@@ -2993,21 +3089,6 @@ ${truncateOutput(result.stderr)}`);
2993
3089
  // src/tool/builtins/glob.ts
2994
3090
  import { readdir as readdir2, stat as stat2 } from "fs/promises";
2995
3091
  import { join as join4, relative as relative4, isAbsolute as isAbsolute2 } from "path";
2996
- var globSchema = {
2997
- type: "object",
2998
- properties: {
2999
- pattern: {
3000
- type: "string",
3001
- description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u652F\u6301 * \u548C ** \u901A\u914D\u7B26\uFF0C\u5982 **/*.ts\u3001src/**/*.test.ts\uFF09"
3002
- },
3003
- directory: {
3004
- type: "string",
3005
- description: "\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3006
- }
3007
- },
3008
- required: ["pattern"],
3009
- additionalProperties: false
3010
- };
3011
3092
  function globToRegex(pattern) {
3012
3093
  let regexStr = pattern;
3013
3094
  regexStr = regexStr.replace(/\*\*\//g, "<<GLOBSTAR_SLASH>>");
@@ -3044,16 +3125,29 @@ async function walkDir(dir, baseDir) {
3044
3125
  }
3045
3126
  var globTool = {
3046
3127
  name: "glob",
3128
+ kind: "read" /* Read */,
3047
3129
  description: "\u6309\u6A21\u5F0F\u641C\u7D22\u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301 *\uFF08\u5339\u914D\u6587\u4EF6\u540D\u90E8\u5206\uFF09\u548C **\uFF08\u5339\u914D\u591A\u5C42\u76EE\u5F55\uFF09\u901A\u914D\u7B26\u3002\u81EA\u52A8\u8DF3\u8FC7 node_modules \u548C .git \u76EE\u5F55\u3002",
3048
- parameters: globSchema,
3049
- readOnly: true,
3130
+ parameters: {
3131
+ type: "object",
3132
+ properties: {
3133
+ pattern: {
3134
+ type: "string",
3135
+ description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u652F\u6301 * \u548C ** \u901A\u914D\u7B26\uFF0C\u5982 **/*.ts\u3001src/**/*.test.ts\uFF09"
3136
+ },
3137
+ directory: {
3138
+ type: "string",
3139
+ description: "\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3140
+ }
3141
+ },
3142
+ required: ["pattern"],
3143
+ additionalProperties: false
3144
+ },
3050
3145
  async execute(args, ctx) {
3051
- const params = args;
3052
- if (!params?.pattern || typeof params.pattern !== "string") {
3146
+ if (!args?.pattern || typeof args.pattern !== "string") {
3053
3147
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
3054
3148
  }
3055
- const searchDir = params.directory ? isAbsolute2(params.directory) ? params.directory : join4(ctx.cwd, params.directory) : ctx.cwd;
3056
- const regex = globToRegex(params.pattern);
3149
+ const searchDir = args.directory ? isAbsolute2(args.directory) ? args.directory : join4(ctx.cwd, args.directory) : ctx.cwd;
3150
+ const regex = globToRegex(args.pattern);
3057
3151
  try {
3058
3152
  const dirStat = await stat2(searchDir);
3059
3153
  if (!dirStat.isDirectory()) {
@@ -3064,8 +3158,8 @@ var globTool = {
3064
3158
  if (matched.length === 0) {
3065
3159
  return {
3066
3160
  success: true,
3067
- data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u6587\u4EF6`,
3068
- summary: `${params.pattern} \u2192 0 \u4E2A\u6587\u4EF6`
3161
+ data: `\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u6587\u4EF6`,
3162
+ summary: `${args.pattern} \u2192 0 \u4E2A\u6587\u4EF6`
3069
3163
  };
3070
3164
  }
3071
3165
  const limit = 200;
@@ -3077,7 +3171,7 @@ var globTool = {
3077
3171
  return {
3078
3172
  success: true,
3079
3173
  data: truncateOutput(output + suffix),
3080
- summary: `${params.pattern} \u2192 ${matched.length} \u4E2A\u6587\u4EF6`
3174
+ summary: `${args.pattern} \u2192 ${matched.length} \u4E2A\u6587\u4EF6`
3081
3175
  };
3082
3176
  } catch (err) {
3083
3177
  const message = err instanceof Error ? err.message : String(err);
@@ -3093,33 +3187,6 @@ var globTool = {
3093
3187
  // src/tool/builtins/grep.ts
3094
3188
  import { readdir as readdir3, readFile as readFile9, stat as stat3 } from "fs/promises";
3095
3189
  import { join as join5, relative as relative5, isAbsolute as isAbsolute3 } from "path";
3096
- var grepSchema = {
3097
- type: "object",
3098
- properties: {
3099
- pattern: {
3100
- type: "string",
3101
- description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u641C\u7D22\u6A21\u5F0F"
3102
- },
3103
- directory: {
3104
- type: "string",
3105
- description: "\u641C\u7D22\u7684\u76EE\u5F55\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3106
- },
3107
- include: {
3108
- type: "string",
3109
- description: "\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\uFF08\u5982 ts\u3001json\uFF09\uFF0C\u4E0D\u542B\u70B9\u53F7"
3110
- },
3111
- case_sensitive: {
3112
- type: "boolean",
3113
- description: "\u662F\u5426\u5927\u5C0F\u5199\u654F\u611F\uFF0C\u9ED8\u8BA4 false"
3114
- },
3115
- max_files: {
3116
- type: "number",
3117
- description: "\u6700\u5927\u641C\u7D22\u6587\u4EF6\u6570\uFF0C\u9ED8\u8BA4 200"
3118
- }
3119
- },
3120
- required: ["pattern"],
3121
- additionalProperties: false
3122
- };
3123
3190
  async function collectFiles(dir, baseDir, extension, maxFiles = 200) {
3124
3191
  const results = [];
3125
3192
  let entries;
@@ -3147,24 +3214,49 @@ async function collectFiles(dir, baseDir, extension, maxFiles = 200) {
3147
3214
  }
3148
3215
  var grepTool = {
3149
3216
  name: "grep",
3217
+ kind: "read" /* Read */,
3150
3218
  description: "\u5728\u6587\u4EF6\u5185\u5BB9\u4E2D\u641C\u7D22\u6B63\u5219\u8868\u8FBE\u5F0F\u3002\u8FD4\u56DE\u5339\u914D\u884C\u7684\u6587\u4EF6\u8DEF\u5F84\u3001\u884C\u53F7\u548C\u5185\u5BB9\u3002\u652F\u6301\u5927\u5C0F\u5199\u654F\u611F\u3001\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\u3002",
3151
- parameters: grepSchema,
3152
- readOnly: true,
3219
+ parameters: {
3220
+ type: "object",
3221
+ properties: {
3222
+ pattern: {
3223
+ type: "string",
3224
+ description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u641C\u7D22\u6A21\u5F0F"
3225
+ },
3226
+ directory: {
3227
+ type: "string",
3228
+ description: "\u641C\u7D22\u7684\u76EE\u5F55\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3229
+ },
3230
+ include: {
3231
+ type: "string",
3232
+ description: "\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\uFF08\u5982 ts\u3001json\uFF09\uFF0C\u4E0D\u542B\u70B9\u53F7"
3233
+ },
3234
+ case_sensitive: {
3235
+ type: "boolean",
3236
+ description: "\u662F\u5426\u5927\u5C0F\u5199\u654F\u611F\uFF0C\u9ED8\u8BA4 false"
3237
+ },
3238
+ max_files: {
3239
+ type: "number",
3240
+ description: "\u6700\u5927\u641C\u7D22\u6587\u4EF6\u6570\uFF0C\u9ED8\u8BA4 200"
3241
+ }
3242
+ },
3243
+ required: ["pattern"],
3244
+ additionalProperties: false
3245
+ },
3153
3246
  async execute(args, ctx) {
3154
- const params = args;
3155
- if (!params?.pattern || typeof params.pattern !== "string") {
3247
+ if (!args?.pattern || typeof args.pattern !== "string") {
3156
3248
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
3157
3249
  }
3158
- const searchDir = params.directory ? isAbsolute3(params.directory) ? params.directory : join5(ctx.cwd, params.directory) : ctx.cwd;
3159
- const maxFiles = params.max_files ?? 200;
3250
+ const searchDir = args.directory ? isAbsolute3(args.directory) ? args.directory : join5(ctx.cwd, args.directory) : ctx.cwd;
3251
+ const maxFiles = args.max_files ?? 200;
3160
3252
  try {
3161
- const flags = params.case_sensitive ? "g" : "gi";
3162
- const regex = new RegExp(params.pattern, flags);
3253
+ const flags = args.case_sensitive ? "g" : "gi";
3254
+ const regex = new RegExp(args.pattern, flags);
3163
3255
  const dirStat = await stat3(searchDir);
3164
3256
  if (!dirStat.isDirectory()) {
3165
3257
  return { success: false, data: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${searchDir}`, error: "NOT_DIRECTORY" };
3166
3258
  }
3167
- const files = await collectFiles(searchDir, searchDir, params.include, maxFiles);
3259
+ const files = await collectFiles(searchDir, searchDir, args.include, maxFiles);
3168
3260
  const matches = [];
3169
3261
  for (const filePath of files) {
3170
3262
  try {
@@ -3190,13 +3282,13 @@ var grepTool = {
3190
3282
  if (matches.length === 0) {
3191
3283
  return {
3192
3284
  success: true,
3193
- data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u5185\u5BB9`,
3194
- summary: `\u{1F50D} "${params.pattern}" \u2192 0 \u6761\u547D\u4E2D`
3285
+ data: `\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u5185\u5BB9`,
3286
+ summary: `\u{1F50D} "${args.pattern}" \u2192 0 \u6761\u547D\u4E2D`
3195
3287
  };
3196
3288
  }
3197
3289
  const output = matches.map((m) => `${m.file}:${m.line}: ${m.content}`).join("\n");
3198
3290
  const fileSet = new Set(matches.map((m) => m.file));
3199
- const summary = `\u{1F50D} "${params.pattern}" \u2192 ${matches.length} \u6761\u547D\u4E2D / ${fileSet.size} \u4E2A\u6587\u4EF6`;
3291
+ const summary = `\u{1F50D} "${args.pattern}" \u2192 ${matches.length} \u6761\u547D\u4E2D / ${fileSet.size} \u4E2A\u6587\u4EF6`;
3200
3292
  return {
3201
3293
  success: true,
3202
3294
  data: truncateOutput(output),
@@ -3216,30 +3308,28 @@ var grepTool = {
3216
3308
  // src/tool/builtins/ls.ts
3217
3309
  import { readdir as readdir4, stat as stat4 } from "fs/promises";
3218
3310
  import { join as join6, relative as relative6 } from "path";
3219
- var lsSchema = {
3220
- type: "object",
3221
- properties: {
3222
- path: {
3223
- type: "string",
3224
- description: "\u76EE\u5F55\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55"
3225
- },
3226
- all: {
3227
- type: "boolean",
3228
- description: "\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\uFF08\u4EE5 . \u5F00\u5934\u7684\u6587\u4EF6\uFF09\uFF0C\u9ED8\u8BA4 false"
3229
- }
3230
- },
3231
- required: [],
3232
- additionalProperties: false
3233
- };
3234
3311
  var lsTool = {
3235
3312
  name: "ls",
3313
+ kind: "read" /* Read */,
3236
3314
  description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9\u3002\u663E\u793A\u6761\u76EE\u7C7B\u578B\uFF08\u6587\u4EF6/\u76EE\u5F55/\u94FE\u63A5\uFF09\u548C\u5927\u5C0F\u3002\u53EF\u9009\u62E9\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\u3002",
3237
- parameters: lsSchema,
3238
- readOnly: true,
3315
+ parameters: {
3316
+ type: "object",
3317
+ properties: {
3318
+ path: {
3319
+ type: "string",
3320
+ description: "\u76EE\u5F55\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55"
3321
+ },
3322
+ all: {
3323
+ type: "boolean",
3324
+ description: "\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\uFF08\u4EE5 . \u5F00\u5934\u7684\u6587\u4EF6\uFF09\uFF0C\u9ED8\u8BA4 false"
3325
+ }
3326
+ },
3327
+ required: [],
3328
+ additionalProperties: false
3329
+ },
3239
3330
  async execute(args, ctx) {
3240
- const params = args ?? {};
3241
- const dirPath = params.path ? resolvePath(params.path, ctx.cwd) : ctx.cwd;
3242
- const showAll = params.all ?? false;
3331
+ const dirPath = args.path ? resolvePath(args.path, ctx.cwd) : ctx.cwd;
3332
+ const showAll = args.all ?? false;
3243
3333
  try {
3244
3334
  const entries = await readdir4(dirPath, { withFileTypes: true });
3245
3335
  const lines = [];
@@ -3292,58 +3382,56 @@ ${lines.join("\n")}`),
3292
3382
  };
3293
3383
 
3294
3384
  // src/tool/builtins/fetch.ts
3295
- var fetchSchema = {
3296
- type: "object",
3297
- properties: {
3298
- url: {
3299
- type: "string",
3300
- description: "\u8BF7\u6C42\u7684 URL"
3301
- },
3302
- method: {
3303
- type: "string",
3304
- description: "HTTP \u65B9\u6CD5\uFF08GET\u3001POST\u3001PUT\u3001DELETE \u7B49\uFF09\uFF0C\u9ED8\u8BA4 GET"
3305
- },
3306
- headers: {
3307
- type: "object",
3308
- description: "\u8BF7\u6C42\u5934\u952E\u503C\u5BF9",
3309
- additionalProperties: { type: "string" }
3310
- },
3311
- body: {
3312
- type: "string",
3313
- description: "\u8BF7\u6C42\u4F53\u5185\u5BB9\uFF08POST/PUT \u65F6\u4F7F\u7528\uFF09"
3314
- },
3315
- max_length: {
3316
- type: "number",
3317
- description: "\u54CD\u5E94\u5185\u5BB9\u6700\u5927\u957F\u5EA6\uFF08\u5B57\u7B26\uFF09\uFF0C\u9ED8\u8BA4 50000"
3318
- }
3319
- },
3320
- required: ["url"],
3321
- additionalProperties: false
3322
- };
3323
3385
  var fetchTool = {
3324
3386
  name: "fetch",
3387
+ kind: "read" /* Read */,
3325
3388
  description: "\u53D1\u8D77 HTTP \u8BF7\u6C42\u5E76\u8FD4\u56DE\u54CD\u5E94\u5185\u5BB9\u3002\u652F\u6301\u81EA\u5B9A\u4E49\u65B9\u6CD5\u548C\u8BF7\u6C42\u5934\u3002\u9002\u7528\u4E8E\u83B7\u53D6\u7F51\u9875\u5185\u5BB9\u3001API \u8C03\u7528\u7B49\u573A\u666F\u3002",
3326
- parameters: fetchSchema,
3327
- readOnly: true,
3389
+ parameters: {
3390
+ type: "object",
3391
+ properties: {
3392
+ url: {
3393
+ type: "string",
3394
+ description: "\u8BF7\u6C42\u7684 URL"
3395
+ },
3396
+ method: {
3397
+ type: "string",
3398
+ description: "HTTP \u65B9\u6CD5\uFF08GET\u3001POST\u3001PUT\u3001DELETE \u7B49\uFF09\uFF0C\u9ED8\u8BA4 GET"
3399
+ },
3400
+ headers: {
3401
+ type: "object",
3402
+ description: "\u8BF7\u6C42\u5934\u952E\u503C\u5BF9",
3403
+ additionalProperties: { type: "string" }
3404
+ },
3405
+ body: {
3406
+ type: "string",
3407
+ description: "\u8BF7\u6C42\u4F53\u5185\u5BB9\uFF08POST/PUT \u65F6\u4F7F\u7528\uFF09"
3408
+ },
3409
+ max_length: {
3410
+ type: "number",
3411
+ description: "\u54CD\u5E94\u5185\u5BB9\u6700\u5927\u957F\u5EA6\uFF08\u5B57\u7B26\uFF09\uFF0C\u9ED8\u8BA4 50000"
3412
+ }
3413
+ },
3414
+ required: ["url"],
3415
+ additionalProperties: false
3416
+ },
3328
3417
  async execute(args, ctx) {
3329
- const params = args;
3330
- if (!params?.url || typeof params.url !== "string") {
3418
+ if (!args?.url || typeof args.url !== "string") {
3331
3419
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 url", error: "INVALID_ARGS" };
3332
3420
  }
3333
- const method = (params.method ?? "GET").toUpperCase();
3421
+ const method = (args.method ?? "GET").toUpperCase();
3334
3422
  const timeout = 3e4;
3335
- const maxLength = params.max_length ?? 5e4;
3423
+ const maxLength = args.max_length ?? 5e4;
3336
3424
  try {
3337
3425
  const fetchOptions = {
3338
3426
  method,
3339
- headers: params.headers ?? {},
3427
+ headers: args.headers ?? {},
3340
3428
  signal: ctx.signal ?? AbortSignal.timeout(timeout)
3341
3429
  };
3342
- if (params.body && (method === "POST" || method === "PUT" || method === "PATCH")) {
3430
+ if (args.body && (method === "POST" || method === "PUT" || method === "PATCH")) {
3343
3431
  fetchOptions.headers["Content-Type"] ??= "application/json";
3344
- fetchOptions.body = params.body;
3432
+ fetchOptions.body = args.body;
3345
3433
  }
3346
- const response = await fetch(params.url, fetchOptions);
3434
+ const response = await fetch(args.url, fetchOptions);
3347
3435
  const contentType = response.headers.get("content-type") ?? "unknown";
3348
3436
  const statusText = `${response.status} ${response.statusText}`;
3349
3437
  let body;
@@ -3356,7 +3444,7 @@ var fetchTool = {
3356
3444
  const header = `\u72B6\u6001: ${statusText}
3357
3445
  \u5185\u5BB9\u7C7B\u578B: ${contentType}`;
3358
3446
  const separator = body.length > 0 ? "\n---\n" : "";
3359
- const urlPreview = params.url.length > 60 ? params.url.slice(0, 57) + "..." : params.url;
3447
+ const urlPreview = args.url.length > 60 ? args.url.slice(0, 57) + "..." : args.url;
3360
3448
  const summary = `\u{1F310} ${method} ${urlPreview} \u2192 ${response.status}`;
3361
3449
  return {
3362
3450
  success: response.ok,
@@ -3383,16 +3471,16 @@ var fetchTool = {
3383
3471
 
3384
3472
  // src/tool/builtins/index.ts
3385
3473
  var builtinTools = [
3386
- readFileTool,
3387
- writeFileTool,
3388
- editFileTool,
3389
- multiEditTool,
3390
- deleteRangeTool,
3391
- bashTool,
3392
- globTool,
3393
- grepTool,
3394
- lsTool,
3395
- fetchTool
3474
+ eraseTool(readFileTool),
3475
+ eraseTool(writeFileTool),
3476
+ eraseTool(editFileTool),
3477
+ eraseTool(multiEditTool),
3478
+ eraseTool(deleteRangeTool),
3479
+ eraseTool(bashTool),
3480
+ eraseTool(globTool),
3481
+ eraseTool(grepTool),
3482
+ eraseTool(lsTool),
3483
+ eraseTool(fetchTool)
3396
3484
  ];
3397
3485
 
3398
3486
  // src/utils/gradient.ts
@@ -3459,7 +3547,7 @@ function getGradientColors(text, phase, stops) {
3459
3547
  }
3460
3548
 
3461
3549
  // src/ui/ChatSession.tsx
3462
- import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3550
+ import { Fragment, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
3463
3551
  var commandRegistry = /* @__PURE__ */ new Map();
3464
3552
  function registerCommand(name, cmd) {
3465
3553
  commandRegistry.set(name, cmd);
@@ -3483,6 +3571,8 @@ registerCommand("/help", {
3483
3571
  registerCommand("/clear", { desc: "\u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", handler: () => ({ kind: "clear" }) });
3484
3572
  registerCommand("/version", { desc: "\u663E\u793A\u7248\u672C\u4FE1\u606F", handler: () => ({ kind: "text", content: "dskcode v0.1.10" }) });
3485
3573
  registerCommand("/model", { desc: "\u5207\u6362\u6A21\u578B", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /model \u8FDB\u5165\u9009\u62E9\u754C\u9762" }) });
3574
+ registerCommand("/thinking", { desc: "\u5207\u6362\u6DF1\u5EA6\u601D\u8003\u6A21\u5F0F", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /thinking \u5207\u6362" }) });
3575
+ registerCommand("/effort", { desc: "\u5207\u6362\u63A8\u7406\u7B49\u7EA7 High/Max", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /effort \u5207\u6362" }) });
3486
3576
  registerCommand("/game", { desc: "\u542F\u52A8\u6E38\u620F", handler: () => ({ kind: "navigate", target: "game" }) });
3487
3577
  registerCommand("/stock", { desc: "\u67E5\u770B\u80A1\u7968\u884C\u60C5", handler: () => ({ kind: "navigate", target: "stock" }) });
3488
3578
  var STREAMING_PLACEHOLDERS = [
@@ -3541,6 +3631,19 @@ function ChatSession({
3541
3631
  const [activeModel, setActiveModel] = useState3(model);
3542
3632
  const [streamingModel, setStreamingModel] = useState3(void 0);
3543
3633
  const [streamError, setStreamError] = useState3(void 0);
3634
+ const [thinkingEnabled, setThinkingEnabled] = useState3(true);
3635
+ const [thinkingEffort, setThinkingEffort] = useState3("high");
3636
+ const [responseFormat, setResponseFormat] = useState3("text");
3637
+ const [toolChoice, setToolChoice] = useState3(void 0);
3638
+ const sessionCost = useMemo(() => {
3639
+ return displayMessages.reduce((sum, msg) => {
3640
+ if (msg.assistantDetail?.cost) {
3641
+ return sum + msg.assistantDetail.cost;
3642
+ }
3643
+ return sum;
3644
+ }, 0);
3645
+ }, [displayMessages]);
3646
+ const hasConversationStarted = displayMessages.length > 0;
3544
3647
  const cmdTips = Array.from(getRegisteredCommands()).filter(([name]) => name !== "/exit" && name !== "/quit").map(([name, cmd]) => ({ name, desc: cmd.desc }));
3545
3648
  const [cmdTipIndex, setCmdTipIndex] = useState3(0);
3546
3649
  const [cmdTipGradientColors, setCmdTipGradientColors] = useState3([]);
@@ -3672,6 +3775,11 @@ function ChatSession({
3672
3775
  return;
3673
3776
  }
3674
3777
  }
3778
+ if (selectingModel) {
3779
+ if (key.upArrow || key.downArrow) {
3780
+ }
3781
+ return;
3782
+ }
3675
3783
  if (key.ctrl && _input === "c") {
3676
3784
  if (isStreaming) {
3677
3785
  abortRef.current?.abort();
@@ -3691,7 +3799,7 @@ function ChatSession({
3691
3799
  if (cmdTips.length <= 1) return;
3692
3800
  const timer = setInterval(() => {
3693
3801
  setCmdTipIndex((prev) => (prev + 1) % cmdTips.length);
3694
- }, 5e3);
3802
+ }, 2e3);
3695
3803
  return () => clearInterval(timer);
3696
3804
  }, [cmdTips.length]);
3697
3805
  useEffect3(() => {
@@ -3738,7 +3846,7 @@ function ChatSession({
3738
3846
  if (!apiKey || !baseUrl) return;
3739
3847
  let cancelled = false;
3740
3848
  setBalanceLoading(true);
3741
- import("./deepseek-UJXV2D6K.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
3849
+ import("./deepseek-YTT76XDE.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
3742
3850
  const provider = new DeepSeekProvider2({
3743
3851
  apiKey,
3744
3852
  baseUrl,
@@ -3807,14 +3915,48 @@ function ChatSession({
3807
3915
  const trimmed = value.trim();
3808
3916
  if (!trimmed) return;
3809
3917
  if (trimmed.startsWith("/") && trimmed.length > 1) {
3810
- if (trimmed.toLowerCase() === "/model") {
3918
+ const cmdLower = trimmed.toLowerCase();
3919
+ if (cmdLower === "/model") {
3811
3920
  const curIdx = modelOptions.indexOf(activeModel);
3812
3921
  setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
3813
3922
  setSelectingModel(true);
3814
3923
  setInput("");
3815
3924
  return;
3816
3925
  }
3817
- const cmd = commandRegistry.get(trimmed.toLowerCase());
3926
+ if (cmdLower === "/thinking") {
3927
+ setThinkingEnabled((prev) => !prev);
3928
+ setDisplayMessages((prev) => [
3929
+ ...prev,
3930
+ { role: "user", content: trimmed },
3931
+ { role: "assistant", content: `\u6DF1\u5EA6\u601D\u8003\u5DF2${thinkingEnabled ? "\u5173\u95ED" : "\u5F00\u542F"}` }
3932
+ ]);
3933
+ setInput("");
3934
+ return;
3935
+ }
3936
+ if (cmdLower === "/effort") {
3937
+ const next = thinkingEffort === "high" ? "max" : "high";
3938
+ setThinkingEffort(next);
3939
+ setDisplayMessages((prev) => [
3940
+ ...prev,
3941
+ { role: "user", content: trimmed },
3942
+ { role: "assistant", content: `\u63A8\u7406\u7B49\u7EA7\u5DF2\u5207\u6362\u4E3A ${next === "high" ? "High" : "Max"}` }
3943
+ ]);
3944
+ setInput("");
3945
+ return;
3946
+ }
3947
+ if (cmdLower === "/tools") {
3948
+ const next = toolChoice === void 0 ? "none" : toolChoice === "none" ? "required" : toolChoice === "required" ? "auto" : void 0;
3949
+ setToolChoice(next);
3950
+ const label = next === void 0 ? "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09" : next === "none" ? "\u7981\u6B62\u8C03\u7528" : next === "required" ? "\u5F3A\u5236\u8C03\u7528" : "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09";
3951
+ setDisplayMessages((prev) => [
3952
+ ...prev,
3953
+ { role: "user", content: trimmed },
3954
+ { role: "assistant", content: `\u5DE5\u5177\u8C03\u7528\u7B56\u7565\u5DF2\u5207\u6362\u4E3A ${label}` }
3955
+ ]);
3956
+ setInput("");
3957
+ return;
3958
+ }
3959
+ const cmd = commandRegistry.get(cmdLower);
3818
3960
  if (cmd) {
3819
3961
  const result = cmd.handler();
3820
3962
  switch (result.kind) {
@@ -3889,7 +4031,12 @@ function ChatSession({
3889
4031
  const abortController = new AbortController();
3890
4032
  abortRef.current = abortController;
3891
4033
  try {
3892
- for await (const event of session.chat(trimmed)) {
4034
+ for await (const event of session.chat(trimmed, {
4035
+ thinkingAllowed: thinkingEnabled || void 0,
4036
+ thinkingEffort: thinkingEnabled ? thinkingEffort : void 0,
4037
+ responseFormat: responseFormat !== "text" ? responseFormat : void 0,
4038
+ toolChoice
4039
+ })) {
3893
4040
  if (abortController.signal.aborted) break;
3894
4041
  switch (event.type) {
3895
4042
  case "text_delta":
@@ -3927,6 +4074,11 @@ function ChatSession({
3927
4074
  setStreamingModel(event.model);
3928
4075
  currentUsageRef.current = event.usage;
3929
4076
  currentModelRef.current = event.model;
4077
+ {
4078
+ const cost = calculateCost(event.usage, event.model);
4079
+ setCurrentCost(cost.totalCost);
4080
+ currentCostRef.current = cost.totalCost;
4081
+ }
3930
4082
  break;
3931
4083
  case "done":
3932
4084
  setCurrentElapsed(event.elapsed);
@@ -3968,66 +4120,66 @@ function ChatSession({
3968
4120
  ]);
3969
4121
  }
3970
4122
  }
3971
- }, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills]);
4123
+ }, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills, thinkingEnabled, thinkingEffort, responseFormat, toolChoice, activeModel]);
3972
4124
  useEffect3(() => {
3973
4125
  if (!isStreaming && externalCostTracker) {
3974
4126
  setTodayCost(externalCostTracker.todayTotalCost);
3975
4127
  }
3976
4128
  }, [isStreaming, externalCostTracker]);
3977
- useEffect3(() => {
3978
- if (currentUsage && streamingModel && !currentCost) {
3979
- import("./models-OL7DHYGK.js").then(({ calculateCost: calculateCost2 }) => {
3980
- const cost = calculateCost2(currentUsage, streamingModel);
3981
- setCurrentCost(cost.totalCost);
3982
- currentCostRef.current = cost.totalCost;
3983
- });
3984
- }
3985
- }, [currentUsage, streamingModel, currentCost]);
3986
4129
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
3987
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginBottom: 1, children: [
3988
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
4130
+ !hasConversationStarted && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginBottom: 1, children: [
4131
+ /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
3989
4132
  const colorIndex = (i + offset) % CYBER_PALETTE.length;
3990
- return /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
4133
+ return /* @__PURE__ */ jsx9(Box8, { children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
3991
4134
  }) }),
3992
4135
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", justifyContent: "center", children: [
3993
- /* @__PURE__ */ jsxs8(Text9, { color: "#00ff41", children: [
4136
+ /* @__PURE__ */ jsxs8(Text10, { color: "#00ff41", children: [
3994
4137
  " \u2714 ",
3995
4138
  "\u5DF2\u5C31\u7EEA ",
3996
4139
  skillCount,
3997
4140
  " \u4E2A Skill"
3998
4141
  ] }),
3999
- /* @__PURE__ */ jsxs8(Text9, { color: "#00ffff", children: [
4142
+ /* @__PURE__ */ jsxs8(Text10, { color: "#00ffff", children: [
4000
4143
  " \u2139 ",
4001
4144
  "\u5DF2\u5C31\u7EEA ",
4002
4145
  toolCount,
4003
4146
  " \u4E2A\u5DE5\u5177"
4004
4147
  ] }),
4005
- /* @__PURE__ */ jsxs8(Text9, { color: "#00ffff", children: [
4148
+ /* @__PURE__ */ jsxs8(Text10, { color: "#00ffff", children: [
4006
4149
  " \u{1F527} \u6A21\u578B ",
4007
4150
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
4008
4151
  ] }),
4152
+ thinkingEnabled && /* @__PURE__ */ jsxs8(Text10, { color: "#ff9800", children: [
4153
+ " \u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
4154
+ thinkingEffort === "max" ? "Max" : "High"
4155
+ ] }),
4156
+ responseFormat === "json_object" && /* @__PURE__ */ jsx9(Text10, { color: "#4caf50", children: " \u{1F4C4} JSON" }),
4157
+ toolChoice !== void 0 && /* @__PURE__ */ jsxs8(Text10, { color: "#e91e63", children: [
4158
+ " \u{1F6E0} ",
4159
+ toolChoice === "none" ? "\u7981\u6B62\u5DE5\u5177" : toolChoice === "required" ? "\u5F3A\u5236\u5DE5\u5177" : ""
4160
+ ] }),
4009
4161
  cmdTips.length > 0 && (() => {
4010
4162
  const tip = cmdTips[cmdTipIndex % cmdTips.length];
4011
4163
  if (!tip) return null;
4012
4164
  const text = `${tip.name} ${tip.desc}`;
4013
- return /* @__PURE__ */ jsxs8(Text9, { children: [
4014
- /* @__PURE__ */ jsx8(Text9, { color: "#808080", children: " \u{1F4A1} " }),
4015
- cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx8(Text9, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx8(Text9, { color: "#808080", children: text })
4165
+ return /* @__PURE__ */ jsxs8(Text10, { children: [
4166
+ /* @__PURE__ */ jsx9(Text10, { color: "#808080", children: " \u{1F4A1} " }),
4167
+ 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 })
4016
4168
  ] });
4017
4169
  })(),
4018
- verbose ? /* @__PURE__ */ jsx8(Text9, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
4170
+ verbose ? /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
4019
4171
  ] }),
4020
4172
  /* @__PURE__ */ jsxs8(Box8, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
4021
- balanceLoading && balance === null ? /* @__PURE__ */ jsx8(Text9, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
4022
- /* @__PURE__ */ jsx8(Text9, { color: "yellow", children: "\u{1F4B0} " }),
4023
- /* @__PURE__ */ jsxs8(Text9, { color: "yellow", children: [
4173
+ balanceLoading && balance === null ? /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
4174
+ /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: "\u{1F4B0} " }),
4175
+ /* @__PURE__ */ jsxs8(Text10, { color: "yellow", children: [
4024
4176
  "\u4F59\u989D \xA5",
4025
4177
  balance.toFixed(2)
4026
4178
  ] })
4027
4179
  ] }) : null,
4028
4180
  todayCost !== null ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
4029
- /* @__PURE__ */ jsx8(Text9, { color: "cyan", children: "\u{1F4CA} " }),
4030
- /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
4181
+ /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: "\u{1F4CA} " }),
4182
+ /* @__PURE__ */ jsxs8(Text10, { color: "cyan", children: [
4031
4183
  "\u4ECA\u65E5 \xA5",
4032
4184
  todayCost.toFixed(2)
4033
4185
  ] })
@@ -4035,24 +4187,24 @@ function ChatSession({
4035
4187
  ] })
4036
4188
  ] }),
4037
4189
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
4038
- /* @__PURE__ */ jsx8(Static, { items: displayMessages, children: (msg, i) => {
4190
+ /* @__PURE__ */ jsx9(Static, { items: displayMessages, children: (msg, i) => {
4039
4191
  if (msg.role === "user") {
4040
4192
  return /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
4041
- /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
4042
- /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx8(Text9, { wrap: "wrap", children: msg.content }) })
4193
+ /* @__PURE__ */ jsx9(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
4194
+ /* @__PURE__ */ jsx9(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text10, { wrap: "wrap", children: msg.content }) })
4043
4195
  ] }, i);
4044
4196
  }
4045
4197
  if (msg.role === "tool") {
4046
4198
  return /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
4047
4199
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
4048
- /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#f59e0b", children: "\u{1F527}" }) }),
4049
- /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx8(Text9, { wrap: "wrap", children: msg.content }) })
4200
+ /* @__PURE__ */ jsx9(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#f59e0b", children: "\u{1F527}" }) }),
4201
+ /* @__PURE__ */ jsx9(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx9(Text10, { wrap: "wrap", children: msg.content }) })
4050
4202
  ] }),
4051
- msg.diff && /* @__PURE__ */ jsx8(DiffPreview, { diff: msg.diff })
4203
+ msg.diff && /* @__PURE__ */ jsx9(DiffPreview, { diff: msg.diff })
4052
4204
  ] }, i);
4053
4205
  }
4054
4206
  const detail = msg.assistantDetail;
4055
- return /* @__PURE__ */ jsx8(
4207
+ return /* @__PURE__ */ jsx9(
4056
4208
  AssistantMessage,
4057
4209
  {
4058
4210
  content: msg.content,
@@ -4066,7 +4218,7 @@ function ChatSession({
4066
4218
  i
4067
4219
  );
4068
4220
  } }, staticKey),
4069
- isStreaming && /* @__PURE__ */ jsx8(
4221
+ isStreaming && /* @__PURE__ */ jsx9(
4070
4222
  AssistantMessage,
4071
4223
  {
4072
4224
  content: currentContent,
@@ -4074,16 +4226,16 @@ function ChatSession({
4074
4226
  isStreaming: true
4075
4227
  }
4076
4228
  ),
4077
- isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx8(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
4078
- !isStreaming && streamError && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs8(Text9, { color: "red", children: [
4229
+ isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */ jsx9(Box8, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx9(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
4230
+ !isStreaming && streamError && /* @__PURE__ */ jsx9(Box8, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs8(Text10, { color: "red", children: [
4079
4231
  "\u26A0 ",
4080
4232
  streamError
4081
4233
  ] }) })
4082
4234
  ] }),
4083
4235
  selectingModel ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
4084
- /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
4236
+ /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
4085
4237
  /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
4086
- /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
4238
+ /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
4087
4239
  modelOptions.map((id, i) => {
4088
4240
  const meta = SUPPORTED_MODELS[id];
4089
4241
  const isCurrent = id === activeModel;
@@ -4092,7 +4244,7 @@ function ChatSession({
4092
4244
  const suffix = isCurrent ? " (\u5F53\u524D)" : "";
4093
4245
  return /* @__PURE__ */ jsxs8(Box8, { children: [
4094
4246
  /* @__PURE__ */ jsxs8(
4095
- Text9,
4247
+ Text10,
4096
4248
  {
4097
4249
  color: isSelected ? "#00ff41" : void 0,
4098
4250
  bold: isSelected,
@@ -4103,20 +4255,34 @@ function ChatSession({
4103
4255
  ]
4104
4256
  }
4105
4257
  ),
4106
- isSelected && /* @__PURE__ */ jsxs8(Text9, { color: "#808080", children: [
4258
+ isSelected && /* @__PURE__ */ jsxs8(Text10, { color: "#808080", children: [
4107
4259
  " \u2014 ",
4108
4260
  id
4109
4261
  ] })
4110
4262
  ] }, id);
4111
4263
  }),
4112
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
4264
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
4113
4265
  ] }),
4114
- /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
4266
+ /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
4115
4267
  ] }) : /* @__PURE__ */ jsxs8(Fragment, { children: [
4116
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4268
+ /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: hasConversationStarted && (balance !== null || sessionCost > 0 || isStreaming) ? /* @__PURE__ */ jsxs8(Text10, { color: "#00ffff", dimColor: true, children: [
4269
+ "\u2500".repeat(Math.max(dividerWidth - 35, 10)),
4270
+ balance !== null && /* @__PURE__ */ jsxs8(Text10, { color: "yellow", children: [
4271
+ " \u{1F4B0} \u4F59\u989D \xA5",
4272
+ balance.toFixed(2)
4273
+ ] }),
4274
+ isStreaming ? /* @__PURE__ */ jsxs8(Text10, { color: "cyan", children: [
4275
+ " \u{1F4CA} \u672C\u6B21 \xA5",
4276
+ sessionCost > 0 ? sessionCost.toFixed(4) + " " : "",
4277
+ /* @__PURE__ */ jsx9(InkSpinner2, { type: "dots" })
4278
+ ] }) : sessionCost > 0 ? /* @__PURE__ */ jsxs8(Text10, { color: "cyan", children: [
4279
+ " \u{1F4CA} \u672C\u6B21 \xA5",
4280
+ sessionCost.toFixed(4)
4281
+ ] }) : null
4282
+ ] }) : /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4117
4283
  /* @__PURE__ */ jsxs8(Box8, { children: [
4118
- /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
4119
- /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx8(Text9, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx8(Text9, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx8(Text9, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx8(Text9, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx8(
4284
+ /* @__PURE__ */ jsx9(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
4285
+ /* @__PURE__ */ jsx9(Box8, { 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(
4120
4286
  TextInput,
4121
4287
  {
4122
4288
  value: input,
@@ -4127,19 +4293,19 @@ function ChatSession({
4127
4293
  inputKey
4128
4294
  ) })
4129
4295
  ] }),
4130
- /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4131
- /* @__PURE__ */ jsx8(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
4132
- /* @__PURE__ */ jsx8(FileSelector, { files, input, selectedIndex: fileSelectIndex })
4296
+ /* @__PURE__ */ jsx9(Box8, { children: /* @__PURE__ */ jsx9(Text10, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4297
+ /* @__PURE__ */ jsx9(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
4298
+ /* @__PURE__ */ jsx9(FileSelector, { files, input, selectedIndex: fileSelectIndex })
4133
4299
  ] }),
4134
- doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
4135
- isStreaming && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
4300
+ doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
4301
+ isStreaming && /* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
4136
4302
  ] });
4137
4303
  }
4138
4304
 
4139
4305
  // src/ui/GamePicker.tsx
4140
- import { Box as Box9, Text as Text10, useInput as useInput2 } from "ink";
4306
+ import { Box as Box9, Text as Text11, useInput as useInput2 } from "ink";
4141
4307
  import { useState as useState4, useCallback as useCallback3 } from "react";
4142
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
4308
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
4143
4309
  function GamePicker({ games, onSelect, onExit, onBackToChat }) {
4144
4310
  const [selectedIndex, setSelectedIndex] = useState4(0);
4145
4311
  const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
@@ -4168,17 +4334,17 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
4168
4334
  )
4169
4335
  );
4170
4336
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
4171
- /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
4172
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: games.map((game, index) => {
4337
+ /* @__PURE__ */ jsx10(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
4338
+ /* @__PURE__ */ jsx10(Box9, { flexDirection: "column", children: games.map((game, index) => {
4173
4339
  const isSelected = index === selectedIndex;
4174
4340
  return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
4175
- /* @__PURE__ */ jsx9(Box9, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx9(Text10, { children: " " }) }),
4176
- /* @__PURE__ */ jsx9(Box9, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
4177
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { color: "#888888", children: game.description }) })
4341
+ /* @__PURE__ */ jsx10(Box9, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx10(Text11, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx10(Text11, { children: " " }) }),
4342
+ /* @__PURE__ */ jsx10(Box9, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
4343
+ /* @__PURE__ */ jsx10(Box9, { children: /* @__PURE__ */ jsx10(Text11, { color: "#888888", children: game.description }) })
4178
4344
  ] }, game.id);
4179
4345
  }) }),
4180
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
4181
- doubleCtrlC && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
4346
+ /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
4347
+ doubleCtrlC && /* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
4182
4348
  ] });
4183
4349
  }
4184
4350
 
@@ -4195,9 +4361,9 @@ function listGames() {
4195
4361
  }
4196
4362
 
4197
4363
  // src/game/brick-breaker/index.tsx
4198
- import { Box as Box10, Text as Text11, useInput as useInput3, render as render2 } from "ink";
4364
+ import { Box as Box10, Text as Text12, useInput as useInput3, render as render2 } from "ink";
4199
4365
  import { useState as useState5, useEffect as useEffect4, useRef as useRef3, useCallback as useCallback4 } from "react";
4200
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
4366
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
4201
4367
  var GAME_WIDTH = 40;
4202
4368
  var GAME_HEIGHT = 18;
4203
4369
  var PADDLE_WIDTH = 9;
@@ -4389,47 +4555,47 @@ function BrickBreakerGame({ onExit: _onExit }) {
4389
4555
  void tick2;
4390
4556
  return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
4391
4557
  /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
4392
- /* @__PURE__ */ jsx10(Box10, { width: 20, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4558
+ /* @__PURE__ */ jsx11(Box10, { width: 20, children: /* @__PURE__ */ jsxs10(Text12, { children: [
4393
4559
  "\u5173\u5361 ",
4394
4560
  s.level,
4395
4561
  ": ",
4396
- /* @__PURE__ */ jsx10(Text11, { color: "cyan", children: def.desc })
4562
+ /* @__PURE__ */ jsx11(Text12, { color: "cyan", children: def.desc })
4397
4563
  ] }) }),
4398
- /* @__PURE__ */ jsx10(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4564
+ /* @__PURE__ */ jsx11(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text12, { children: [
4399
4565
  "\u5206\u6570: ",
4400
- /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: String(s.score).padStart(3, "0") })
4566
+ /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: String(s.score).padStart(3, "0") })
4401
4567
  ] }) }),
4402
- /* @__PURE__ */ jsx10(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4568
+ /* @__PURE__ */ jsx11(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text12, { children: [
4403
4569
  "\u751F\u547D: ",
4404
- /* @__PURE__ */ jsx10(Text11, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
4570
+ /* @__PURE__ */ jsx11(Text12, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
4405
4571
  ] }) }),
4406
- /* @__PURE__ */ jsx10(Box10, { width: 10, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4572
+ /* @__PURE__ */ jsx11(Box10, { width: 10, children: /* @__PURE__ */ jsxs10(Text12, { children: [
4407
4573
  "\u7816\u5757: ",
4408
- /* @__PURE__ */ jsx10(Text11, { color: "cyan", children: aliveCount })
4574
+ /* @__PURE__ */ jsx11(Text12, { color: "cyan", children: aliveCount })
4409
4575
  ] }) }),
4410
- /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsxs10(Text11, { color: s.paused ? "gray" : "green", children: [
4576
+ /* @__PURE__ */ jsx11(Box10, { children: /* @__PURE__ */ jsxs10(Text12, { color: s.paused ? "gray" : "green", children: [
4411
4577
  "[",
4412
4578
  s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
4413
4579
  "]"
4414
4580
  ] }) })
4415
4581
  ] }),
4416
4582
  /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
4417
- /* @__PURE__ */ jsxs10(Text11, { children: [
4583
+ /* @__PURE__ */ jsxs10(Text12, { children: [
4418
4584
  "\u250C",
4419
4585
  "\u2500".repeat(GAME_WIDTH),
4420
4586
  "\u2510"
4421
4587
  ] }),
4422
- /* @__PURE__ */ jsx10(Text11, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
4423
- /* @__PURE__ */ jsxs10(Text11, { children: [
4588
+ /* @__PURE__ */ jsx11(Text12, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
4589
+ /* @__PURE__ */ jsxs10(Text12, { children: [
4424
4590
  "\u2514",
4425
4591
  "\u2500".repeat(GAME_WIDTH),
4426
4592
  "\u2518"
4427
4593
  ] })
4428
4594
  ] }),
4429
4595
  selectingLevel && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
4430
- /* @__PURE__ */ jsx10(Text11, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
4431
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx10(Box10, { width: 22, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4432
- /* @__PURE__ */ jsx10(Text11, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
4596
+ /* @__PURE__ */ jsx11(Text12, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
4597
+ /* @__PURE__ */ jsx11(Box10, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx11(Box10, { width: 22, children: /* @__PURE__ */ jsxs10(Text12, { children: [
4598
+ /* @__PURE__ */ jsx11(Text12, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
4433
4599
  ". ",
4434
4600
  lv.desc,
4435
4601
  " (",
@@ -4438,16 +4604,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
4438
4604
  lv.cols,
4439
4605
  ")"
4440
4606
  ] }) }, i)) }),
4441
- /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
4607
+ /* @__PURE__ */ jsx11(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
4442
4608
  ] }),
4443
4609
  !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
4444
- /* @__PURE__ */ jsx10(Text11, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
4445
- /* @__PURE__ */ jsxs10(Text11, { children: [
4610
+ /* @__PURE__ */ jsx11(Text12, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
4611
+ /* @__PURE__ */ jsxs10(Text12, { children: [
4446
4612
  " \u5206\u6570: ",
4447
- /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: s.score })
4613
+ /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: s.score })
4448
4614
  ] })
4449
4615
  ] }),
4450
- !selectingLevel && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
4616
+ !selectingLevel && /* @__PURE__ */ jsx11(Box10, { 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" }) })
4451
4617
  ] });
4452
4618
  }
4453
4619
  var brick_breaker_default = {
@@ -4457,7 +4623,7 @@ var brick_breaker_default = {
4457
4623
  play: async () => {
4458
4624
  await new Promise((resolve2) => {
4459
4625
  const { unmount } = render2(
4460
- /* @__PURE__ */ jsx10(BrickBreakerGame, { onExit: () => {
4626
+ /* @__PURE__ */ jsx11(BrickBreakerGame, { onExit: () => {
4461
4627
  unmount();
4462
4628
  resolve2();
4463
4629
  } })
@@ -4467,9 +4633,9 @@ var brick_breaker_default = {
4467
4633
  };
4468
4634
 
4469
4635
  // src/game/coder-check/index.tsx
4470
- import { Box as Box11, Text as Text12, useInput as useInput4, render as render3 } from "ink";
4636
+ import { Box as Box11, Text as Text13, useInput as useInput4, render as render3 } from "ink";
4471
4637
  import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback5 } from "react";
4472
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
4638
+ import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4473
4639
  var GAME_W = 66;
4474
4640
  var GAME_H = 20;
4475
4641
  var SCORE_H = 6;
@@ -4941,43 +5107,43 @@ function CoderCheck({ onExit: _onExit }) {
4941
5107
  const view = buildGameView(s, scoreLines, scoreColor, s.message);
4942
5108
  void tick2;
4943
5109
  return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, children: [
4944
- /* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: /* @__PURE__ */ jsxs11(Text12, { children: [
5110
+ /* @__PURE__ */ jsx12(Box11, { flexDirection: "row", children: /* @__PURE__ */ jsxs11(Text13, { children: [
4945
5111
  "\u751F\u547D ",
4946
- /* @__PURE__ */ jsx11(Text12, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
5112
+ /* @__PURE__ */ jsx12(Text13, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
4947
5113
  " ",
4948
5114
  "\u901F\u5EA6 ",
4949
- /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
5115
+ /* @__PURE__ */ jsxs11(Text13, { color: "cyan", children: [
4950
5116
  "Lv.",
4951
5117
  Math.floor(s.speed * 10)
4952
5118
  ] })
4953
5119
  ] }) }),
4954
- !s.gameOver && s.target && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { children: [
5120
+ !s.gameOver && s.target && /* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text13, { children: [
4955
5121
  "\u6253\u5B57: ",
4956
- /* @__PURE__ */ jsx11(Text12, { color: "green", children: s.typed }),
4957
- /* @__PURE__ */ jsx11(Text12, { color: "white", children: s.target.slice(s.typed.length) })
5122
+ /* @__PURE__ */ jsx12(Text13, { color: "green", children: s.typed }),
5123
+ /* @__PURE__ */ jsx12(Text13, { color: "white", children: s.target.slice(s.typed.length) })
4958
5124
  ] }) }),
4959
5125
  /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
4960
- /* @__PURE__ */ jsxs11(Text12, { children: [
5126
+ /* @__PURE__ */ jsxs11(Text13, { children: [
4961
5127
  "\u250C",
4962
5128
  "\u2500".repeat(GAME_W),
4963
5129
  "\u2510"
4964
5130
  ] }),
4965
- view.map((row, i) => /* @__PURE__ */ jsx11(Text12, { children: `\u2502${row}\u2502` }, i)),
4966
- /* @__PURE__ */ jsxs11(Text12, { children: [
5131
+ view.map((row, i) => /* @__PURE__ */ jsx12(Text13, { children: `\u2502${row}\u2502` }, i)),
5132
+ /* @__PURE__ */ jsxs11(Text13, { children: [
4967
5133
  "\u2514",
4968
5134
  "\u2500".repeat(GAME_W),
4969
5135
  "\u2518"
4970
5136
  ] })
4971
5137
  ] }),
4972
5138
  s.gameOver && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
4973
- /* @__PURE__ */ jsx11(Text12, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
4974
- /* @__PURE__ */ jsxs11(Text12, { children: [
5139
+ /* @__PURE__ */ jsx12(Text13, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
5140
+ /* @__PURE__ */ jsxs11(Text13, { children: [
4975
5141
  " \u5F97\u5206: ",
4976
- /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: s.score }),
5142
+ /* @__PURE__ */ jsx12(Text13, { color: "yellow", children: s.score }),
4977
5143
  " r \u91CD\u5F00 q \u9000\u51FA"
4978
5144
  ] })
4979
5145
  ] }),
4980
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
5146
+ /* @__PURE__ */ jsx12(Box11, { 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" }) })
4981
5147
  ] });
4982
5148
  }
4983
5149
  var coder_check_default = {
@@ -4987,7 +5153,7 @@ var coder_check_default = {
4987
5153
  play: async () => {
4988
5154
  await new Promise((resolve2) => {
4989
5155
  const { unmount } = render3(
4990
- /* @__PURE__ */ jsx11(CoderCheck, { onExit: () => {
5156
+ /* @__PURE__ */ jsx12(CoderCheck, { onExit: () => {
4991
5157
  unmount();
4992
5158
  resolve2();
4993
5159
  } })
@@ -5367,12 +5533,12 @@ import { render as render4 } from "ink";
5367
5533
  import chalk5 from "chalk";
5368
5534
 
5369
5535
  // src/stock/StockList.tsx
5370
- import { Box as Box12, Text as Text13, useInput as useInput5 } from "ink";
5536
+ import { Box as Box12, Text as Text14, useInput as useInput5 } from "ink";
5371
5537
  import { useState as useState7, useCallback as useCallback6, useEffect as useEffect6 } from "react";
5372
5538
  import asciichart from "asciichart";
5373
5539
  import os from "os";
5374
5540
  import { join as join7 } from "path";
5375
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
5541
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5376
5542
  var SETTINGS_PATH = join7(os.homedir(), ".dskcode", "settings.json");
5377
5543
  function toFileUrl(p) {
5378
5544
  const norm = p.replace(/\\/g, "/");
@@ -5583,61 +5749,61 @@ function StockList({ codes, onExit, onBackToChat }) {
5583
5749
  );
5584
5750
  if (detailView) {
5585
5751
  if (detailLoading) {
5586
- return /* @__PURE__ */ jsx12(Box12, { paddingLeft: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
5752
+ return /* @__PURE__ */ jsx13(Box12, { paddingLeft: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
5587
5753
  }
5588
5754
  return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
5589
5755
  }
5590
5756
  const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
5591
5757
  return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
5592
5758
  /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, justifyContent: "space-between", children: [
5593
- /* @__PURE__ */ jsx12(Text13, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
5594
- /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
5759
+ /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
5760
+ /* @__PURE__ */ jsxs12(Text14, { dimColor: true, children: [
5595
5761
  " \u{1F550} ",
5596
5762
  currentTime
5597
5763
  ] }),
5598
- /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
5764
+ /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
5599
5765
  ] }),
5600
5766
  /* @__PURE__ */ jsxs12(Box12, { children: [
5601
- /* @__PURE__ */ jsx12(Box12, { width: 3 }),
5602
- /* @__PURE__ */ jsx12(Box12, { width: 9, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u4EE3\u7801" }) }),
5603
- /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u540D\u79F0" }) }),
5604
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
5605
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
5606
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
5607
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u9AD8" }) }),
5608
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u4F4E" }) }),
5609
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
5767
+ /* @__PURE__ */ jsx13(Box12, { width: 3 }),
5768
+ /* @__PURE__ */ jsx13(Box12, { width: 9, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u4EE3\u7801" }) }),
5769
+ /* @__PURE__ */ jsx13(Box12, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u540D\u79F0" }) }),
5770
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
5771
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
5772
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
5773
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u9AD8" }) }),
5774
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6700\u4F4E" }) }),
5775
+ /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
5610
5776
  ] }),
5611
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
5612
- /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: stocks.map((stock, index) => {
5777
+ /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
5778
+ /* @__PURE__ */ jsx13(Box12, { flexDirection: "column", children: stocks.map((stock, index) => {
5613
5779
  const isSelected = index === selectedIndex;
5614
5780
  const isUp = stock.changePercent >= 0;
5615
5781
  const color = isUp ? "#ff1493" : "#00ff41";
5616
5782
  return /* @__PURE__ */ jsxs12(Box12, { children: [
5617
- /* @__PURE__ */ jsx12(Box12, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx12(Text13, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx12(Text13, { children: " " }) }),
5618
- /* @__PURE__ */ jsx12(Box12, { width: 9, children: /* @__PURE__ */ jsx12(Text13, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
5619
- /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
5620
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
5621
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { ...cp2(color), children: [
5783
+ /* @__PURE__ */ jsx13(Box12, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx13(Text14, { children: " " }) }),
5784
+ /* @__PURE__ */ jsx13(Box12, { width: 9, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
5785
+ /* @__PURE__ */ jsx13(Box12, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
5786
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
5787
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text14, { ...cp2(color), children: [
5622
5788
  isUp ? "+" : "",
5623
5789
  stock.changePercent.toFixed(2),
5624
5790
  "%"
5625
5791
  ] }) }),
5626
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { ...cp2(color), children: [
5792
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text14, { ...cp2(color), children: [
5627
5793
  isUp ? "+" : "",
5628
5794
  stock.changeAmount.toFixed(3)
5629
5795
  ] }) }),
5630
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
5631
- /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
5632
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
5796
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
5797
+ /* @__PURE__ */ jsx13(Box12, { width: 12, children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
5798
+ /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsx13(Text14, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
5633
5799
  ] }, stock.code);
5634
5800
  }) }),
5635
- /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 h \u7F6E\u7070/\u6062\u590D q \u8FD4\u56DE` }) }),
5801
+ /* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 h \u7F6E\u7070/\u6062\u590D q \u8FD4\u56DE` }) }),
5636
5802
  /* @__PURE__ */ jsxs12(Box12, { children: [
5637
- /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
5638
- /* @__PURE__ */ jsx12(Text13, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
5803
+ /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
5804
+ /* @__PURE__ */ jsx13(Text14, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
5639
5805
  ] }),
5640
- doubleCtrlC && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
5806
+ doubleCtrlC && /* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
5641
5807
  ] });
5642
5808
  }
5643
5809
  function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
@@ -5658,30 +5824,30 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
5658
5824
  return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, children: [
5659
5825
  /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, justifyContent: "space-between", children: [
5660
5826
  /* @__PURE__ */ jsxs12(Box12, { children: [
5661
- /* @__PURE__ */ jsxs12(Text13, { bold: true, color: "#00ffff", children: [
5827
+ /* @__PURE__ */ jsxs12(Text14, { bold: true, color: "#00ffff", children: [
5662
5828
  " \u{1F4CA} ",
5663
5829
  stock.name,
5664
5830
  " "
5665
5831
  ] }),
5666
- /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: stock.code }),
5667
- currentTime && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
5832
+ /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: stock.code }),
5833
+ currentTime && /* @__PURE__ */ jsxs12(Text14, { dimColor: true, children: [
5668
5834
  " \u{1F550} ",
5669
5835
  currentTime
5670
5836
  ] })
5671
5837
  ] }),
5672
- /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
5838
+ /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
5673
5839
  ] }),
5674
5840
  /* @__PURE__ */ jsxs12(Box12, { children: [
5675
- /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
5676
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { bold: true, color: colorCode, children: [
5841
+ /* @__PURE__ */ jsx13(Box12, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
5842
+ /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsxs12(Text14, { bold: true, color: colorCode, children: [
5677
5843
  arrow,
5678
5844
  " ",
5679
5845
  formatPrice(stock.price)
5680
5846
  ] }) })
5681
5847
  ] }),
5682
5848
  /* @__PURE__ */ jsxs12(Box12, { children: [
5683
- /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
5684
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: colorCode, children: [
5849
+ /* @__PURE__ */ jsx13(Box12, { width: 16, children: /* @__PURE__ */ jsx13(Text14, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
5850
+ /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsxs12(Text14, { color: colorCode, children: [
5685
5851
  isUp ? "+" : "",
5686
5852
  stock.changePercent.toFixed(2),
5687
5853
  "%",
@@ -5690,8 +5856,8 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
5690
5856
  stock.changeAmount.toFixed(3)
5691
5857
  ] }) })
5692
5858
  ] }),
5693
- chartLines.length > 0 && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { color: colorCode, children: line || " " }) }, i)) }),
5694
- /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
5859
+ chartLines.length > 0 && /* @__PURE__ */ jsx13(Box12, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx13(Box12, { children: /* @__PURE__ */ jsx13(Text14, { color: colorCode, children: line || " " }) }, i)) }),
5860
+ /* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
5695
5861
  ] });
5696
5862
  }
5697
5863
 
@@ -5776,7 +5942,7 @@ async function scanProjectFiles(baseDir, dir) {
5776
5942
  }
5777
5943
 
5778
5944
  // src/cli/index.tsx
5779
- import { jsx as jsx13 } from "react/jsx-runtime";
5945
+ import { jsx as jsx14 } from "react/jsx-runtime";
5780
5946
  var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
5781
5947
  function createCli() {
5782
5948
  const program2 = new Command();
@@ -5822,7 +5988,7 @@ function createCli() {
5822
5988
  );
5823
5989
  const model = defaultProvider?.model ?? "deepseek-v4-flash";
5824
5990
  const chatApp = renderApp(
5825
- /* @__PURE__ */ jsx13(
5991
+ /* @__PURE__ */ jsx14(
5826
5992
  ChatSession,
5827
5993
  {
5828
5994
  skillCount,
@@ -5840,7 +6006,7 @@ function createCli() {
5840
6006
  initGames();
5841
6007
  const games = listGames();
5842
6008
  const { unmount } = render4(
5843
- /* @__PURE__ */ jsx13(
6009
+ /* @__PURE__ */ jsx14(
5844
6010
  GamePicker,
5845
6011
  {
5846
6012
  games,
@@ -5864,7 +6030,7 @@ function createCli() {
5864
6030
  setImmediate(() => {
5865
6031
  const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
5866
6032
  const stockApp = renderApp(
5867
- /* @__PURE__ */ jsx13(
6033
+ /* @__PURE__ */ jsx14(
5868
6034
  StockList,
5869
6035
  {
5870
6036
  codes: defaultStockCodes,
@@ -5951,7 +6117,7 @@ compdef _dskcode_completion dskcode`);
5951
6117
  const freshResult = await loadAndValidate();
5952
6118
  const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
5953
6119
  const app = renderApp(
5954
- /* @__PURE__ */ jsx13(
6120
+ /* @__PURE__ */ jsx14(
5955
6121
  StockList,
5956
6122
  {
5957
6123
  codes: codeList,
@@ -5980,7 +6146,7 @@ compdef _dskcode_completion dskcode`);
5980
6146
  }
5981
6147
  const selectedGame = await new Promise((resolve2) => {
5982
6148
  const { unmount } = render4(
5983
- /* @__PURE__ */ jsx13(
6149
+ /* @__PURE__ */ jsx14(
5984
6150
  GamePicker,
5985
6151
  {
5986
6152
  games,