dskcode 0.1.16 → 0.1.17

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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  DeepSeekProvider,
4
4
  ModelNotSupportedError
5
- } from "./chunk-HWZZJB6I.js";
5
+ } from "./chunk-BA7UJPKJ.js";
6
6
  import {
7
7
  SUPPORTED_MODELS,
8
8
  calculateCost,
@@ -451,7 +451,7 @@ async function promptForApiKey() {
451
451
  input: process.stdin,
452
452
  output: process.stdout
453
453
  });
454
- return new Promise((resolve) => {
454
+ return new Promise((resolve2) => {
455
455
  let resolved = false;
456
456
  const cleanup = () => {
457
457
  if (resolved) return;
@@ -462,7 +462,7 @@ async function promptForApiKey() {
462
462
  const onKeypress = (_, key) => {
463
463
  if (key.ctrl && key.name === "c") {
464
464
  cleanup();
465
- resolve(null);
465
+ resolve2(null);
466
466
  }
467
467
  };
468
468
  process.stdin.on("keypress", onKeypress);
@@ -473,15 +473,15 @@ async function promptForApiKey() {
473
473
  const trimmed = answer.trim();
474
474
  if (!trimmed) {
475
475
  console.log(chalk2.red(" \u2716 API Key \u4E0D\u80FD\u4E3A\u7A7A"));
476
- resolve(null);
476
+ resolve2(null);
477
477
  return;
478
478
  }
479
479
  if (trimmed.length < MIN_API_KEY_LENGTH) {
480
480
  console.log(chalk2.red(" \u2716 API Key \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u957F\u5EA6\u81F3\u5C11 10 \u4F4D"));
481
- resolve(null);
481
+ resolve2(null);
482
482
  return;
483
483
  }
484
- resolve(trimmed);
484
+ resolve2(trimmed);
485
485
  }
486
486
  );
487
487
  });
@@ -521,8 +521,8 @@ async function listClaudeSkills() {
521
521
  const skills = [];
522
522
  for (const name of entries) {
523
523
  const full = join2(claudeDir, name);
524
- const stat = statSync(full);
525
- if (stat.isDirectory() && await isSkillDir(full)) {
524
+ const stat5 = statSync(full);
525
+ if (stat5.isDirectory() && await isSkillDir(full)) {
526
526
  skills.push(name);
527
527
  }
528
528
  }
@@ -533,7 +533,7 @@ function askConfirm(question) {
533
533
  input: process.stdin,
534
534
  output: process.stdout
535
535
  });
536
- return new Promise((resolve) => {
536
+ return new Promise((resolve2) => {
537
537
  let resolved = false;
538
538
  const cleanup = () => {
539
539
  if (resolved) return;
@@ -544,14 +544,14 @@ function askConfirm(question) {
544
544
  const onKeypress = (_, key) => {
545
545
  if (key.ctrl && key.name === "c") {
546
546
  cleanup();
547
- resolve(false);
547
+ resolve2(false);
548
548
  }
549
549
  };
550
550
  process.stdin.on("keypress", onKeypress);
551
551
  rl.question(question, (answer) => {
552
552
  cleanup();
553
553
  const trimmed = answer.trim().toLowerCase();
554
- resolve(trimmed === "y" || trimmed === "yes");
554
+ resolve2(trimmed === "y" || trimmed === "yes");
555
555
  });
556
556
  });
557
557
  }
@@ -611,8 +611,8 @@ async function countProjectLocalSkills(cwd) {
611
611
  let count = 0;
612
612
  for (const name of entries) {
613
613
  const full = join2(skillDir, name);
614
- const stat = statSync(full);
615
- if (stat.isDirectory() && await isSkillDir(full)) {
614
+ const stat5 = statSync(full);
615
+ if (stat5.isDirectory() && await isSkillDir(full)) {
616
616
  count++;
617
617
  }
618
618
  }
@@ -629,8 +629,8 @@ async function hasDskcodeSkills() {
629
629
  }
630
630
  for (const name of entries) {
631
631
  const full = join2(dskcodeDir, name);
632
- const stat = statSync(full);
633
- if (stat.isDirectory() && await isSkillDir(full)) {
632
+ const stat5 = statSync(full);
633
+ if (stat5.isDirectory() && await isSkillDir(full)) {
634
634
  return true;
635
635
  }
636
636
  }
@@ -773,8 +773,8 @@ async function getAllSkills(cwd) {
773
773
  }
774
774
 
775
775
  // src/cli/index.tsx
776
- import { readFile as readFile4 } from "fs/promises";
777
- import { join as join5 } from "path";
776
+ import { readFile as readFile8 } from "fs/promises";
777
+ import { join as join8 } from "path";
778
778
 
779
779
  // src/ui/RenderScope.tsx
780
780
  import { render } from "ink";
@@ -816,7 +816,7 @@ var LOGO_LINES = [
816
816
  ];
817
817
 
818
818
  // src/ui/ChatSession.tsx
819
- import { Box as Box7, Text as Text8, useInput, Static } from "ink";
819
+ import { Box as Box8, Text as Text9, useInput, Static } from "ink";
820
820
  import TextInput from "ink-text-input";
821
821
  import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useRef as useRef2 } from "react";
822
822
 
@@ -1280,9 +1280,54 @@ function AssistantMessage({
1280
1280
  ] });
1281
1281
  }
1282
1282
 
1283
- // src/ui/SkillSelector.tsx
1283
+ // src/ui/DiffPreview.tsx
1284
1284
  import { Box as Box5, Text as Text6 } from "ink";
1285
1285
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1286
+ function DiffPreview({ diff }) {
1287
+ const { patch, additions, deletions, existedBefore, filePath } = diff;
1288
+ if (!patch || patch.length === 0) {
1289
+ return null;
1290
+ }
1291
+ const lines = patch.split("\n");
1292
+ const fileName = filePath.replace(/\\/g, "/").split("/").pop() ?? filePath;
1293
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1294
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", gap: 1, children: [
1295
+ /* @__PURE__ */ jsxs5(Text6, { bold: true, color: "#00ffff", children: [
1296
+ "\u{1F4DD} ",
1297
+ existedBefore ? "\u4FEE\u6539" : "\u65B0\u5EFA",
1298
+ ":"
1299
+ ] }),
1300
+ /* @__PURE__ */ jsx5(Text6, { bold: true, children: fileName }),
1301
+ /* @__PURE__ */ jsxs5(Text6, { color: "#555555", children: [
1302
+ "(+",
1303
+ additions,
1304
+ " -",
1305
+ deletions,
1306
+ ")"
1307
+ ] })
1308
+ ] }),
1309
+ /* @__PURE__ */ jsx5(Box5, { flexDirection: "column", marginLeft: 2, children: lines.map((line, i) => /* @__PURE__ */ jsx5(DiffLine, { line }, i)) })
1310
+ ] });
1311
+ }
1312
+ function DiffLine({ line }) {
1313
+ if (line.startsWith("---") || line.startsWith("+++")) {
1314
+ return /* @__PURE__ */ jsx5(Text6, { color: "#00cccc", bold: true, children: line });
1315
+ }
1316
+ if (line.startsWith("@@")) {
1317
+ return /* @__PURE__ */ jsx5(Text6, { color: "#00cccc", children: line });
1318
+ }
1319
+ if (line.startsWith("+")) {
1320
+ return /* @__PURE__ */ jsx5(Text6, { color: "#22c55e", children: line });
1321
+ }
1322
+ if (line.startsWith("-")) {
1323
+ return /* @__PURE__ */ jsx5(Text6, { color: "#ef4444", children: line });
1324
+ }
1325
+ return /* @__PURE__ */ jsx5(Text6, { color: "#6b7280", children: line });
1326
+ }
1327
+
1328
+ // src/ui/SkillSelector.tsx
1329
+ import { Box as Box6, Text as Text7 } from "ink";
1330
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1286
1331
  var HIGHLIGHT_COLOR = "#00bfff";
1287
1332
  function SkillSelector({ skills, input, selectedIndex }) {
1288
1333
  const match = input.match(/(?:^|\s)\/([^/]*)$/);
@@ -1292,19 +1337,19 @@ function SkillSelector({ skills, input, selectedIndex }) {
1292
1337
  const matched = !query && input.startsWith("/") ? skills.slice(0, 3) : skills.filter((s) => s.name.toLowerCase().includes(query)).slice(0, 3);
1293
1338
  if (query && matched.length > 0 && matched.some((s) => s.name.toLowerCase() === query)) return null;
1294
1339
  if (matched.length === 0) return null;
1295
- return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1296
- /* @__PURE__ */ jsx5(Text6, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
1297
- matched.map((skill, i) => /* @__PURE__ */ jsx5(Box5, { children: /* @__PURE__ */ jsxs5(Text6, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
1340
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1341
+ /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u652F\u6301\u7684 Skill\uFF1A" }),
1342
+ matched.map((skill, i) => /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text7, { color: i === selectedIndex ? HIGHLIGHT_COLOR : "#808080", children: [
1298
1343
  i === selectedIndex ? " \u203A " : " ",
1299
1344
  skill.name
1300
1345
  ] }) }, skill.name)),
1301
- /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text6, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1346
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1302
1347
  ] });
1303
1348
  }
1304
1349
 
1305
1350
  // src/ui/FileSelector.tsx
1306
- import { Box as Box6, Text as Text7 } from "ink";
1307
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1351
+ import { Box as Box7, Text as Text8 } from "ink";
1352
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1308
1353
  var HIGHLIGHT_COLOR2 = "#00ff41";
1309
1354
  function FileSelector({ files, input, selectedIndex }) {
1310
1355
  const match = input.match(/(?:^|\s)@([^@]*)$/);
@@ -1314,13 +1359,13 @@ function FileSelector({ files, input, selectedIndex }) {
1314
1359
  const matched = !query && input.startsWith("@") ? files.slice(0, 5) : files.filter((f) => f.toLowerCase().includes(query)).slice(0, 5);
1315
1360
  if (query && matched.some((f) => f.toLowerCase() === query)) return null;
1316
1361
  if (matched.length === 0) return null;
1317
- return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1318
- /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
1319
- matched.map((file, i) => /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text7, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
1362
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginLeft: 4, marginTop: 1, children: [
1363
+ /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u9879\u76EE\u6587\u4EF6\uFF1A" }),
1364
+ matched.map((file, i) => /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { color: i === selectedIndex ? HIGHLIGHT_COLOR2 : "#808080", children: [
1320
1365
  i === selectedIndex ? " \u203A " : " ",
1321
1366
  file
1322
1367
  ] }) }, file)),
1323
- /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text7, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1368
+ /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Tab \u8865\u5168" }) })
1324
1369
  ] });
1325
1370
  }
1326
1371
 
@@ -1473,17 +1518,132 @@ ${opts.projectContext}`);
1473
1518
  return sections.join("\n\n");
1474
1519
  }
1475
1520
 
1521
+ // src/tool/registry.ts
1522
+ var ToolRegistry = class {
1523
+ #tools = /* @__PURE__ */ new Map();
1524
+ #disabledNames;
1525
+ constructor(opts) {
1526
+ this.#disabledNames = new Set(opts?.disabledTools ?? []);
1527
+ }
1528
+ /**
1529
+ * 注册一个工具。
1530
+ * 如果同名工具已存在则抛出错误。
1531
+ */
1532
+ register(tool) {
1533
+ if (this.#tools.has(tool.name)) {
1534
+ throw new Error(`\u5DE5\u5177 "${tool.name}" \u5DF2\u6CE8\u518C\uFF0C\u4E0D\u80FD\u91CD\u590D\u6CE8\u518C`);
1535
+ }
1536
+ this.#tools.set(tool.name, tool);
1537
+ return this;
1538
+ }
1539
+ /**
1540
+ * 批量注册工具。
1541
+ */
1542
+ registerAll(tools) {
1543
+ for (const tool of tools) {
1544
+ this.register(tool);
1545
+ }
1546
+ return this;
1547
+ }
1548
+ /**
1549
+ * 注销一个工具。
1550
+ */
1551
+ unregister(name) {
1552
+ return this.#tools.delete(name);
1553
+ }
1554
+ /**
1555
+ * 按名称获取工具。
1556
+ * 如果工具被禁用或不存在,返回 undefined。
1557
+ */
1558
+ get(name) {
1559
+ if (this.#disabledNames.has(name)) return void 0;
1560
+ return this.#tools.get(name);
1561
+ }
1562
+ /**
1563
+ * 获取所有启用的工具列表。
1564
+ */
1565
+ list() {
1566
+ const result = [];
1567
+ for (const [name, tool] of this.#tools) {
1568
+ if (!this.#disabledNames.has(name)) {
1569
+ result.push(tool);
1570
+ }
1571
+ }
1572
+ return result;
1573
+ }
1574
+ /**
1575
+ * 获取所有已注册的工具名称(含禁用的)。
1576
+ */
1577
+ names() {
1578
+ return [...this.#tools.keys()];
1579
+ }
1580
+ /**
1581
+ * 检查工具是否已注册(含禁用的)。
1582
+ */
1583
+ has(name) {
1584
+ return this.#tools.has(name);
1585
+ }
1586
+ /**
1587
+ * 检查工具是否已启用。
1588
+ */
1589
+ isEnabled(name) {
1590
+ return this.#tools.has(name) && !this.#disabledNames.has(name);
1591
+ }
1592
+ /**
1593
+ * 禁用一个工具。
1594
+ */
1595
+ disable(name) {
1596
+ this.#disabledNames.add(name);
1597
+ }
1598
+ /**
1599
+ * 启用一个之前被禁用的工具。
1600
+ */
1601
+ enable(name) {
1602
+ this.#disabledNames.delete(name);
1603
+ }
1604
+ /**
1605
+ * 执行指定工具。
1606
+ *
1607
+ * @returns 工具执行结果;如果工具不存在或被禁用,返回失败结果
1608
+ */
1609
+ async execute(name, args, ctx) {
1610
+ const tool = this.get(name);
1611
+ if (!tool) {
1612
+ return {
1613
+ success: false,
1614
+ data: `\u5DE5\u5177 "${name}" \u4E0D\u5B58\u5728\u6216\u5DF2\u88AB\u7981\u7528`,
1615
+ error: "TOOL_NOT_FOUND"
1616
+ };
1617
+ }
1618
+ try {
1619
+ return await tool.execute(args, ctx);
1620
+ } catch (err) {
1621
+ const message = err instanceof Error ? err.message : String(err);
1622
+ return {
1623
+ success: false,
1624
+ data: `\u5DE5\u5177 "${name}" \u6267\u884C\u5F02\u5E38\uFF1A${message}`,
1625
+ error: "EXECUTION_ERROR"
1626
+ };
1627
+ }
1628
+ }
1629
+ };
1630
+
1476
1631
  // src/agent/index.ts
1477
1632
  var Session = class {
1478
1633
  #messages = [];
1479
1634
  #provider;
1480
- #tools;
1635
+ #toolRegistry;
1481
1636
  #costTracker;
1482
1637
  #options;
1483
1638
  #abortController = new AbortController();
1484
1639
  constructor(provider, tools = [], costTracker, options) {
1485
1640
  this.#provider = provider;
1486
- this.#tools = tools;
1641
+ if (tools instanceof ToolRegistry) {
1642
+ this.#toolRegistry = tools;
1643
+ } else {
1644
+ this.#toolRegistry = new ToolRegistry();
1645
+ this.#toolRegistry.registerAll(tools);
1646
+ }
1487
1647
  this.#costTracker = costTracker ?? new CostTracker();
1488
1648
  this.#options = {
1489
1649
  cwd: options?.cwd ?? process.cwd(),
@@ -1508,18 +1668,32 @@ var Session = class {
1508
1668
  get model() {
1509
1669
  return this.#provider.model();
1510
1670
  }
1671
+ /** 获取工具注册表(只读视图) */
1672
+ get toolRegistry() {
1673
+ return this.#toolRegistry;
1674
+ }
1511
1675
  // -------------------------------------------------------------------------
1512
1676
  // 流式对话 — Agent 主循环
1513
1677
  // -------------------------------------------------------------------------
1514
1678
  /**
1515
- * 执行一轮对话,以 AsyncGenerator 形式逐步 yield 事件。
1679
+ * 执行一轮用户对话,以 AsyncGenerator 形式逐步 yield 事件。
1680
+ *
1681
+ * 主循环流程:
1682
+ * 1. 追加用户消息
1683
+ * 2. 进入 Agent 循环(最多 maxToolRounds 轮)
1684
+ * a. 构建消息 → 裁剪 → 调用 Provider 流式接口
1685
+ * b. 解析响应:文本增量、工具调用、使用量
1686
+ * c. 如果有工具调用 → 执行工具 → 追加结果 → 继续循环
1687
+ * d. 如果没有工具调用 → 退出循环
1688
+ * 3. yield done 事件
1516
1689
  *
1517
1690
  * 调用方式:
1518
1691
  * ```ts
1519
1692
  * for await (const event of session.chat("你好")) {
1520
1693
  * switch (event.type) {
1521
- * case "text_delta": // 追加文本
1694
+ * case "text_delta": // 追加文本
1522
1695
  * case "tool_calls": // 展示工具调用
1696
+ * case "tool_result": // 工具执行结果
1523
1697
  * case "usage": // 记录使用量
1524
1698
  * case "done": // 本轮完成
1525
1699
  * case "error": // 处理错误
@@ -1529,75 +1703,91 @@ var Session = class {
1529
1703
  */
1530
1704
  async *chat(userInput) {
1531
1705
  this.#messages.push({ role: "user", content: userInput });
1532
- const systemPrompt = this.#buildSystemPrompt();
1533
- const [trimmed, wasTrimmed] = trimMessages(
1534
- [...this.#messages],
1535
- {
1536
- model: this.#provider.model(),
1537
- reservedForOutput: this.#options.reservedForOutput,
1538
- systemPrompt,
1539
- preserveRecentRounds: this.#options.preserveRecentRounds
1540
- }
1541
- );
1542
- if (wasTrimmed) {
1543
- }
1544
- const apiMessages = buildApiMessages(systemPrompt, trimmed);
1545
- const toolDefs = this.#buildToolDefinitions();
1546
1706
  const startTime = Date.now();
1707
+ let toolRounds = 0;
1547
1708
  try {
1548
- const stream = this.#provider.chat(apiMessages, {
1549
- signal: this.#abortController.signal
1550
- // 将工具定义传给 provider(如支持 function calling)
1551
- // 注意:当前 chat() 签名不含 tools 参数,
1552
- // 工具定义在 system prompt 中描述,由模型通过文本方式请求
1553
- });
1554
- let accumulatedText = "";
1555
- let lastUsage;
1556
- let lastToolCalls;
1557
- let lastFinishReason = null;
1558
- for await (const chunk of stream) {
1559
- if (chunk.content) {
1560
- accumulatedText += chunk.content;
1561
- yield { type: "text_delta", content: chunk.content };
1562
- }
1563
- if (chunk.toolCalls && chunk.toolCalls.length > 0) {
1564
- lastToolCalls = chunk.toolCalls;
1709
+ while (toolRounds < this.#options.maxToolRounds) {
1710
+ const systemPrompt = this.#buildSystemPrompt();
1711
+ const [trimmed] = trimMessages(
1712
+ [...this.#messages],
1713
+ {
1714
+ model: this.#provider.model(),
1715
+ reservedForOutput: this.#options.reservedForOutput,
1716
+ systemPrompt,
1717
+ preserveRecentRounds: this.#options.preserveRecentRounds
1718
+ }
1719
+ );
1720
+ const apiMessages = buildApiMessages(systemPrompt, trimmed);
1721
+ const toolDefs = this.#buildToolDefinitions();
1722
+ const stream = this.#provider.chat(apiMessages, {
1723
+ signal: this.#abortController.signal,
1724
+ tools: toolDefs.length > 0 ? toolDefs : void 0
1725
+ });
1726
+ let accumulatedText = "";
1727
+ let lastUsage;
1728
+ let lastToolCalls;
1729
+ let lastFinishReason = null;
1730
+ for await (const chunk of stream) {
1731
+ if (chunk.content) {
1732
+ accumulatedText += chunk.content;
1733
+ yield { type: "text_delta", content: chunk.content };
1734
+ }
1735
+ if (chunk.toolCalls && chunk.toolCalls.length > 0) {
1736
+ lastToolCalls = chunk.toolCalls;
1737
+ }
1738
+ if (chunk.usage) {
1739
+ lastUsage = chunk.usage;
1740
+ }
1741
+ if (chunk.finishReason) {
1742
+ lastFinishReason = chunk.finishReason;
1743
+ }
1565
1744
  }
1566
- if (chunk.usage) {
1567
- lastUsage = chunk.usage;
1745
+ if (lastUsage) {
1746
+ const modelId = this.#provider.model();
1747
+ this.#costTracker.record(lastUsage, modelId);
1748
+ yield { type: "usage", usage: lastUsage, model: modelId };
1568
1749
  }
1569
- if (chunk.finishReason) {
1570
- lastFinishReason = chunk.finishReason;
1750
+ const assistantMsg = {
1751
+ role: "assistant",
1752
+ content: accumulatedText
1753
+ };
1754
+ if (lastToolCalls && lastToolCalls.length > 0) {
1755
+ assistantMsg.toolCalls = lastToolCalls;
1571
1756
  }
1572
- }
1573
- if (lastToolCalls && lastToolCalls.length > 0) {
1574
- yield { type: "tool_calls", calls: lastToolCalls };
1575
- }
1576
- if (lastUsage) {
1577
- const modelId = this.#provider.model();
1578
- const costInfo = this.#costTracker.record(lastUsage, modelId);
1579
- yield { type: "usage", usage: lastUsage, model: modelId };
1580
- }
1581
- const assistantMsg = {
1582
- role: "assistant",
1583
- content: accumulatedText
1584
- };
1585
- if (lastToolCalls && lastToolCalls.length > 0) {
1586
- assistantMsg.toolCalls = lastToolCalls;
1587
- }
1588
- this.#messages.push(assistantMsg);
1589
- if (lastToolCalls && lastToolCalls.length > 0) {
1590
- for (const tc of lastToolCalls) {
1591
- this.#messages.push({
1592
- role: "tool",
1593
- content: `\u26A0 \u5DE5\u5177 "${tc.name}" \u7B49\u5F85\u6267\u884C\uFF08\u5DE5\u5177\u7CFB\u7EDF\u5C06\u5728\u7B2C08\u7AE0\u5B9E\u73B0\uFF09`,
1594
- toolCallId: tc.id,
1595
- name: tc.name
1596
- });
1757
+ this.#messages.push(assistantMsg);
1758
+ if (lastToolCalls && lastToolCalls.length > 0) {
1759
+ yield { type: "tool_calls", calls: lastToolCalls };
1760
+ const toolCtx = {
1761
+ cwd: this.#options.cwd,
1762
+ signal: this.#abortController.signal
1763
+ };
1764
+ for (const tc of lastToolCalls) {
1765
+ let toolArgs;
1766
+ try {
1767
+ toolArgs = tc.arguments ? JSON.parse(tc.arguments) : {};
1768
+ } catch {
1769
+ toolArgs = {};
1770
+ }
1771
+ const result = await this.#toolRegistry.execute(tc.name, toolArgs, toolCtx);
1772
+ yield { type: "tool_result", name: tc.name, result };
1773
+ let toolContent = result.data;
1774
+ if (result.diff && result.diff.patch) {
1775
+ toolContent += `
1776
+
1777
+ ${result.diff.patch}`;
1778
+ }
1779
+ this.#messages.push({
1780
+ role: "tool",
1781
+ content: toolContent,
1782
+ toolCallId: tc.id,
1783
+ name: tc.name
1784
+ });
1785
+ }
1786
+ toolRounds++;
1787
+ continue;
1597
1788
  }
1789
+ break;
1598
1790
  }
1599
- const elapsed = Date.now() - startTime;
1600
- yield { type: "done", elapsed };
1601
1791
  } catch (err) {
1602
1792
  if (err instanceof DOMException && err.name === "AbortError") {
1603
1793
  return;
@@ -1609,7 +1799,10 @@ var Session = class {
1609
1799
  type: "error",
1610
1800
  error: err instanceof Error ? err : new Error(String(err))
1611
1801
  };
1802
+ return;
1612
1803
  }
1804
+ const elapsed = Date.now() - startTime;
1805
+ yield { type: "done", elapsed };
1613
1806
  }
1614
1807
  // -------------------------------------------------------------------------
1615
1808
  // 会话管理
@@ -1628,7 +1821,8 @@ var Session = class {
1628
1821
  // -------------------------------------------------------------------------
1629
1822
  /** 构建系统提示词 */
1630
1823
  #buildSystemPrompt() {
1631
- const toolDescs = this.#tools.map((t) => ({
1824
+ const enabledTools = this.#toolRegistry.list();
1825
+ const toolDescs = enabledTools.map((t) => ({
1632
1826
  name: t.name,
1633
1827
  description: t.description,
1634
1828
  parameters: t.parameters
@@ -1643,7 +1837,7 @@ var Session = class {
1643
1837
  }
1644
1838
  /** 将注册的工具转为 ToolDefinition 格式(预留给 function calling) */
1645
1839
  #buildToolDefinitions() {
1646
- return this.#tools.map((t) => ({
1840
+ return this.#toolRegistry.list().map((t) => ({
1647
1841
  type: "function",
1648
1842
  function: {
1649
1843
  name: t.name,
@@ -1654,6 +1848,956 @@ var Session = class {
1654
1848
  }
1655
1849
  };
1656
1850
 
1851
+ // src/tool/sandbox.ts
1852
+ import { resolve, relative, isAbsolute } from "path";
1853
+ import { spawn } from "child_process";
1854
+ import process2 from "process";
1855
+ var DEFAULT_TIMEOUT_MS = 3e4;
1856
+ var DEFAULT_MAX_OUTPUT_LENGTH = 5e4;
1857
+ var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
1858
+ var isWindows = process2.platform === "win32";
1859
+ function resolvePath(inputPath, cwd) {
1860
+ const resolved = isAbsolute(inputPath) ? inputPath : resolve(cwd, inputPath);
1861
+ const normalized = resolve(resolved);
1862
+ const rel = relative(cwd, normalized);
1863
+ if (rel.startsWith("..") || normalized !== resolve(cwd) && !rel) {
1864
+ }
1865
+ return normalized;
1866
+ }
1867
+ function truncateOutput(content, maxLength = DEFAULT_MAX_OUTPUT_LENGTH) {
1868
+ if (content.length <= maxLength) return content;
1869
+ const truncated = content.slice(0, maxLength);
1870
+ return `${truncated}
1871
+
1872
+ ... [\u8F93\u51FA\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF0C\u5171 ${content.length} \u5B57\u7B26]`;
1873
+ }
1874
+ function getDefaultTimeout() {
1875
+ return DEFAULT_TIMEOUT_MS;
1876
+ }
1877
+ async function execCommand(command, args, cwd, timeoutMs = DEFAULT_TIMEOUT_MS, signal, isShellCommand) {
1878
+ return new Promise((resolve2) => {
1879
+ let spawnCmd;
1880
+ let spawnArgs;
1881
+ let useShell;
1882
+ if (isShellCommand) {
1883
+ spawnCmd = command;
1884
+ spawnArgs = args;
1885
+ useShell = false;
1886
+ } else {
1887
+ useShell = !isWindows;
1888
+ spawnCmd = isWindows ? "cmd" : command;
1889
+ spawnArgs = isWindows ? ["/c", command, ...args] : args;
1890
+ }
1891
+ const child = spawn(spawnCmd, spawnArgs, {
1892
+ cwd,
1893
+ shell: useShell,
1894
+ env: { ...process2.env },
1895
+ stdio: ["pipe", "pipe", "pipe"]
1896
+ });
1897
+ let stdout = "";
1898
+ let stderr = "";
1899
+ child.stdout.on("data", (data) => {
1900
+ stdout += data.toString();
1901
+ });
1902
+ child.stderr.on("data", (data) => {
1903
+ stderr += data.toString();
1904
+ });
1905
+ const timeout = setTimeout(() => {
1906
+ child.kill("SIGTERM");
1907
+ setTimeout(() => {
1908
+ child.kill("SIGKILL");
1909
+ }, 5e3);
1910
+ }, timeoutMs);
1911
+ if (signal) {
1912
+ if (signal.aborted) {
1913
+ child.kill("SIGTERM");
1914
+ }
1915
+ signal.addEventListener("abort", () => {
1916
+ child.kill("SIGTERM");
1917
+ }, { once: true });
1918
+ }
1919
+ child.on("close", (code) => {
1920
+ clearTimeout(timeout);
1921
+ resolve2({ stdout, stderr, exitCode: code });
1922
+ });
1923
+ child.on("error", (err) => {
1924
+ clearTimeout(timeout);
1925
+ stderr += `
1926
+ \u8FDB\u7A0B\u542F\u52A8\u5931\u8D25\uFF1A${err.message}`;
1927
+ resolve2({ stdout, stderr, exitCode: null });
1928
+ });
1929
+ });
1930
+ }
1931
+
1932
+ // src/tool/diff.ts
1933
+ function computeFileDiff(oldContent, newContent, filePath) {
1934
+ if (oldContent === newContent) {
1935
+ return {
1936
+ filePath,
1937
+ patch: "",
1938
+ existedBefore: oldContent.length > 0,
1939
+ additions: 0,
1940
+ deletions: 0
1941
+ };
1942
+ }
1943
+ if (oldContent.length === 0) {
1944
+ const newLines2 = splitLines(newContent);
1945
+ const patch2 = formatNewFileDiff(newLines2, filePath);
1946
+ return {
1947
+ filePath,
1948
+ patch: patch2,
1949
+ existedBefore: false,
1950
+ additions: newLines2.length,
1951
+ deletions: 0
1952
+ };
1953
+ }
1954
+ if (newContent.length === 0) {
1955
+ const oldLines2 = splitLines(oldContent);
1956
+ const patch2 = formatDeletedFileDiff(oldLines2, filePath);
1957
+ return {
1958
+ filePath,
1959
+ patch: patch2,
1960
+ existedBefore: true,
1961
+ additions: 0,
1962
+ deletions: oldLines2.length
1963
+ };
1964
+ }
1965
+ const oldLines = splitLines(oldContent);
1966
+ const newLines = splitLines(newContent);
1967
+ const diffLines = computeLineDiff(oldLines, newLines);
1968
+ let additions = 0;
1969
+ let deletions = 0;
1970
+ for (const line of diffLines) {
1971
+ if (line.op === "add") additions++;
1972
+ if (line.op === "remove") deletions++;
1973
+ }
1974
+ const hunks = groupIntoHunks(diffLines);
1975
+ const patch = formatUnifiedDiff(hunks, filePath);
1976
+ return {
1977
+ filePath,
1978
+ patch,
1979
+ existedBefore: true,
1980
+ additions,
1981
+ deletions
1982
+ };
1983
+ }
1984
+ function splitLines(text) {
1985
+ const raw = text.split("\n");
1986
+ if (text.endsWith("\n") && raw.length > 0 && raw[raw.length - 1] === "") {
1987
+ return raw.slice(0, -1);
1988
+ }
1989
+ return raw;
1990
+ }
1991
+ function computeLineDiff(oldLines, newLines) {
1992
+ const N = oldLines.length;
1993
+ const M = newLines.length;
1994
+ const dp = [];
1995
+ for (let i2 = 0; i2 <= N; i2++) {
1996
+ dp[i2] = new Array(M + 1).fill(0);
1997
+ }
1998
+ for (let i2 = 1; i2 <= N; i2++) {
1999
+ for (let j2 = 1; j2 <= M; j2++) {
2000
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
2001
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
2002
+ } else {
2003
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
2004
+ }
2005
+ }
2006
+ }
2007
+ const result = [];
2008
+ let i = N;
2009
+ let j = M;
2010
+ while (i > 0 || j > 0) {
2011
+ const oldLine = i > 0 ? oldLines[i - 1] : void 0;
2012
+ const newLine = j > 0 ? newLines[j - 1] : void 0;
2013
+ if (i > 0 && j > 0 && oldLine !== void 0 && newLine !== void 0 && oldLine === newLine) {
2014
+ result.unshift({ op: "equal", line: oldLine });
2015
+ i--;
2016
+ j--;
2017
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
2018
+ result.unshift({ op: "add", line: newLines[j - 1] });
2019
+ j--;
2020
+ } else {
2021
+ result.unshift({ op: "remove", line: oldLines[i - 1] });
2022
+ i--;
2023
+ }
2024
+ }
2025
+ return result;
2026
+ }
2027
+ var CONTEXT_LINES = 3;
2028
+ function groupIntoHunks(diffLines) {
2029
+ if (diffLines.length === 0) return [];
2030
+ const changeIndices = [];
2031
+ for (let i = 0; i < diffLines.length; i++) {
2032
+ if (diffLines[i].op !== "equal") {
2033
+ changeIndices.push(i);
2034
+ }
2035
+ }
2036
+ if (changeIndices.length === 0) return [];
2037
+ const groups = [[changeIndices[0]]];
2038
+ for (let idx = 1; idx < changeIndices.length; idx++) {
2039
+ const prevIdx = groups[groups.length - 1][groups[groups.length - 1].length - 1];
2040
+ const currIdx = changeIndices[idx];
2041
+ let gap = 0;
2042
+ for (let k = prevIdx + 1; k < currIdx; k++) {
2043
+ if (diffLines[k].op === "equal") gap++;
2044
+ }
2045
+ if (gap <= 2 * CONTEXT_LINES) {
2046
+ groups[groups.length - 1].push(currIdx);
2047
+ } else {
2048
+ groups.push([currIdx]);
2049
+ }
2050
+ }
2051
+ const hunks = [];
2052
+ for (const group of groups) {
2053
+ const firstChangeIdx = group[0];
2054
+ const lastChangeIdx = group[group.length - 1];
2055
+ const startIdx = Math.max(0, firstChangeIdx - CONTEXT_LINES);
2056
+ const endIdx = Math.min(diffLines.length - 1, lastChangeIdx + CONTEXT_LINES);
2057
+ const lines = diffLines.slice(startIdx, endIdx + 1);
2058
+ let oldLine = 0;
2059
+ let newLine = 0;
2060
+ for (let i = 0; i < startIdx; i++) {
2061
+ const op = diffLines[i].op;
2062
+ if (op === "equal" || op === "remove") oldLine++;
2063
+ if (op === "equal" || op === "add") newLine++;
2064
+ }
2065
+ let oldCount = 0;
2066
+ let newCount = 0;
2067
+ for (const line of lines) {
2068
+ if (line.op === "equal" || line.op === "remove") oldCount++;
2069
+ if (line.op === "equal" || line.op === "add") newCount++;
2070
+ }
2071
+ hunks.push({
2072
+ oldStart: oldLine + 1,
2073
+ oldCount,
2074
+ newStart: newLine + 1,
2075
+ newCount,
2076
+ lines
2077
+ });
2078
+ }
2079
+ return hunks;
2080
+ }
2081
+ function formatUnifiedDiff(hunks, filePath) {
2082
+ if (hunks.length === 0) return "";
2083
+ const parts = [];
2084
+ const fileName = extractFileName(filePath);
2085
+ parts.push(`--- a/${fileName}`);
2086
+ parts.push(`+++ b/${fileName}`);
2087
+ for (const hunk of hunks) {
2088
+ parts.push(`@@ -${hunk.oldStart},${hunk.oldCount} +${hunk.newStart},${hunk.newCount} @@`);
2089
+ for (const line of hunk.lines) {
2090
+ switch (line.op) {
2091
+ case "equal":
2092
+ parts.push(` ${line.line}`);
2093
+ break;
2094
+ case "remove":
2095
+ parts.push(`-${line.line}`);
2096
+ break;
2097
+ case "add":
2098
+ parts.push(`+${line.line}`);
2099
+ break;
2100
+ }
2101
+ }
2102
+ }
2103
+ return parts.join("\n");
2104
+ }
2105
+ function formatNewFileDiff(lines, filePath) {
2106
+ const fileName = extractFileName(filePath);
2107
+ const parts = [];
2108
+ parts.push(`--- /dev/null`);
2109
+ parts.push(`+++ b/${fileName}`);
2110
+ parts.push(`@@ -0,0 +1,${lines.length} @@`);
2111
+ for (const line of lines) {
2112
+ parts.push(`+${line}`);
2113
+ }
2114
+ return parts.join("\n");
2115
+ }
2116
+ function formatDeletedFileDiff(lines, filePath) {
2117
+ const fileName = extractFileName(filePath);
2118
+ const parts = [];
2119
+ parts.push(`--- a/${fileName}`);
2120
+ parts.push(`+++ /dev/null`);
2121
+ parts.push(`@@ -1,${lines.length} +0,0 @@`);
2122
+ for (const line of lines) {
2123
+ parts.push(`-${line}`);
2124
+ }
2125
+ return parts.join("\n");
2126
+ }
2127
+ function extractFileName(filePath) {
2128
+ const normalized = filePath.replace(/\\/g, "/");
2129
+ return normalized.split("/").pop() ?? filePath;
2130
+ }
2131
+
2132
+ // src/tool/builtins/read-file.ts
2133
+ import { readFile as readFile4 } from "fs/promises";
2134
+ import { stat } from "fs/promises";
2135
+ var readFileSchema = {
2136
+ type: "object",
2137
+ properties: {
2138
+ path: {
2139
+ type: "string",
2140
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2141
+ },
2142
+ start_line: {
2143
+ type: "number",
2144
+ description: "\u8D77\u59CB\u884C\u53F7\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u9ED8\u8BA4\u4E3A 1"
2145
+ },
2146
+ end_line: {
2147
+ type: "number",
2148
+ description: "\u7ED3\u675F\u884C\u53F7\uFF08\u5305\u542B\uFF09\uFF0C\u9ED8\u8BA4\u5230\u6587\u4EF6\u672B\u5C3E"
2149
+ }
2150
+ },
2151
+ required: ["path"],
2152
+ additionalProperties: false
2153
+ };
2154
+ var readFileTool = {
2155
+ name: "read_file",
2156
+ 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",
2157
+ parameters: readFileSchema,
2158
+ async execute(args, ctx) {
2159
+ const params = args;
2160
+ if (!params?.path || typeof params.path !== "string") {
2161
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2162
+ }
2163
+ const filePath = resolvePath(params.path, ctx.cwd);
2164
+ try {
2165
+ const fileStat = await stat(filePath);
2166
+ const maxSize = 10 * 1024 * 1024;
2167
+ if (fileStat.size > maxSize) {
2168
+ return {
2169
+ success: false,
2170
+ data: `\u6587\u4EF6\u8FC7\u5927\uFF08${(fileStat.size / 1024 / 1024).toFixed(1)}MB\uFF09\uFF0C\u8D85\u8FC7 10MB \u9650\u5236`,
2171
+ error: "FILE_TOO_LARGE"
2172
+ };
2173
+ }
2174
+ const content = await readFile4(filePath, "utf-8");
2175
+ const lines = content.split("\n");
2176
+ const startLine = Math.max(1, params.start_line ?? 1) - 1;
2177
+ const endLine = params.end_line ? Math.min(params.end_line, lines.length) : lines.length;
2178
+ const selectedLines = lines.slice(startLine, endLine);
2179
+ const lineNumWidth = String(endLine).length;
2180
+ const result = selectedLines.map((line, i) => {
2181
+ const lineNum = String(startLine + i + 1).padStart(lineNumWidth, " ");
2182
+ return `${lineNum} | ${line}`;
2183
+ }).join("\n");
2184
+ return {
2185
+ success: true,
2186
+ data: truncateOutput(result)
2187
+ };
2188
+ } catch (err) {
2189
+ const message = err instanceof Error ? err.message : String(err);
2190
+ return {
2191
+ success: false,
2192
+ data: `\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25\uFF1A${message}`,
2193
+ error: "READ_ERROR"
2194
+ };
2195
+ }
2196
+ }
2197
+ };
2198
+
2199
+ // src/tool/builtins/write-file.ts
2200
+ import { writeFile as writeFile3, mkdir as mkdir4, readFile as readFile5 } from "fs/promises";
2201
+ import { dirname } from "path";
2202
+ var writeFileSchema = {
2203
+ type: "object",
2204
+ properties: {
2205
+ path: {
2206
+ type: "string",
2207
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2208
+ },
2209
+ content: {
2210
+ type: "string",
2211
+ description: "\u8981\u5199\u5165\u7684\u6587\u4EF6\u5185\u5BB9"
2212
+ }
2213
+ },
2214
+ required: ["path", "content"],
2215
+ additionalProperties: false
2216
+ };
2217
+ var writeFileTool = {
2218
+ name: "write_file",
2219
+ 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",
2220
+ parameters: writeFileSchema,
2221
+ async execute(args, ctx) {
2222
+ const params = args;
2223
+ if (!params?.path || typeof params.path !== "string") {
2224
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2225
+ }
2226
+ if (params.content === void 0 || params.content === null) {
2227
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 content", error: "INVALID_ARGS" };
2228
+ }
2229
+ const filePath = resolvePath(params.path, ctx.cwd);
2230
+ try {
2231
+ let oldContent = "";
2232
+ let existedBefore = false;
2233
+ try {
2234
+ oldContent = await readFile5(filePath, "utf-8");
2235
+ existedBefore = true;
2236
+ } catch {
2237
+ }
2238
+ await mkdir4(dirname(filePath), { recursive: true });
2239
+ const content = String(params.content);
2240
+ await writeFile3(filePath, content, "utf-8");
2241
+ const diff = computeFileDiff(oldContent, content, filePath);
2242
+ diff.existedBefore = existedBefore;
2243
+ const lineCount = content.split("\n").length;
2244
+ const byteSize = Buffer.byteLength(content, "utf-8");
2245
+ const action = existedBefore ? "\u5DF2\u4FEE\u6539" : "\u5DF2\u521B\u5EFA";
2246
+ const diffSummary = existedBefore ? `\uFF0C+${diff.additions} -${diff.deletions}` : `\uFF0C+${diff.additions} \u884C\uFF08\u65B0\u5EFA\uFF09`;
2247
+ return {
2248
+ success: true,
2249
+ data: `\u6587\u4EF6${action}\uFF1A${filePath}\uFF08${lineCount} \u884C\uFF0C${byteSize} \u5B57\u8282${diffSummary}\uFF09`,
2250
+ diff
2251
+ };
2252
+ } catch (err) {
2253
+ const message = err instanceof Error ? err.message : String(err);
2254
+ return {
2255
+ success: false,
2256
+ data: `\u5199\u5165\u6587\u4EF6\u5931\u8D25\uFF1A${message}`,
2257
+ error: "WRITE_ERROR"
2258
+ };
2259
+ }
2260
+ }
2261
+ };
2262
+
2263
+ // src/tool/builtins/edit-file.ts
2264
+ import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
2265
+ var editFileSchema = {
2266
+ type: "object",
2267
+ properties: {
2268
+ path: {
2269
+ type: "string",
2270
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2271
+ },
2272
+ old_text: {
2273
+ type: "string",
2274
+ description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09"
2275
+ },
2276
+ new_text: {
2277
+ type: "string",
2278
+ description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C"
2279
+ }
2280
+ },
2281
+ required: ["path", "old_text", "new_text"],
2282
+ additionalProperties: false
2283
+ };
2284
+ var editFileTool = {
2285
+ name: "edit_file",
2286
+ 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",
2287
+ parameters: editFileSchema,
2288
+ async execute(args, ctx) {
2289
+ const params = args;
2290
+ if (!params?.path || typeof params.path !== "string") {
2291
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2292
+ }
2293
+ if (typeof params.old_text !== "string") {
2294
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 old_text", error: "INVALID_ARGS" };
2295
+ }
2296
+ if (typeof params.new_text !== "string") {
2297
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 new_text", error: "INVALID_ARGS" };
2298
+ }
2299
+ const filePath = resolvePath(params.path, ctx.cwd);
2300
+ try {
2301
+ const content = await readFile6(filePath, "utf-8");
2302
+ const firstIndex = content.indexOf(params.old_text);
2303
+ if (firstIndex === -1) {
2304
+ return {
2305
+ success: false,
2306
+ data: `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u6587\u672C\u3002\u8BF7\u786E\u8BA4 old_text \u4E0E\u6587\u4EF6\u5185\u5BB9\u5B8C\u5168\u4E00\u81F4\uFF08\u5305\u62EC\u7F29\u8FDB\u548C\u7A7A\u683C\uFF09\u3002`,
2307
+ error: "TEXT_NOT_FOUND"
2308
+ };
2309
+ }
2310
+ const secondIndex = content.indexOf(params.old_text, firstIndex + 1);
2311
+ if (secondIndex !== -1) {
2312
+ return {
2313
+ success: false,
2314
+ data: `\u8981\u66FF\u6362\u7684\u6587\u672C\u5728\u6587\u4EF6\u4E2D\u51FA\u73B0\u591A\u6B21\uFF0C\u8BF7\u63D0\u4F9B\u66F4\u591A\u4E0A\u4E0B\u6587\u4EE5\u7CBE\u786E\u5B9A\u4F4D\u3002`,
2315
+ error: "TEXT_MULTIPLE_MATCHES"
2316
+ };
2317
+ }
2318
+ const newContent = content.replace(params.old_text, params.new_text);
2319
+ await writeFile4(filePath, newContent, "utf-8");
2320
+ const diff = computeFileDiff(content, newContent, filePath);
2321
+ diff.existedBefore = true;
2322
+ const beforeText = content.slice(0, firstIndex);
2323
+ const startLine = beforeText.split("\n").length;
2324
+ const oldLines = params.old_text.split("\n").length;
2325
+ const newLines = params.new_text.split("\n").length;
2326
+ const diffSummary = `+${diff.additions} -${diff.deletions}`;
2327
+ return {
2328
+ success: true,
2329
+ data: `\u6587\u4EF6\u5DF2\u7F16\u8F91\uFF1A${filePath}
2330
+ \u66FF\u6362\u4F4D\u7F6E\uFF1A\u7B2C ${startLine} \u884C
2331
+ ${oldLines} \u884C \u2192 ${newLines} \u884C
2332
+ \u53D8\u66F4\uFF1A${diffSummary}`,
2333
+ diff
2334
+ };
2335
+ } catch (err) {
2336
+ const message = err instanceof Error ? err.message : String(err);
2337
+ return {
2338
+ success: false,
2339
+ data: `\u7F16\u8F91\u6587\u4EF6\u5931\u8D25\uFF1A${message}`,
2340
+ error: "EDIT_ERROR"
2341
+ };
2342
+ }
2343
+ }
2344
+ };
2345
+
2346
+ // src/tool/builtins/bash.ts
2347
+ import process3 from "process";
2348
+ var isWindows2 = process3.platform === "win32";
2349
+ var bashSchema = {
2350
+ type: "object",
2351
+ properties: {
2352
+ command: {
2353
+ type: "string",
2354
+ description: "\u8981\u6267\u884C\u7684 shell \u547D\u4EE4"
2355
+ },
2356
+ timeout: {
2357
+ type: "number",
2358
+ description: "\u6267\u884C\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 30000"
2359
+ }
2360
+ },
2361
+ required: ["command"],
2362
+ additionalProperties: false
2363
+ };
2364
+ var bashTool = {
2365
+ name: "bash",
2366
+ 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",
2367
+ parameters: bashSchema,
2368
+ async execute(args, ctx) {
2369
+ const params = args;
2370
+ if (!params?.command || typeof params.command !== "string") {
2371
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 command", error: "INVALID_ARGS" };
2372
+ }
2373
+ const timeout = params.timeout ?? ctx.timeout ?? getDefaultTimeout();
2374
+ try {
2375
+ const shellCommand = isWindows2 ? "cmd" : "sh";
2376
+ const shellArgs = isWindows2 ? ["/c", params.command] : ["-c", params.command];
2377
+ const result = await execCommand(
2378
+ shellCommand,
2379
+ shellArgs,
2380
+ ctx.cwd,
2381
+ timeout,
2382
+ ctx.signal,
2383
+ true
2384
+ // isShellCommand — 已指定 shell 程序,不需要二次包装
2385
+ );
2386
+ const parts = [];
2387
+ if (result.stdout) {
2388
+ parts.push(truncateOutput(result.stdout));
2389
+ }
2390
+ if (result.stderr) {
2391
+ parts.push(`[stderr]
2392
+ ${truncateOutput(result.stderr)}`);
2393
+ }
2394
+ const success = result.exitCode === 0;
2395
+ const output = parts.length > 0 ? parts.join("\n") : "(\u65E0\u8F93\u51FA)";
2396
+ return {
2397
+ success,
2398
+ data: `${output}
2399
+ [\u9000\u51FA\u7801: ${result.exitCode ?? "\u672A\u77E5"}]`,
2400
+ error: success ? void 0 : `EXIT_CODE_${result.exitCode ?? "UNKNOWN"}`
2401
+ };
2402
+ } catch (err) {
2403
+ const message = err instanceof Error ? err.message : String(err);
2404
+ return {
2405
+ success: false,
2406
+ data: `\u547D\u4EE4\u6267\u884C\u5931\u8D25\uFF1A${message}`,
2407
+ error: "EXECUTION_ERROR"
2408
+ };
2409
+ }
2410
+ }
2411
+ };
2412
+
2413
+ // src/tool/builtins/glob.ts
2414
+ import { readdir as readdir2, stat as stat2 } from "fs/promises";
2415
+ import { join as join4, relative as relative2, isAbsolute as isAbsolute2 } from "path";
2416
+ var globSchema = {
2417
+ type: "object",
2418
+ properties: {
2419
+ pattern: {
2420
+ type: "string",
2421
+ description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u652F\u6301 * \u548C ** \u901A\u914D\u7B26\uFF0C\u5982 **/*.ts\u3001src/**/*.test.ts\uFF09"
2422
+ },
2423
+ directory: {
2424
+ type: "string",
2425
+ description: "\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
2426
+ }
2427
+ },
2428
+ required: ["pattern"],
2429
+ additionalProperties: false
2430
+ };
2431
+ function globToRegex(pattern) {
2432
+ let regexStr = pattern;
2433
+ regexStr = regexStr.replace(/\*\*\//g, "<<GLOBSTAR_SLASH>>");
2434
+ regexStr = regexStr.replace(/\*\*/g, "<<GLOBSTAR>>");
2435
+ regexStr = regexStr.replace(/\?/g, "<<QUESTION>>");
2436
+ regexStr = regexStr.replace(/[.+^${}()|[\]\\]/g, "\\$&");
2437
+ regexStr = regexStr.replace(/\*/g, "[^/]*");
2438
+ regexStr = regexStr.replace(/<<GLOBSTAR_SLASH>>/g, "(.*/)?");
2439
+ regexStr = regexStr.replace(/<<GLOBSTAR>>/g, ".*");
2440
+ regexStr = regexStr.replace(/<<QUESTION>>/g, "[^/]");
2441
+ return new RegExp(`^${regexStr}$`, "i");
2442
+ }
2443
+ async function walkDir(dir, baseDir) {
2444
+ const results = [];
2445
+ let entries;
2446
+ try {
2447
+ entries = await readdir2(dir, { withFileTypes: true });
2448
+ } catch {
2449
+ return results;
2450
+ }
2451
+ for (const entry of entries) {
2452
+ if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
2453
+ continue;
2454
+ }
2455
+ const fullPath = join4(dir, entry.name);
2456
+ const relPath = relative2(baseDir, fullPath);
2457
+ if (entry.isDirectory()) {
2458
+ results.push(...await walkDir(fullPath, baseDir));
2459
+ } else {
2460
+ results.push(relPath);
2461
+ }
2462
+ }
2463
+ return results;
2464
+ }
2465
+ var globTool = {
2466
+ name: "glob",
2467
+ 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",
2468
+ parameters: globSchema,
2469
+ async execute(args, ctx) {
2470
+ const params = args;
2471
+ if (!params?.pattern || typeof params.pattern !== "string") {
2472
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
2473
+ }
2474
+ const searchDir = params.directory ? isAbsolute2(params.directory) ? params.directory : join4(ctx.cwd, params.directory) : ctx.cwd;
2475
+ const regex = globToRegex(params.pattern);
2476
+ try {
2477
+ const dirStat = await stat2(searchDir);
2478
+ if (!dirStat.isDirectory()) {
2479
+ return { success: false, data: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${searchDir}`, error: "NOT_DIRECTORY" };
2480
+ }
2481
+ const allFiles = await walkDir(searchDir, searchDir);
2482
+ const matched = allFiles.filter((f) => regex.test(f));
2483
+ if (matched.length === 0) {
2484
+ return {
2485
+ success: true,
2486
+ data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u6587\u4EF6`
2487
+ };
2488
+ }
2489
+ const limit = 200;
2490
+ const limited = matched.slice(0, limit);
2491
+ const output = limited.join("\n");
2492
+ const suffix = matched.length > limit ? `
2493
+
2494
+ ... \u5171 ${matched.length} \u4E2A\u6587\u4EF6\uFF0C\u53EA\u663E\u793A\u524D ${limit} \u4E2A` : "";
2495
+ return {
2496
+ success: true,
2497
+ data: truncateOutput(output + suffix)
2498
+ };
2499
+ } catch (err) {
2500
+ const message = err instanceof Error ? err.message : String(err);
2501
+ return {
2502
+ success: false,
2503
+ data: `\u6587\u4EF6\u641C\u7D22\u5931\u8D25\uFF1A${message}`,
2504
+ error: "GLOB_ERROR"
2505
+ };
2506
+ }
2507
+ }
2508
+ };
2509
+
2510
+ // src/tool/builtins/grep.ts
2511
+ import { readdir as readdir3, readFile as readFile7, stat as stat3 } from "fs/promises";
2512
+ import { join as join5, relative as relative3, isAbsolute as isAbsolute3 } from "path";
2513
+ var grepSchema = {
2514
+ type: "object",
2515
+ properties: {
2516
+ pattern: {
2517
+ type: "string",
2518
+ description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u641C\u7D22\u6A21\u5F0F"
2519
+ },
2520
+ directory: {
2521
+ type: "string",
2522
+ description: "\u641C\u7D22\u7684\u76EE\u5F55\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
2523
+ },
2524
+ include: {
2525
+ type: "string",
2526
+ description: "\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\uFF08\u5982 ts\u3001json\uFF09\uFF0C\u4E0D\u542B\u70B9\u53F7"
2527
+ },
2528
+ case_sensitive: {
2529
+ type: "boolean",
2530
+ description: "\u662F\u5426\u5927\u5C0F\u5199\u654F\u611F\uFF0C\u9ED8\u8BA4 false"
2531
+ },
2532
+ max_files: {
2533
+ type: "number",
2534
+ description: "\u6700\u5927\u641C\u7D22\u6587\u4EF6\u6570\uFF0C\u9ED8\u8BA4 200"
2535
+ }
2536
+ },
2537
+ required: ["pattern"],
2538
+ additionalProperties: false
2539
+ };
2540
+ async function collectFiles(dir, baseDir, extension, maxFiles = 200) {
2541
+ const results = [];
2542
+ let entries;
2543
+ try {
2544
+ entries = await readdir3(dir, { withFileTypes: true });
2545
+ } catch {
2546
+ return results;
2547
+ }
2548
+ for (const entry of entries) {
2549
+ if (results.length >= maxFiles) break;
2550
+ if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist")) {
2551
+ continue;
2552
+ }
2553
+ const fullPath = join5(dir, entry.name);
2554
+ if (entry.isDirectory()) {
2555
+ results.push(...await collectFiles(fullPath, baseDir, extension, maxFiles - results.length));
2556
+ } else {
2557
+ if (extension && !entry.name.endsWith(`.${extension}`)) {
2558
+ continue;
2559
+ }
2560
+ results.push(fullPath);
2561
+ }
2562
+ }
2563
+ return results;
2564
+ }
2565
+ var grepTool = {
2566
+ name: "grep",
2567
+ 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",
2568
+ parameters: grepSchema,
2569
+ async execute(args, ctx) {
2570
+ const params = args;
2571
+ if (!params?.pattern || typeof params.pattern !== "string") {
2572
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
2573
+ }
2574
+ const searchDir = params.directory ? isAbsolute3(params.directory) ? params.directory : join5(ctx.cwd, params.directory) : ctx.cwd;
2575
+ const maxFiles = params.max_files ?? 200;
2576
+ try {
2577
+ const flags = params.case_sensitive ? "g" : "gi";
2578
+ const regex = new RegExp(params.pattern, flags);
2579
+ const dirStat = await stat3(searchDir);
2580
+ if (!dirStat.isDirectory()) {
2581
+ return { success: false, data: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${searchDir}`, error: "NOT_DIRECTORY" };
2582
+ }
2583
+ const files = await collectFiles(searchDir, searchDir, params.include, maxFiles);
2584
+ const matches = [];
2585
+ for (const filePath of files) {
2586
+ try {
2587
+ const content = await readFile7(filePath, "utf-8");
2588
+ const lines = content.split("\n");
2589
+ const relPath = relative3(searchDir, filePath);
2590
+ for (let i = 0; i < lines.length; i++) {
2591
+ if (regex.test(lines[i])) {
2592
+ regex.lastIndex = 0;
2593
+ matches.push({
2594
+ file: relPath,
2595
+ line: i + 1,
2596
+ content: lines[i]
2597
+ });
2598
+ if (matches.length >= 500) break;
2599
+ }
2600
+ }
2601
+ if (matches.length >= 500) break;
2602
+ } catch {
2603
+ continue;
2604
+ }
2605
+ }
2606
+ if (matches.length === 0) {
2607
+ return {
2608
+ success: true,
2609
+ data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u5185\u5BB9`
2610
+ };
2611
+ }
2612
+ const output = matches.map((m) => `${m.file}:${m.line}: ${m.content}`).join("\n");
2613
+ return {
2614
+ success: true,
2615
+ data: truncateOutput(output)
2616
+ };
2617
+ } catch (err) {
2618
+ const message = err instanceof Error ? err.message : String(err);
2619
+ return {
2620
+ success: false,
2621
+ data: `\u5185\u5BB9\u641C\u7D22\u5931\u8D25\uFF1A${message}`,
2622
+ error: "GREP_ERROR"
2623
+ };
2624
+ }
2625
+ }
2626
+ };
2627
+
2628
+ // src/tool/builtins/ls.ts
2629
+ import { readdir as readdir4, stat as stat4 } from "fs/promises";
2630
+ import { join as join6 } from "path";
2631
+ var lsSchema = {
2632
+ type: "object",
2633
+ properties: {
2634
+ path: {
2635
+ type: "string",
2636
+ 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"
2637
+ },
2638
+ all: {
2639
+ type: "boolean",
2640
+ description: "\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\uFF08\u4EE5 . \u5F00\u5934\u7684\u6587\u4EF6\uFF09\uFF0C\u9ED8\u8BA4 false"
2641
+ }
2642
+ },
2643
+ required: [],
2644
+ additionalProperties: false
2645
+ };
2646
+ var lsTool = {
2647
+ name: "ls",
2648
+ 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",
2649
+ parameters: lsSchema,
2650
+ async execute(args, ctx) {
2651
+ const params = args ?? {};
2652
+ const dirPath = params.path ? resolvePath(params.path, ctx.cwd) : ctx.cwd;
2653
+ const showAll = params.all ?? false;
2654
+ try {
2655
+ const entries = await readdir4(dirPath, { withFileTypes: true });
2656
+ const lines = [];
2657
+ const sorted = [...entries].sort((a, b) => {
2658
+ if (a.isDirectory() !== b.isDirectory()) {
2659
+ return a.isDirectory() ? -1 : 1;
2660
+ }
2661
+ return a.name.localeCompare(b.name);
2662
+ });
2663
+ for (const entry of sorted) {
2664
+ if (!showAll && entry.name.startsWith(".")) continue;
2665
+ const typeMark = entry.isDirectory() ? "DIR" : entry.isSymbolicLink() ? "LINK" : "FILE";
2666
+ let sizeStr = "";
2667
+ if (typeMark === "FILE") {
2668
+ try {
2669
+ const fileStat = await stat4(join6(dirPath, entry.name));
2670
+ if (fileStat.size < 1024) {
2671
+ sizeStr = `${fileStat.size}B`;
2672
+ } else if (fileStat.size < 1024 * 1024) {
2673
+ sizeStr = `${(fileStat.size / 1024).toFixed(1)}KB`;
2674
+ } else {
2675
+ sizeStr = `${(fileStat.size / 1024 / 1024).toFixed(1)}MB`;
2676
+ }
2677
+ } catch {
2678
+ sizeStr = "?";
2679
+ }
2680
+ }
2681
+ const typeLabel = typeMark === "DIR" ? "\u{1F4C1}" : typeMark === "LINK" ? "\u{1F517}" : "\u{1F4C4}";
2682
+ lines.push(`${typeLabel} ${entry.name}${sizeStr ? ` (${sizeStr})` : ""}`);
2683
+ }
2684
+ if (lines.length === 0) {
2685
+ return { success: true, data: "\u76EE\u5F55\u4E3A\u7A7A" };
2686
+ }
2687
+ return {
2688
+ success: true,
2689
+ data: truncateOutput(`\u76EE\u5F55\uFF1A${dirPath}
2690
+ ${lines.join("\n")}`)
2691
+ };
2692
+ } catch (err) {
2693
+ const message = err instanceof Error ? err.message : String(err);
2694
+ return {
2695
+ success: false,
2696
+ data: `\u5217\u76EE\u5F55\u5931\u8D25\uFF1A${message}`,
2697
+ error: "LS_ERROR"
2698
+ };
2699
+ }
2700
+ }
2701
+ };
2702
+
2703
+ // src/tool/builtins/fetch.ts
2704
+ var fetchSchema = {
2705
+ type: "object",
2706
+ properties: {
2707
+ url: {
2708
+ type: "string",
2709
+ description: "\u8BF7\u6C42\u7684 URL"
2710
+ },
2711
+ method: {
2712
+ type: "string",
2713
+ description: "HTTP \u65B9\u6CD5\uFF08GET\u3001POST\u3001PUT\u3001DELETE \u7B49\uFF09\uFF0C\u9ED8\u8BA4 GET"
2714
+ },
2715
+ headers: {
2716
+ type: "object",
2717
+ description: "\u8BF7\u6C42\u5934\u952E\u503C\u5BF9",
2718
+ additionalProperties: { type: "string" }
2719
+ },
2720
+ body: {
2721
+ type: "string",
2722
+ description: "\u8BF7\u6C42\u4F53\u5185\u5BB9\uFF08POST/PUT \u65F6\u4F7F\u7528\uFF09"
2723
+ },
2724
+ max_length: {
2725
+ type: "number",
2726
+ description: "\u54CD\u5E94\u5185\u5BB9\u6700\u5927\u957F\u5EA6\uFF08\u5B57\u7B26\uFF09\uFF0C\u9ED8\u8BA4 50000"
2727
+ }
2728
+ },
2729
+ required: ["url"],
2730
+ additionalProperties: false
2731
+ };
2732
+ var fetchTool = {
2733
+ name: "fetch",
2734
+ 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",
2735
+ parameters: fetchSchema,
2736
+ async execute(args, ctx) {
2737
+ const params = args;
2738
+ if (!params?.url || typeof params.url !== "string") {
2739
+ return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 url", error: "INVALID_ARGS" };
2740
+ }
2741
+ const method = (params.method ?? "GET").toUpperCase();
2742
+ const timeout = 3e4;
2743
+ const maxLength = params.max_length ?? 5e4;
2744
+ try {
2745
+ const fetchOptions = {
2746
+ method,
2747
+ headers: params.headers ?? {},
2748
+ signal: ctx.signal ?? AbortSignal.timeout(timeout)
2749
+ };
2750
+ if (params.body && (method === "POST" || method === "PUT" || method === "PATCH")) {
2751
+ fetchOptions.headers["Content-Type"] ??= "application/json";
2752
+ fetchOptions.body = params.body;
2753
+ }
2754
+ const response = await fetch(params.url, fetchOptions);
2755
+ const contentType = response.headers.get("content-type") ?? "unknown";
2756
+ const statusText = `${response.status} ${response.statusText}`;
2757
+ let body;
2758
+ try {
2759
+ body = await response.text();
2760
+ } catch {
2761
+ body = "(\u65E0\u6CD5\u8BFB\u53D6\u54CD\u5E94\u4F53)";
2762
+ }
2763
+ const truncatedBody = truncateOutput(body, maxLength);
2764
+ const header = `\u72B6\u6001: ${statusText}
2765
+ \u5185\u5BB9\u7C7B\u578B: ${contentType}`;
2766
+ const separator = body.length > 0 ? "\n---\n" : "";
2767
+ return {
2768
+ success: response.ok,
2769
+ data: `${header}${separator}${truncatedBody}`,
2770
+ error: response.ok ? void 0 : `HTTP_${response.status}`
2771
+ };
2772
+ } catch (err) {
2773
+ if (err instanceof DOMException && err.name === "AbortError") {
2774
+ return { success: false, data: "\u8BF7\u6C42\u88AB\u4E2D\u6B62", error: "ABORTED" };
2775
+ }
2776
+ if (err instanceof TypeError && err.message.includes("fetch")) {
2777
+ return { success: false, data: `\u7F51\u7EDC\u9519\u8BEF\uFF1A${err.message}`, error: "NETWORK_ERROR" };
2778
+ }
2779
+ const message = err instanceof Error ? err.message : String(err);
2780
+ return {
2781
+ success: false,
2782
+ data: `HTTP \u8BF7\u6C42\u5931\u8D25\uFF1A${message}`,
2783
+ error: "FETCH_ERROR"
2784
+ };
2785
+ }
2786
+ }
2787
+ };
2788
+
2789
+ // src/tool/builtins/index.ts
2790
+ var builtinTools = [
2791
+ readFileTool,
2792
+ writeFileTool,
2793
+ editFileTool,
2794
+ bashTool,
2795
+ globTool,
2796
+ grepTool,
2797
+ lsTool,
2798
+ fetchTool
2799
+ ];
2800
+
1657
2801
  // src/utils/gradient.ts
1658
2802
  var IDLE_GRADIENT_STOPS = [
1659
2803
  [0, 255, 65],
@@ -1718,7 +2862,7 @@ function getGradientColors(text, phase, stops) {
1718
2862
  }
1719
2863
 
1720
2864
  // src/ui/ChatSession.tsx
1721
- import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2865
+ import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1722
2866
  var commandRegistry = /* @__PURE__ */ new Map();
1723
2867
  function registerCommand(name, cmd) {
1724
2868
  commandRegistry.set(name, cmd);
@@ -1983,7 +3127,9 @@ function ChatSession({
1983
3127
  model: activeModel
1984
3128
  });
1985
3129
  const tracker = externalCostTracker ?? new CostTracker();
1986
- const session = new Session(provider, [], tracker, {
3130
+ const toolRegistry = new ToolRegistry();
3131
+ toolRegistry.registerAll(builtinTools);
3132
+ const session = new Session(provider, toolRegistry, tracker, {
1987
3133
  cwd: process.cwd()
1988
3134
  });
1989
3135
  sessionRef.current = session;
@@ -1995,7 +3141,7 @@ function ChatSession({
1995
3141
  if (!apiKey || !baseUrl) return;
1996
3142
  let cancelled = false;
1997
3143
  setBalanceLoading(true);
1998
- import("./deepseek-OUOEENTK.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
3144
+ import("./deepseek-UJXV2D6K.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
1999
3145
  const provider = new DeepSeekProvider2({
2000
3146
  apiKey,
2001
3147
  baseUrl,
@@ -2163,6 +3309,20 @@ function ChatSession({
2163
3309
  return next;
2164
3310
  });
2165
3311
  break;
3312
+ case "tool_result":
3313
+ setCurrentContent("");
3314
+ currentContentRef.current = "";
3315
+ setCurrentToolCalls([]);
3316
+ currentToolCallsRef.current = [];
3317
+ setDisplayMessages((prev) => [
3318
+ ...prev,
3319
+ {
3320
+ role: "tool",
3321
+ content: event.result.success ? `\u2705 ${event.name}: ${event.result.data.slice(0, 500)}${event.result.data.length > 500 ? "..." : ""}` : `\u274C ${event.name}: ${event.result.error ?? "\u6267\u884C\u5931\u8D25"}`,
3322
+ diff: event.result.diff
3323
+ }
3324
+ ]);
3325
+ break;
2166
3326
  case "usage":
2167
3327
  setCurrentUsage(event.usage);
2168
3328
  setStreamingModel(event.model);
@@ -2224,26 +3384,26 @@ function ChatSession({
2224
3384
  });
2225
3385
  }
2226
3386
  }, [currentUsage, streamingModel, currentCost]);
2227
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
2228
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", marginBottom: 1, children: [
2229
- /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
3387
+ return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
3388
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginBottom: 1, children: [
3389
+ /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
2230
3390
  const colorIndex = (i + offset) % CYBER_PALETTE.length;
2231
- return /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
3391
+ return /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
2232
3392
  }) }),
2233
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", justifyContent: "center", children: [
2234
- /* @__PURE__ */ jsxs7(Text8, { color: "#00ff41", children: [
3393
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", justifyContent: "center", children: [
3394
+ /* @__PURE__ */ jsxs8(Text9, { color: "#00ff41", children: [
2235
3395
  " \u2714 ",
2236
3396
  "\u5DF2\u5C31\u7EEA ",
2237
3397
  skillCount,
2238
3398
  " \u4E2A Skill"
2239
3399
  ] }),
2240
- /* @__PURE__ */ jsxs7(Text8, { color: "#00ffff", children: [
3400
+ /* @__PURE__ */ jsxs8(Text9, { color: "#00ffff", children: [
2241
3401
  " \u2139 ",
2242
3402
  "\u5DF2\u5C31\u7EEA ",
2243
3403
  toolCount,
2244
3404
  " \u4E2A\u5DE5\u5177"
2245
3405
  ] }),
2246
- /* @__PURE__ */ jsxs7(Text8, { color: "#00ffff", children: [
3406
+ /* @__PURE__ */ jsxs8(Text9, { color: "#00ffff", children: [
2247
3407
  " \u{1F527} \u6A21\u578B ",
2248
3408
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
2249
3409
  ] }),
@@ -2251,40 +3411,49 @@ function ChatSession({
2251
3411
  const tip = cmdTips[cmdTipIndex % cmdTips.length];
2252
3412
  if (!tip) return null;
2253
3413
  const text = `${tip.name} ${tip.desc}`;
2254
- return /* @__PURE__ */ jsxs7(Text8, { children: [
2255
- /* @__PURE__ */ jsx7(Text8, { color: "#808080", children: " \u{1F4A1} " }),
2256
- cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx7(Text8, { color: "#808080", children: text })
3414
+ return /* @__PURE__ */ jsxs8(Text9, { children: [
3415
+ /* @__PURE__ */ jsx8(Text9, { color: "#808080", children: " \u{1F4A1} " }),
3416
+ 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 })
2257
3417
  ] });
2258
3418
  })(),
2259
- verbose ? /* @__PURE__ */ jsx7(Text8, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
3419
+ verbose ? /* @__PURE__ */ jsx8(Text9, { color: "#ff1493", children: " \u26A1 Verbose" }) : null
2260
3420
  ] }),
2261
- /* @__PURE__ */ jsxs7(Box7, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
2262
- balanceLoading && balance === null ? /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", children: [
2263
- /* @__PURE__ */ jsx7(Text8, { color: "yellow", children: "\u{1F4B0} " }),
2264
- /* @__PURE__ */ jsxs7(Text8, { color: "yellow", children: [
3421
+ /* @__PURE__ */ jsxs8(Box8, { flexGrow: 1, flexDirection: "column", justifyContent: "center", alignItems: "flex-end", children: [
3422
+ balanceLoading && balance === null ? /* @__PURE__ */ jsx8(Text9, { color: "yellow", children: " \u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : balance !== null ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
3423
+ /* @__PURE__ */ jsx8(Text9, { color: "yellow", children: "\u{1F4B0} " }),
3424
+ /* @__PURE__ */ jsxs8(Text9, { color: "yellow", children: [
2265
3425
  "\u4F59\u989D \xA5",
2266
3426
  balance.toFixed(2)
2267
3427
  ] })
2268
3428
  ] }) : null,
2269
- todayCost !== null ? /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", children: [
2270
- /* @__PURE__ */ jsx7(Text8, { color: "cyan", children: "\u{1F4CA} " }),
2271
- /* @__PURE__ */ jsxs7(Text8, { color: "cyan", children: [
3429
+ todayCost !== null ? /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
3430
+ /* @__PURE__ */ jsx8(Text9, { color: "cyan", children: "\u{1F4CA} " }),
3431
+ /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
2272
3432
  "\u4ECA\u65E5 \xA5",
2273
3433
  todayCost.toFixed(2)
2274
3434
  ] })
2275
3435
  ] }) : null
2276
3436
  ] })
2277
3437
  ] }),
2278
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
2279
- /* @__PURE__ */ jsx7(Static, { items: displayMessages, children: (msg, i) => {
3438
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
3439
+ /* @__PURE__ */ jsx8(Static, { items: displayMessages, children: (msg, i) => {
2280
3440
  if (msg.role === "user") {
2281
- return /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, children: [
2282
- /* @__PURE__ */ jsx7(Box7, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
2283
- /* @__PURE__ */ jsx7(Box7, { flexGrow: 1, children: /* @__PURE__ */ jsx7(Text8, { wrap: "wrap", children: msg.content }) })
3441
+ return /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
3442
+ /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u{1F464}" }) }),
3443
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx8(Text9, { wrap: "wrap", children: msg.content }) })
3444
+ ] }, i);
3445
+ }
3446
+ if (msg.role === "tool") {
3447
+ return /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
3448
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
3449
+ /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#f59e0b", children: "\u{1F527}" }) }),
3450
+ /* @__PURE__ */ jsx8(Box8, { flexGrow: 1, children: /* @__PURE__ */ jsx8(Text9, { wrap: "wrap", children: msg.content }) })
3451
+ ] }),
3452
+ msg.diff && /* @__PURE__ */ jsx8(DiffPreview, { diff: msg.diff })
2284
3453
  ] }, i);
2285
3454
  }
2286
3455
  const detail = msg.assistantDetail;
2287
- return /* @__PURE__ */ jsx7(
3456
+ return /* @__PURE__ */ jsx8(
2288
3457
  AssistantMessage,
2289
3458
  {
2290
3459
  content: msg.content,
@@ -2298,7 +3467,7 @@ function ChatSession({
2298
3467
  i
2299
3468
  );
2300
3469
  } }, staticKey),
2301
- isStreaming && /* @__PURE__ */ jsx7(
3470
+ isStreaming && /* @__PURE__ */ jsx8(
2302
3471
  AssistantMessage,
2303
3472
  {
2304
3473
  content: currentContent,
@@ -2306,25 +3475,25 @@ function ChatSession({
2306
3475
  isStreaming: true
2307
3476
  }
2308
3477
  ),
2309
- isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx7(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
2310
- !isStreaming && streamError && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs7(Text8, { color: "red", children: [
3478
+ isStreaming && !currentContent && currentToolCalls.length === 0 && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, marginLeft: 4, children: /* @__PURE__ */ jsx8(Spinner, { type: "dots", label: "\u601D\u8003\u4E2D..." }) }),
3479
+ !isStreaming && streamError && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs8(Text9, { color: "red", children: [
2311
3480
  "\u26A0 ",
2312
3481
  streamError
2313
3482
  ] }) })
2314
3483
  ] }),
2315
- selectingModel ? /* @__PURE__ */ jsxs7(Box7, { marginTop: 1, flexDirection: "column", children: [
2316
- /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
2317
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
2318
- /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
3484
+ selectingModel ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
3485
+ /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
3486
+ /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
3487
+ /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
2319
3488
  modelOptions.map((id, i) => {
2320
3489
  const meta = SUPPORTED_MODELS[id];
2321
3490
  const isCurrent = id === activeModel;
2322
3491
  const isSelected = i === modelSelectIndex;
2323
3492
  const marker = isSelected ? " > " : " ";
2324
3493
  const suffix = isCurrent ? " (\u5F53\u524D)" : "";
2325
- return /* @__PURE__ */ jsxs7(Box7, { children: [
2326
- /* @__PURE__ */ jsxs7(
2327
- Text8,
3494
+ return /* @__PURE__ */ jsxs8(Box8, { children: [
3495
+ /* @__PURE__ */ jsxs8(
3496
+ Text9,
2328
3497
  {
2329
3498
  color: isSelected ? "#00ff41" : void 0,
2330
3499
  bold: isSelected,
@@ -2335,20 +3504,20 @@ function ChatSession({
2335
3504
  ]
2336
3505
  }
2337
3506
  ),
2338
- isSelected && /* @__PURE__ */ jsxs7(Text8, { color: "#808080", children: [
3507
+ isSelected && /* @__PURE__ */ jsxs8(Text9, { color: "#808080", children: [
2339
3508
  " \u2014 ",
2340
3509
  id
2341
3510
  ] })
2342
3511
  ] }, id);
2343
3512
  }),
2344
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
3513
+ /* @__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" }) })
2345
3514
  ] }),
2346
- /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
2347
- ] }) : /* @__PURE__ */ jsxs7(Fragment, { children: [
2348
- /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
2349
- /* @__PURE__ */ jsxs7(Box7, { children: [
2350
- /* @__PURE__ */ jsx7(Box7, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
2351
- /* @__PURE__ */ jsx7(Box7, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx7(Text8, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx7(Text8, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx7(Text8, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx7(
3515
+ /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
3516
+ ] }) : /* @__PURE__ */ jsxs8(Fragment, { children: [
3517
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
3518
+ /* @__PURE__ */ jsxs8(Box8, { children: [
3519
+ /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
3520
+ /* @__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(
2352
3521
  TextInput,
2353
3522
  {
2354
3523
  value: input,
@@ -2359,19 +3528,19 @@ function ChatSession({
2359
3528
  inputKey
2360
3529
  ) })
2361
3530
  ] }),
2362
- /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
2363
- /* @__PURE__ */ jsx7(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
2364
- /* @__PURE__ */ jsx7(FileSelector, { files, input, selectedIndex: fileSelectIndex })
3531
+ /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
3532
+ /* @__PURE__ */ jsx8(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
3533
+ /* @__PURE__ */ jsx8(FileSelector, { files, input, selectedIndex: fileSelectIndex })
2365
3534
  ] }),
2366
- doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
2367
- isStreaming && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
3535
+ 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" }) }),
3536
+ 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" }) })
2368
3537
  ] });
2369
3538
  }
2370
3539
 
2371
3540
  // src/ui/GamePicker.tsx
2372
- import { Box as Box8, Text as Text9, useInput as useInput2 } from "ink";
3541
+ import { Box as Box9, Text as Text10, useInput as useInput2 } from "ink";
2373
3542
  import { useState as useState4, useCallback as useCallback3 } from "react";
2374
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
3543
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
2375
3544
  function GamePicker({ games, onSelect, onExit, onBackToChat }) {
2376
3545
  const [selectedIndex, setSelectedIndex] = useState4(0);
2377
3546
  const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
@@ -2399,18 +3568,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
2399
3568
  [games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
2400
3569
  )
2401
3570
  );
2402
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2403
- /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
2404
- /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", children: games.map((game, index) => {
3571
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
3572
+ /* @__PURE__ */ jsx9(Box9, { marginBottom: 1, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
3573
+ /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: games.map((game, index) => {
2405
3574
  const isSelected = index === selectedIndex;
2406
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
2407
- /* @__PURE__ */ jsx8(Box8, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx8(Text9, { children: " " }) }),
2408
- /* @__PURE__ */ jsx8(Box8, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
2409
- /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { color: "#888888", children: game.description }) })
3575
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
3576
+ /* @__PURE__ */ jsx9(Box9, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx9(Text10, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx9(Text10, { children: " " }) }),
3577
+ /* @__PURE__ */ jsx9(Box9, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx9(Text10, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
3578
+ /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsx9(Text10, { color: "#888888", children: game.description }) })
2410
3579
  ] }, game.id);
2411
3580
  }) }),
2412
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
2413
- doubleCtrlC && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
3581
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
3582
+ 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" }) })
2414
3583
  ] });
2415
3584
  }
2416
3585
 
@@ -2427,9 +3596,9 @@ function listGames() {
2427
3596
  }
2428
3597
 
2429
3598
  // src/game/brick-breaker/index.tsx
2430
- import { Box as Box9, Text as Text10, useInput as useInput3, render as render2 } from "ink";
3599
+ import { Box as Box10, Text as Text11, useInput as useInput3, render as render2 } from "ink";
2431
3600
  import { useState as useState5, useEffect as useEffect4, useRef as useRef3, useCallback as useCallback4 } from "react";
2432
- import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
3601
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
2433
3602
  var GAME_WIDTH = 40;
2434
3603
  var GAME_HEIGHT = 18;
2435
3604
  var PADDLE_WIDTH = 9;
@@ -2619,49 +3788,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
2619
3788
  const board = buildBoard(s);
2620
3789
  const def = getLevel(s.level);
2621
3790
  void tick;
2622
- return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2623
- /* @__PURE__ */ jsxs9(Box9, { flexDirection: "row", children: [
2624
- /* @__PURE__ */ jsx9(Box9, { width: 20, children: /* @__PURE__ */ jsxs9(Text10, { children: [
3791
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
3792
+ /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
3793
+ /* @__PURE__ */ jsx10(Box10, { width: 20, children: /* @__PURE__ */ jsxs10(Text11, { children: [
2625
3794
  "\u5173\u5361 ",
2626
3795
  s.level,
2627
3796
  ": ",
2628
- /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: def.desc })
3797
+ /* @__PURE__ */ jsx10(Text11, { color: "cyan", children: def.desc })
2629
3798
  ] }) }),
2630
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
3799
+ /* @__PURE__ */ jsx10(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text11, { children: [
2631
3800
  "\u5206\u6570: ",
2632
- /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: String(s.score).padStart(3, "0") })
3801
+ /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: String(s.score).padStart(3, "0") })
2633
3802
  ] }) }),
2634
- /* @__PURE__ */ jsx9(Box9, { width: 12, children: /* @__PURE__ */ jsxs9(Text10, { children: [
3803
+ /* @__PURE__ */ jsx10(Box10, { width: 12, children: /* @__PURE__ */ jsxs10(Text11, { children: [
2635
3804
  "\u751F\u547D: ",
2636
- /* @__PURE__ */ jsx9(Text10, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
3805
+ /* @__PURE__ */ jsx10(Text11, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
2637
3806
  ] }) }),
2638
- /* @__PURE__ */ jsx9(Box9, { width: 10, children: /* @__PURE__ */ jsxs9(Text10, { children: [
3807
+ /* @__PURE__ */ jsx10(Box10, { width: 10, children: /* @__PURE__ */ jsxs10(Text11, { children: [
2639
3808
  "\u7816\u5757: ",
2640
- /* @__PURE__ */ jsx9(Text10, { color: "cyan", children: aliveCount })
3809
+ /* @__PURE__ */ jsx10(Text11, { color: "cyan", children: aliveCount })
2641
3810
  ] }) }),
2642
- /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: s.paused ? "gray" : "green", children: [
3811
+ /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsxs10(Text11, { color: s.paused ? "gray" : "green", children: [
2643
3812
  "[",
2644
3813
  s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
2645
3814
  "]"
2646
3815
  ] }) })
2647
3816
  ] }),
2648
- /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2649
- /* @__PURE__ */ jsxs9(Text10, { children: [
3817
+ /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
3818
+ /* @__PURE__ */ jsxs10(Text11, { children: [
2650
3819
  "\u250C",
2651
3820
  "\u2500".repeat(GAME_WIDTH),
2652
3821
  "\u2510"
2653
3822
  ] }),
2654
- /* @__PURE__ */ jsx9(Text10, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
2655
- /* @__PURE__ */ jsxs9(Text10, { children: [
3823
+ /* @__PURE__ */ jsx10(Text11, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
3824
+ /* @__PURE__ */ jsxs10(Text11, { children: [
2656
3825
  "\u2514",
2657
3826
  "\u2500".repeat(GAME_WIDTH),
2658
3827
  "\u2518"
2659
3828
  ] })
2660
3829
  ] }),
2661
- selectingLevel && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, flexDirection: "column", children: [
2662
- /* @__PURE__ */ jsx9(Text10, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
2663
- /* @__PURE__ */ jsx9(Box9, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx9(Box9, { width: 22, children: /* @__PURE__ */ jsxs9(Text10, { children: [
2664
- /* @__PURE__ */ jsx9(Text10, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
3830
+ selectingLevel && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
3831
+ /* @__PURE__ */ jsx10(Text11, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
3832
+ /* @__PURE__ */ jsx10(Box10, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx10(Box10, { width: 22, children: /* @__PURE__ */ jsxs10(Text11, { children: [
3833
+ /* @__PURE__ */ jsx10(Text11, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
2665
3834
  ". ",
2666
3835
  lv.desc,
2667
3836
  " (",
@@ -2670,16 +3839,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
2670
3839
  lv.cols,
2671
3840
  ")"
2672
3841
  ] }) }, i)) }),
2673
- /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
3842
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
2674
3843
  ] }),
2675
- !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs9(Box9, { marginTop: 1, children: [
2676
- /* @__PURE__ */ jsx9(Text10, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
2677
- /* @__PURE__ */ jsxs9(Text10, { children: [
3844
+ !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
3845
+ /* @__PURE__ */ jsx10(Text11, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
3846
+ /* @__PURE__ */ jsxs10(Text11, { children: [
2678
3847
  " \u5206\u6570: ",
2679
- /* @__PURE__ */ jsx9(Text10, { color: "yellow", children: s.score })
3848
+ /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: s.score })
2680
3849
  ] })
2681
3850
  ] }),
2682
- !selectingLevel && /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx9(Text10, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
3851
+ !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" }) })
2683
3852
  ] });
2684
3853
  }
2685
3854
  var brick_breaker_default = {
@@ -2687,11 +3856,11 @@ var brick_breaker_default = {
2687
3856
  name: "Brick Breaker",
2688
3857
  description: "\u7ECF\u5178\u6253\u7816\u5757\u6E38\u620F\uFF0C10 \u4E2A\u5173\u5361\u53EF\u9009\uFF01",
2689
3858
  play: async () => {
2690
- await new Promise((resolve) => {
3859
+ await new Promise((resolve2) => {
2691
3860
  const { unmount } = render2(
2692
- /* @__PURE__ */ jsx9(BrickBreakerGame, { onExit: () => {
3861
+ /* @__PURE__ */ jsx10(BrickBreakerGame, { onExit: () => {
2693
3862
  unmount();
2694
- resolve();
3863
+ resolve2();
2695
3864
  } })
2696
3865
  );
2697
3866
  });
@@ -2699,9 +3868,9 @@ var brick_breaker_default = {
2699
3868
  };
2700
3869
 
2701
3870
  // src/game/coder-check/index.tsx
2702
- import { Box as Box10, Text as Text11, useInput as useInput4, render as render3 } from "ink";
3871
+ import { Box as Box11, Text as Text12, useInput as useInput4, render as render3 } from "ink";
2703
3872
  import { useState as useState6, useEffect as useEffect5, useRef as useRef4, useCallback as useCallback5 } from "react";
2704
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
3873
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
2705
3874
  var GAME_W = 66;
2706
3875
  var GAME_H = 20;
2707
3876
  var SCORE_H = 6;
@@ -3172,44 +4341,44 @@ function CoderCheck({ onExit: _onExit }) {
3172
4341
  const scoreLines = buildScoreLines(scoreStr);
3173
4342
  const view = buildGameView(s, scoreLines, scoreColor, s.message);
3174
4343
  void tick;
3175
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingX: 1, children: [
3176
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "row", children: /* @__PURE__ */ jsxs10(Text11, { children: [
4344
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, children: [
4345
+ /* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: /* @__PURE__ */ jsxs11(Text12, { children: [
3177
4346
  "\u751F\u547D ",
3178
- /* @__PURE__ */ jsx10(Text11, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
4347
+ /* @__PURE__ */ jsx11(Text12, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
3179
4348
  " ",
3180
4349
  "\u901F\u5EA6 ",
3181
- /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
4350
+ /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
3182
4351
  "Lv.",
3183
4352
  Math.floor(s.speed * 10)
3184
4353
  ] })
3185
4354
  ] }) }),
3186
- !s.gameOver && s.target && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { children: [
4355
+ !s.gameOver && s.target && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { children: [
3187
4356
  "\u6253\u5B57: ",
3188
- /* @__PURE__ */ jsx10(Text11, { color: "green", children: s.typed }),
3189
- /* @__PURE__ */ jsx10(Text11, { color: "white", children: s.target.slice(s.typed.length) })
4357
+ /* @__PURE__ */ jsx11(Text12, { color: "green", children: s.typed }),
4358
+ /* @__PURE__ */ jsx11(Text12, { color: "white", children: s.target.slice(s.typed.length) })
3190
4359
  ] }) }),
3191
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
3192
- /* @__PURE__ */ jsxs10(Text11, { children: [
4360
+ /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
4361
+ /* @__PURE__ */ jsxs11(Text12, { children: [
3193
4362
  "\u250C",
3194
4363
  "\u2500".repeat(GAME_W),
3195
4364
  "\u2510"
3196
4365
  ] }),
3197
- view.map((row, i) => /* @__PURE__ */ jsx10(Text11, { children: `\u2502${row}\u2502` }, i)),
3198
- /* @__PURE__ */ jsxs10(Text11, { children: [
4366
+ view.map((row, i) => /* @__PURE__ */ jsx11(Text12, { children: `\u2502${row}\u2502` }, i)),
4367
+ /* @__PURE__ */ jsxs11(Text12, { children: [
3199
4368
  "\u2514",
3200
4369
  "\u2500".repeat(GAME_W),
3201
4370
  "\u2518"
3202
4371
  ] })
3203
4372
  ] }),
3204
- s.gameOver && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
3205
- /* @__PURE__ */ jsx10(Text11, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
3206
- /* @__PURE__ */ jsxs10(Text11, { children: [
4373
+ s.gameOver && /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
4374
+ /* @__PURE__ */ jsx11(Text12, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
4375
+ /* @__PURE__ */ jsxs11(Text12, { children: [
3207
4376
  " \u5F97\u5206: ",
3208
- /* @__PURE__ */ jsx10(Text11, { color: "yellow", children: s.score }),
4377
+ /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: s.score }),
3209
4378
  " r \u91CD\u5F00 q \u9000\u51FA"
3210
4379
  ] })
3211
4380
  ] }),
3212
- /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
4381
+ /* @__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" }) })
3213
4382
  ] });
3214
4383
  }
3215
4384
  var coder_check_default = {
@@ -3217,11 +4386,11 @@ var coder_check_default = {
3217
4386
  name: "Coder Check",
3218
4387
  description: "\u6781\u901F\u6253\u5B57\u6E38\u620F\uFF0C\u8F93\u5165\u5355\u8BCD\u6D88\u9664\u5B83\u4EEC\uFF01",
3219
4388
  play: async () => {
3220
- await new Promise((resolve) => {
4389
+ await new Promise((resolve2) => {
3221
4390
  const { unmount } = render3(
3222
- /* @__PURE__ */ jsx10(CoderCheck, { onExit: () => {
4391
+ /* @__PURE__ */ jsx11(CoderCheck, { onExit: () => {
3223
4392
  unmount();
3224
- resolve();
4393
+ resolve2();
3225
4394
  } })
3226
4395
  );
3227
4396
  });
@@ -3240,10 +4409,10 @@ import { render as render4 } from "ink";
3240
4409
  import chalk4 from "chalk";
3241
4410
 
3242
4411
  // src/stock/StockList.tsx
3243
- import { Box as Box11, Text as Text12, useInput as useInput5 } from "ink";
4412
+ import { Box as Box12, Text as Text13, useInput as useInput5 } from "ink";
3244
4413
  import { useState as useState7, useCallback as useCallback6, useEffect as useEffect6 } from "react";
3245
4414
  import asciichart from "asciichart";
3246
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
4415
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
3247
4416
  var MINUTE_API = "https://web.ifzq.gtimg.cn/appstock/app/minute/query?code={code}&r=0.1";
3248
4417
  function normalizeApiCode(code) {
3249
4418
  if (code.startsWith("sh") || code.startsWith("sz")) return code;
@@ -3440,57 +4609,57 @@ function StockList({ codes, onExit, onBackToChat }) {
3440
4609
  );
3441
4610
  if (detailView) {
3442
4611
  if (detailLoading) {
3443
- return /* @__PURE__ */ jsx11(Box11, { paddingLeft: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
4612
+ return /* @__PURE__ */ jsx12(Box12, { paddingLeft: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
3444
4613
  }
3445
4614
  return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
3446
4615
  }
3447
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
3448
- /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, justifyContent: "space-between", children: [
3449
- /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
3450
- /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
4616
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
4617
+ /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, justifyContent: "space-between", children: [
4618
+ /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
4619
+ /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3451
4620
  " \u{1F550} ",
3452
4621
  currentTime
3453
4622
  ] }),
3454
- /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
4623
+ /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
3455
4624
  ] }),
3456
- /* @__PURE__ */ jsxs11(Box11, { children: [
3457
- /* @__PURE__ */ jsx11(Box11, { width: 3 }),
3458
- /* @__PURE__ */ jsx11(Box11, { width: 9, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u4EE3\u7801" }) }),
3459
- /* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u540D\u79F0" }) }),
3460
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
3461
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
3462
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
3463
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u9AD8" }) }),
3464
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6700\u4F4E" }) }),
3465
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
4625
+ /* @__PURE__ */ jsxs12(Box12, { children: [
4626
+ /* @__PURE__ */ jsx12(Box12, { width: 3 }),
4627
+ /* @__PURE__ */ jsx12(Box12, { width: 9, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u4EE3\u7801" }) }),
4628
+ /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u540D\u79F0" }) }),
4629
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
4630
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
4631
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
4632
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u9AD8" }) }),
4633
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6700\u4F4E" }) }),
4634
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
3466
4635
  ] }),
3467
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
3468
- /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: stocks.map((stock, index) => {
4636
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
4637
+ /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: stocks.map((stock, index) => {
3469
4638
  const isSelected = index === selectedIndex;
3470
4639
  const isUp = stock.changePercent >= 0;
3471
4640
  const color = isUp ? "#ff1493" : "#00ff41";
3472
- return /* @__PURE__ */ jsxs11(Box11, { children: [
3473
- /* @__PURE__ */ jsx11(Box11, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: "\u25B8 " }) : /* @__PURE__ */ jsx11(Text12, { children: " " }) }),
3474
- /* @__PURE__ */ jsx11(Box11, { width: 9, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: isSelected ? "#00ffff" : "#ffffff", children: stock.code }) }),
3475
- /* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { color: isSelected ? "#ffffff" : "#cccccc", children: stock.name }) }),
3476
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color, children: formatPrice(stock.price) }) }),
3477
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { color, children: [
4641
+ return /* @__PURE__ */ jsxs12(Box12, { children: [
4642
+ /* @__PURE__ */ jsx12(Box12, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: "\u25B8 " }) : /* @__PURE__ */ jsx12(Text13, { children: " " }) }),
4643
+ /* @__PURE__ */ jsx12(Box12, { width: 9, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: isSelected ? "#00ffff" : "#ffffff", children: stock.code }) }),
4644
+ /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { color: isSelected ? "#ffffff" : "#cccccc", children: stock.name }) }),
4645
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color, children: formatPrice(stock.price) }) }),
4646
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { color, children: [
3478
4647
  isUp ? "+" : "",
3479
4648
  stock.changePercent.toFixed(2),
3480
4649
  "%"
3481
4650
  ] }) }),
3482
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsxs11(Text12, { color, children: [
4651
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsxs12(Text13, { color, children: [
3483
4652
  isUp ? "+" : "",
3484
4653
  stock.changeAmount.toFixed(3)
3485
4654
  ] }) }),
3486
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { color: "#cccccc", children: formatPrice(stock.high) }) }),
3487
- /* @__PURE__ */ jsx11(Box11, { width: 12, children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: formatPrice(stock.low) }) }),
3488
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: formatAmount(stock.amount) }) })
4655
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { color: "#cccccc", children: formatPrice(stock.high) }) }),
4656
+ /* @__PURE__ */ jsx12(Box12, { width: 12, children: /* @__PURE__ */ jsx12(Text13, { color: "#888888", children: formatPrice(stock.low) }) }),
4657
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { color: "#888888", children: formatAmount(stock.amount) }) })
3489
4658
  ] }, stock.code);
3490
4659
  }) }),
3491
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 q \u8FD4\u56DE` }) }),
3492
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ~/.dskcode/settings.json` }) }),
3493
- doubleCtrlC && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
4660
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 q \u8FD4\u56DE` }) }),
4661
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ~/.dskcode/settings.json` }) }),
4662
+ doubleCtrlC && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
3494
4663
  ] });
3495
4664
  }
3496
4665
  function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
@@ -3508,33 +4677,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
3508
4677
  raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
3509
4678
  chartLines = raw.split("\n");
3510
4679
  }
3511
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingLeft: 1, children: [
3512
- /* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, justifyContent: "space-between", children: [
3513
- /* @__PURE__ */ jsxs11(Box11, { children: [
3514
- /* @__PURE__ */ jsxs11(Text12, { bold: true, color: "#00ffff", children: [
4680
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, children: [
4681
+ /* @__PURE__ */ jsxs12(Box12, { marginBottom: 1, justifyContent: "space-between", children: [
4682
+ /* @__PURE__ */ jsxs12(Box12, { children: [
4683
+ /* @__PURE__ */ jsxs12(Text13, { bold: true, color: "#00ffff", children: [
3515
4684
  " \u{1F4CA} ",
3516
4685
  stock.name,
3517
4686
  " "
3518
4687
  ] }),
3519
- /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: stock.code }),
3520
- currentTime && /* @__PURE__ */ jsxs11(Text12, { dimColor: true, children: [
4688
+ /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: stock.code }),
4689
+ currentTime && /* @__PURE__ */ jsxs12(Text13, { dimColor: true, children: [
3521
4690
  " \u{1F550} ",
3522
4691
  currentTime
3523
4692
  ] })
3524
4693
  ] }),
3525
- /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
4694
+ /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
3526
4695
  ] }),
3527
- /* @__PURE__ */ jsxs11(Box11, { children: [
3528
- /* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
3529
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { bold: true, color: colorCode, children: [
4696
+ /* @__PURE__ */ jsxs12(Box12, { children: [
4697
+ /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
4698
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { bold: true, color: colorCode, children: [
3530
4699
  arrow,
3531
4700
  " ",
3532
4701
  formatPrice(stock.price)
3533
4702
  ] }) })
3534
4703
  ] }),
3535
- /* @__PURE__ */ jsxs11(Box11, { children: [
3536
- /* @__PURE__ */ jsx11(Box11, { width: 16, children: /* @__PURE__ */ jsx11(Text12, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
3537
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: colorCode, children: [
4704
+ /* @__PURE__ */ jsxs12(Box12, { children: [
4705
+ /* @__PURE__ */ jsx12(Box12, { width: 16, children: /* @__PURE__ */ jsx12(Text13, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
4706
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: colorCode, children: [
3538
4707
  isUp ? "+" : "",
3539
4708
  stock.changePercent.toFixed(2),
3540
4709
  "%",
@@ -3543,14 +4712,14 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
3543
4712
  stock.changeAmount.toFixed(3)
3544
4713
  ] }) })
3545
4714
  ] }),
3546
- chartLines.length > 0 && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: colorCode, children: line || " " }) }, i)) }),
3547
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
4715
+ 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)) }),
4716
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
3548
4717
  ] });
3549
4718
  }
3550
4719
 
3551
4720
  // src/utils/scan-files.ts
3552
- import { readdir as readdir2 } from "fs/promises";
3553
- import { join as join4, relative } from "path";
4721
+ import { readdir as readdir5 } from "fs/promises";
4722
+ import { join as join7, relative as relative4 } from "path";
3554
4723
  var IGNORE_DIRS = /* @__PURE__ */ new Set([
3555
4724
  "node_modules",
3556
4725
  ".git",
@@ -3601,7 +4770,7 @@ async function scanProjectFiles(baseDir, dir) {
3601
4770
  const currentDir = dir ?? baseDir;
3602
4771
  let entries;
3603
4772
  try {
3604
- entries = await readdir2(currentDir, { withFileTypes: true });
4773
+ entries = await readdir5(currentDir, { withFileTypes: true });
3605
4774
  } catch {
3606
4775
  return [];
3607
4776
  }
@@ -3615,12 +4784,12 @@ async function scanProjectFiles(baseDir, dir) {
3615
4784
  } else if (entry.isFile()) {
3616
4785
  const ext = name.slice(name.lastIndexOf(".")).toLowerCase();
3617
4786
  if (SOURCE_EXTS.has(ext)) {
3618
- files.push(relative(baseDir, join4(currentDir, name)));
4787
+ files.push(relative4(baseDir, join7(currentDir, name)));
3619
4788
  }
3620
4789
  }
3621
4790
  }
3622
4791
  const nested = await Promise.all(
3623
- dirs.map((d) => scanProjectFiles(baseDir, join4(currentDir, d)))
4792
+ dirs.map((d) => scanProjectFiles(baseDir, join7(currentDir, d)))
3624
4793
  );
3625
4794
  for (const n of nested) {
3626
4795
  files.push(...n);
@@ -3629,7 +4798,7 @@ async function scanProjectFiles(baseDir, dir) {
3629
4798
  }
3630
4799
 
3631
4800
  // src/cli/index.tsx
3632
- import { jsx as jsx12 } from "react/jsx-runtime";
4801
+ import { jsx as jsx13 } from "react/jsx-runtime";
3633
4802
  var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
3634
4803
  function createCli() {
3635
4804
  const program2 = new Command();
@@ -3675,7 +4844,7 @@ function createCli() {
3675
4844
  );
3676
4845
  const model = defaultProvider?.model ?? "deepseek-v4-flash";
3677
4846
  const chatApp = renderApp(
3678
- /* @__PURE__ */ jsx12(
4847
+ /* @__PURE__ */ jsx13(
3679
4848
  ChatSession,
3680
4849
  {
3681
4850
  skillCount,
@@ -3693,7 +4862,7 @@ function createCli() {
3693
4862
  initGames();
3694
4863
  const games = listGames();
3695
4864
  const { unmount } = render4(
3696
- /* @__PURE__ */ jsx12(
4865
+ /* @__PURE__ */ jsx13(
3697
4866
  GamePicker,
3698
4867
  {
3699
4868
  games,
@@ -3717,7 +4886,7 @@ function createCli() {
3717
4886
  setImmediate(() => {
3718
4887
  const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
3719
4888
  const stockApp = renderApp(
3720
- /* @__PURE__ */ jsx12(
4889
+ /* @__PURE__ */ jsx13(
3721
4890
  StockList,
3722
4891
  {
3723
4892
  codes: defaultStockCodes,
@@ -3781,10 +4950,10 @@ compdef _dskcode_completion dskcode`);
3781
4950
  program2.command("stock").description("\u67E5\u770B\u81EA\u9009\u80A1\u5B9E\u65F6\u884C\u60C5").argument("[codes...]", "\u80A1\u7968\u4EE3\u7801\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u5982 513090 600519").action(async function(codes) {
3782
4951
  const ctx = this.dskcodeCtx;
3783
4952
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
3784
- const globalConfigPath = join5(home, ".dskcode", "settings.json");
4953
+ const globalConfigPath = join8(home, ".dskcode", "settings.json");
3785
4954
  let globalConfigHasStock = false;
3786
4955
  try {
3787
- const raw = await readFile4(globalConfigPath, "utf-8");
4956
+ const raw = await readFile8(globalConfigPath, "utf-8");
3788
4957
  const parsed = JSON.parse(raw);
3789
4958
  const stock = parsed.stock;
3790
4959
  globalConfigHasStock = Array.isArray(stock?.symbols) && stock.symbols.length > 0;
@@ -3804,7 +4973,7 @@ compdef _dskcode_completion dskcode`);
3804
4973
  const freshResult = await loadAndValidate();
3805
4974
  const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
3806
4975
  const app = renderApp(
3807
- /* @__PURE__ */ jsx12(
4976
+ /* @__PURE__ */ jsx13(
3808
4977
  StockList,
3809
4978
  {
3810
4979
  codes: codeList,
@@ -3831,19 +5000,19 @@ compdef _dskcode_completion dskcode`);
3831
5000
  console.log("\u6682\u65E0\u53EF\u7528\u6E38\u620F\u3002");
3832
5001
  return;
3833
5002
  }
3834
- const selectedGame = await new Promise((resolve) => {
5003
+ const selectedGame = await new Promise((resolve2) => {
3835
5004
  const { unmount } = render4(
3836
- /* @__PURE__ */ jsx12(
5005
+ /* @__PURE__ */ jsx13(
3837
5006
  GamePicker,
3838
5007
  {
3839
5008
  games,
3840
5009
  onSelect: (game) => {
3841
5010
  unmount();
3842
- resolve(game);
5011
+ resolve2(game);
3843
5012
  },
3844
5013
  onExit: () => {
3845
5014
  unmount();
3846
- resolve(null);
5015
+ resolve2(null);
3847
5016
  }
3848
5017
  }
3849
5018
  ),