dskcode 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,15 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DeepSeekProvider,
4
- ModelNotSupportedError
5
- } from "./chunk-BA7UJPKJ.js";
6
- import {
4
+ ModelNotSupportedError,
7
5
  SUPPORTED_MODELS,
8
6
  calculateCost,
9
7
  estimateTokens,
10
8
  getModelMeta,
11
9
  isSupportedModel
12
- } from "./chunk-7QS2XBBX.js";
10
+ } from "./chunk-I6HEIOSU.js";
13
11
 
14
12
  // src/cli/index.tsx
15
13
  import { Command } from "commander";
@@ -818,7 +816,7 @@ var LOGO_LINES = [
818
816
  // src/ui/ChatSession.tsx
819
817
  import { Box as Box8, Text as Text9, useInput, Static } from "ink";
820
818
  import TextInput from "ink-text-input";
821
- import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useRef as useRef2 } from "react";
819
+ import { useEffect as useEffect3, useState as useState3, useCallback as useCallback2, useMemo, useRef as useRef2 } from "react";
822
820
 
823
821
  // src/ui/useDoubleCtrlC.ts
824
822
  import { useState as useState2, useCallback, useEffect as useEffect2, useRef } from "react";
@@ -848,6 +846,9 @@ function useDoubleCtrlC(onExit) {
848
846
  return { doubleCtrlC, handleCtrlC };
849
847
  }
850
848
 
849
+ // src/ui/ChatSession.tsx
850
+ import InkSpinner2 from "ink-spinner";
851
+
851
852
  // src/ui/AssistantMessage.tsx
852
853
  import { Box as Box4, Text as Text5 } from "ink";
853
854
 
@@ -1440,6 +1441,44 @@ function createProvider(config) {
1440
1441
  return defaultRegistry.get(config.name, config);
1441
1442
  }
1442
1443
 
1444
+ // src/tool/types.ts
1445
+ function eraseTool(tool) {
1446
+ return {
1447
+ get name() {
1448
+ return tool.name;
1449
+ },
1450
+ get description() {
1451
+ return tool.description;
1452
+ },
1453
+ get kind() {
1454
+ return tool.kind;
1455
+ },
1456
+ get parameters() {
1457
+ return tool.parameters;
1458
+ },
1459
+ get supportsInputStreaming() {
1460
+ return tool.supportsInputStreaming ?? false;
1461
+ },
1462
+ get supportedProviders() {
1463
+ return tool.supportedProviders ?? [];
1464
+ },
1465
+ async execute(args, ctx) {
1466
+ return tool.execute(args, ctx);
1467
+ },
1468
+ initialTitle(args) {
1469
+ return tool.initialTitle?.(args) ?? `${tool.name}`;
1470
+ }
1471
+ };
1472
+ }
1473
+ function isReadOnly(kind) {
1474
+ return kind === "read" /* Read */;
1475
+ }
1476
+ var AlwaysAllowGate = class {
1477
+ check(_toolName, _args) {
1478
+ return true;
1479
+ }
1480
+ };
1481
+
1443
1482
  // src/agent/extra-prompt.ts
1444
1483
  var EXTRA_PROMPT = [
1445
1484
  "\u3010\u7EC8\u7AEF\u8F93\u51FA\u7EA6\u675F\u3011",
@@ -1542,14 +1581,28 @@ ${opts.projectContext}`);
1542
1581
  var ToolRegistry = class {
1543
1582
  #tools = /* @__PURE__ */ new Map();
1544
1583
  #disabledNames;
1584
+ #featureFlagChecker;
1585
+ #provider;
1586
+ /** 所有已注册工具的名称列表(编译期等效) */
1587
+ static ALL_TOOL_NAMES = [];
1545
1588
  constructor(opts) {
1546
1589
  this.#disabledNames = new Set(opts?.disabledTools ?? []);
1590
+ this.#featureFlagChecker = opts?.featureFlagChecker ?? (() => true);
1591
+ this.#provider = opts?.provider;
1547
1592
  }
1548
1593
  /**
1549
- * 注册一个工具。
1594
+ * 注册一个类型安全的 AgentTool。
1595
+ * 自动擦除类型参数后存储。
1550
1596
  * 如果同名工具已存在则抛出错误。
1551
1597
  */
1552
1598
  register(tool) {
1599
+ return this.registerErased(eraseTool(tool));
1600
+ }
1601
+ /**
1602
+ * 注册一个已经擦除类型 AnyAgentTool。
1603
+ * 如果同名工具已存在则抛出错误。
1604
+ */
1605
+ registerErased(tool) {
1553
1606
  if (this.#tools.has(tool.name)) {
1554
1607
  throw new Error(`\u5DE5\u5177 "${tool.name}" \u5DF2\u6CE8\u518C\uFF0C\u4E0D\u80FD\u91CD\u590D\u6CE8\u518C`);
1555
1608
  }
@@ -1561,7 +1614,7 @@ var ToolRegistry = class {
1561
1614
  */
1562
1615
  registerAll(tools) {
1563
1616
  for (const tool of tools) {
1564
- this.register(tool);
1617
+ this.registerErased(tool);
1565
1618
  }
1566
1619
  return this;
1567
1620
  }
@@ -1572,25 +1625,44 @@ var ToolRegistry = class {
1572
1625
  return this.#tools.delete(name);
1573
1626
  }
1574
1627
  /**
1575
- * 按名称获取工具。
1576
- * 如果工具被禁用或不存在,返回 undefined。
1628
+ * 按名称获取工具(未擦除类型版本,调用方自行断言类型)。
1629
+ * 如果工具被禁用、被 feature flag 拦截、或不支持当前 provider,返回 undefined。
1577
1630
  */
1578
1631
  get(name) {
1579
- if (this.#disabledNames.has(name)) return void 0;
1632
+ if (!this.#isToolEnabled(name)) return void 0;
1580
1633
  return this.#tools.get(name);
1581
1634
  }
1582
1635
  /**
1583
1636
  * 获取所有启用的工具列表。
1637
+ * 依次应用:禁用列表 → Feature Flag → Provider 过滤。
1584
1638
  */
1585
1639
  list() {
1586
1640
  const result = [];
1587
1641
  for (const [name, tool] of this.#tools) {
1588
- if (!this.#disabledNames.has(name)) {
1642
+ if (this.#isToolEnabled(name)) {
1589
1643
  result.push(tool);
1590
1644
  }
1591
1645
  }
1592
1646
  return result;
1593
1647
  }
1648
+ /**
1649
+ * 按 ToolKind 分类获取工具列表。
1650
+ */
1651
+ listByKind(kind) {
1652
+ return this.list().filter((t) => t.kind === kind);
1653
+ }
1654
+ /**
1655
+ * 获取读工具列表(可并行执行)。
1656
+ */
1657
+ listReadTools() {
1658
+ return this.listByKind("read" /* Read */);
1659
+ }
1660
+ /**
1661
+ * 获取写工具列表(需串行执行)。
1662
+ */
1663
+ listWriteTools() {
1664
+ return this.list().filter((t) => !isReadOnly(t.kind));
1665
+ }
1594
1666
  /**
1595
1667
  * 获取所有已注册的工具名称(含禁用的)。
1596
1668
  */
@@ -1604,10 +1676,10 @@ var ToolRegistry = class {
1604
1676
  return this.#tools.has(name);
1605
1677
  }
1606
1678
  /**
1607
- * 检查工具是否已启用。
1679
+ * 检查工具是否已启用(注册 + 未禁用 + 通过 feature flag + 支持 provider)。
1608
1680
  */
1609
1681
  isEnabled(name) {
1610
- return this.#tools.has(name) && !this.#disabledNames.has(name);
1682
+ return this.#tools.has(name) && this.#isToolEnabled(name);
1611
1683
  }
1612
1684
  /**
1613
1685
  * 禁用一个工具。
@@ -1621,6 +1693,12 @@ var ToolRegistry = class {
1621
1693
  enable(name) {
1622
1694
  this.#disabledNames.delete(name);
1623
1695
  }
1696
+ /**
1697
+ * 获取工具的分类语义。
1698
+ */
1699
+ kindOf(name) {
1700
+ return this.#tools.get(name)?.kind;
1701
+ }
1624
1702
  /**
1625
1703
  * 执行指定工具。
1626
1704
  *
@@ -1646,11 +1724,21 @@ var ToolRegistry = class {
1646
1724
  };
1647
1725
  }
1648
1726
  }
1649
- };
1650
-
1651
- // src/tool/types.ts
1652
- var AlwaysAllowGate = class {
1653
- check(_toolName, _args) {
1727
+ // ---------------------------------------------------------------------------
1728
+ // 内部方法
1729
+ // ---------------------------------------------------------------------------
1730
+ /**
1731
+ * 判断工具是否应该启用。
1732
+ * 依次检查:是否在禁用列表 → 是否通过 Feature Flag → 是否支持当前 Provider。
1733
+ */
1734
+ #isToolEnabled(name) {
1735
+ const tool = this.#tools.get(name);
1736
+ if (!tool) return false;
1737
+ if (this.#disabledNames.has(name)) return false;
1738
+ if (!this.#featureFlagChecker(name)) return false;
1739
+ if (this.#provider && tool.supportedProviders.length > 0) {
1740
+ if (!tool.supportedProviders.includes(this.#provider)) return false;
1741
+ }
1654
1742
  return true;
1655
1743
  }
1656
1744
  };
@@ -1718,7 +1806,7 @@ var Session = class {
1718
1806
  * d. 如果没有工具调用 → 退出循环
1719
1807
  * 3. yield done 事件
1720
1808
  */
1721
- async *chat(userInput) {
1809
+ async *chat(userInput, opts) {
1722
1810
  this.#messages.push({ role: "user", content: userInput });
1723
1811
  const startTime = Date.now();
1724
1812
  let toolRounds = 0;
@@ -1738,7 +1826,11 @@ var Session = class {
1738
1826
  const toolDefs = this.#buildToolDefinitions();
1739
1827
  const stream = this.#provider.chat(apiMessages, {
1740
1828
  signal: this.#abortController.signal,
1741
- tools: toolDefs.length > 0 ? toolDefs : void 0
1829
+ tools: toolDefs.length > 0 ? toolDefs : void 0,
1830
+ thinkingAllowed: opts?.thinkingAllowed,
1831
+ thinkingEffort: opts?.thinkingEffort,
1832
+ responseFormat: opts?.responseFormat,
1833
+ toolChoice: opts?.toolChoice
1742
1834
  });
1743
1835
  let accumulatedText = "";
1744
1836
  let lastUsage;
@@ -1840,7 +1932,7 @@ ${item.result.diff.patch}`;
1840
1932
  };
1841
1933
  const allReadOnly = calls.every((tc) => {
1842
1934
  const tool = this.#toolRegistry.get(tc.name);
1843
- return tool?.readOnly === true;
1935
+ return tool ? isReadOnly(tool.kind) : true;
1844
1936
  });
1845
1937
  if (allReadOnly && calls.length > 1) {
1846
1938
  const MAX_PARALLEL = 8;
@@ -1894,11 +1986,11 @@ ${item.result.diff.patch}`;
1894
1986
  record: { name: toolName, success: false, error: "GATE_DENIED", timestamp }
1895
1987
  };
1896
1988
  }
1897
- if (!tool.readOnly) {
1898
- const maybePreviewer = tool;
1899
- if (typeof maybePreviewer.preview === "function") {
1989
+ if (!isReadOnly(tool.kind)) {
1990
+ const maybePreview = tool.preview;
1991
+ if (typeof maybePreview === "function") {
1900
1992
  try {
1901
- await maybePreviewer.preview(toolArgs, ctx);
1993
+ await maybePreview(toolArgs, ctx);
1902
1994
  } catch {
1903
1995
  }
1904
1996
  }
@@ -2413,25 +2505,6 @@ async function writeFileWithEol(filePath, originalContent, newContent) {
2413
2505
  import { readFile as readFile4, stat } from "fs/promises";
2414
2506
  import { open } from "fs/promises";
2415
2507
  import { relative as relative2 } from "path";
2416
- var readFileSchema = {
2417
- type: "object",
2418
- properties: {
2419
- path: {
2420
- type: "string",
2421
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2422
- },
2423
- startLine: {
2424
- type: "number",
2425
- description: "\u8D77\u59CB\u884C\u53F7\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u9ED8\u8BA4\u4E3A 1"
2426
- },
2427
- endLine: {
2428
- type: "number",
2429
- description: "\u7ED3\u675F\u884C\u53F7\uFF08\u5305\u542B\uFF09\uFF0C\u9ED8\u8BA4\u5230\u6587\u4EF6\u672B\u5C3E"
2430
- }
2431
- },
2432
- required: ["path"],
2433
- additionalProperties: false
2434
- };
2435
2508
  async function checkBinary(filePath) {
2436
2509
  const fileHandle = await open(filePath, "r");
2437
2510
  try {
@@ -2444,15 +2517,32 @@ async function checkBinary(filePath) {
2444
2517
  }
2445
2518
  var readFileTool = {
2446
2519
  name: "read_file",
2520
+ kind: "read" /* Read */,
2447
2521
  description: "\u8BFB\u53D6\u6307\u5B9A\u8DEF\u5F84\u7684\u6587\u4EF6\u5185\u5BB9\u3002\u652F\u6301\u884C\u53F7\u8303\u56F4\u9009\u62E9\uFF0C\u8F93\u51FA\u5E26\u884C\u53F7\u3002\u9002\u7528\u4E8E\u67E5\u770B\u6E90\u4EE3\u7801\u3001\u914D\u7F6E\u6587\u4EF6\u7B49\u6587\u672C\u6587\u4EF6\u3002\u81EA\u52A8\u62D2\u7EDD\u4E8C\u8FDB\u5236\u6587\u4EF6\u3002",
2448
- parameters: readFileSchema,
2449
- readOnly: true,
2522
+ parameters: {
2523
+ type: "object",
2524
+ properties: {
2525
+ path: {
2526
+ type: "string",
2527
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2528
+ },
2529
+ startLine: {
2530
+ type: "number",
2531
+ description: "\u8D77\u59CB\u884C\u53F7\uFF08\u4ECE 1 \u5F00\u59CB\uFF09\uFF0C\u9ED8\u8BA4\u4E3A 1"
2532
+ },
2533
+ endLine: {
2534
+ type: "number",
2535
+ description: "\u7ED3\u675F\u884C\u53F7\uFF08\u5305\u542B\uFF09\uFF0C\u9ED8\u8BA4\u5230\u6587\u4EF6\u672B\u5C3E"
2536
+ }
2537
+ },
2538
+ required: ["path"],
2539
+ additionalProperties: false
2540
+ },
2450
2541
  async execute(args, ctx) {
2451
- const params = args;
2452
- if (!params?.path || typeof params.path !== "string") {
2542
+ if (!args?.path || typeof args.path !== "string") {
2453
2543
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2454
2544
  }
2455
- const filePath = resolvePath(params.path, ctx.cwd);
2545
+ const filePath = resolvePath(args.path, ctx.cwd);
2456
2546
  try {
2457
2547
  const fileStat = await stat(filePath);
2458
2548
  const maxSize = 10 * 1024 * 1024;
@@ -2485,8 +2575,8 @@ var readFileTool = {
2485
2575
  if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
2486
2576
  lines.pop();
2487
2577
  }
2488
- const startLine = Math.max(1, params.startLine ?? 1) - 1;
2489
- const endLine = params.endLine ? Math.min(params.endLine, lines.length) : lines.length;
2578
+ const startLine = Math.max(1, args.startLine ?? 1) - 1;
2579
+ const endLine = args.endLine ? Math.min(args.endLine, lines.length) : lines.length;
2490
2580
  const selectedLines = lines.slice(startLine, endLine);
2491
2581
  const lineNumWidth = String(endLine).length;
2492
2582
  const result = selectedLines.map((line, i) => {
@@ -2518,35 +2608,33 @@ var readFileTool = {
2518
2608
  // src/tool/builtins/write-file.ts
2519
2609
  import { mkdir as mkdir4, readFile as readFile5 } from "fs/promises";
2520
2610
  import { dirname, relative as relative3, basename } from "path";
2521
- var writeFileSchema = {
2522
- type: "object",
2523
- properties: {
2524
- path: {
2525
- type: "string",
2526
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2527
- },
2528
- content: {
2529
- type: "string",
2530
- description: "\u8981\u5199\u5165\u7684\u6587\u4EF6\u5185\u5BB9"
2531
- }
2532
- },
2533
- required: ["path", "content"],
2534
- additionalProperties: false
2535
- };
2536
2611
  var writeFileTool = {
2537
2612
  name: "write_file",
2613
+ kind: "edit" /* Edit */,
2538
2614
  description: "\u521B\u5EFA\u6216\u8986\u76D6\u6587\u4EF6\u3002\u5982\u679C\u7236\u76EE\u5F55\u4E0D\u5B58\u5728\u4F1A\u81EA\u52A8\u521B\u5EFA\u3002\u9002\u7528\u4E8E\u521B\u5EFA\u65B0\u6587\u4EF6\u6216\u5B8C\u5168\u66FF\u6362\u6587\u4EF6\u5185\u5BB9\u3002\u8BF7\u52FF\u7528\u6B64\u5DE5\u5177\u521B\u5EFA _temp_\u3001_debug_ \u7B49\u7528\u4E8E\u8BCA\u65AD/\u8C03\u8BD5\u7684\u4E34\u65F6\u6587\u4EF6\u2014\u2014\u5982\u9700\u8BCA\u65AD\u8BF7\u6539\u7528 bash \u5DE5\u5177\u5185\u8054\u811A\u672C\uFF08node -e\uFF09\u3002",
2539
- parameters: writeFileSchema,
2540
- readOnly: false,
2615
+ parameters: {
2616
+ type: "object",
2617
+ properties: {
2618
+ path: {
2619
+ type: "string",
2620
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2621
+ },
2622
+ content: {
2623
+ type: "string",
2624
+ description: "\u8981\u5199\u5165\u7684\u6587\u4EF6\u5185\u5BB9"
2625
+ }
2626
+ },
2627
+ required: ["path", "content"],
2628
+ additionalProperties: false
2629
+ },
2541
2630
  async execute(args, ctx) {
2542
- const params = args;
2543
- if (!params?.path || typeof params.path !== "string") {
2631
+ if (!args?.path || typeof args.path !== "string") {
2544
2632
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2545
2633
  }
2546
- if (params.content === void 0 || params.content === null) {
2634
+ if (args.content === void 0 || args.content === null) {
2547
2635
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 content", error: "INVALID_ARGS" };
2548
2636
  }
2549
- const filePath = resolvePath(params.path, ctx.cwd);
2637
+ const filePath = resolvePath(args.path, ctx.cwd);
2550
2638
  try {
2551
2639
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2552
2640
  const conf = await confine(ctx.writeRoots, filePath);
@@ -2562,7 +2650,7 @@ var writeFileTool = {
2562
2650
  } catch {
2563
2651
  }
2564
2652
  await mkdir4(dirname(filePath), { recursive: true });
2565
- const content = String(params.content);
2653
+ const content = String(args.content);
2566
2654
  await writeFileWithEol(filePath, oldContent, content);
2567
2655
  const diff = computeFileDiff(oldContent, content, filePath);
2568
2656
  diff.existedBefore = existedBefore;
@@ -2592,42 +2680,40 @@ var writeFileTool = {
2592
2680
  // src/tool/builtins/edit-file.ts
2593
2681
  import { readFile as readFile6 } from "fs/promises";
2594
2682
  import { basename as basename2 } from "path";
2595
- var editFileSchema = {
2596
- type: "object",
2597
- properties: {
2598
- path: {
2599
- type: "string",
2600
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2601
- },
2602
- old_text: {
2603
- type: "string",
2604
- description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09"
2605
- },
2606
- new_text: {
2607
- type: "string",
2608
- description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C"
2609
- }
2610
- },
2611
- required: ["path", "old_text", "new_text"],
2612
- additionalProperties: false
2613
- };
2614
2683
  var editFileTool = {
2615
2684
  name: "edit_file",
2685
+ kind: "edit" /* Edit */,
2616
2686
  description: "\u5BF9\u6587\u4EF6\u8FDB\u884C\u7CBE\u786E\u5B57\u7B26\u4E32\u66FF\u6362\u3002\u67E5\u627E\u6587\u4EF6\u4E2D\u7684 old_text \u5E76\u66FF\u6362\u4E3A new_text\u3002\u5982\u679C old_text \u51FA\u73B0\u591A\u6B21\u6216\u672A\u627E\u5230\u5219\u62A5\u9519\u3002\u9002\u7528\u4E8E\u5C0F\u8303\u56F4\u7CBE\u786E\u4FEE\u6539\u3002",
2617
- parameters: editFileSchema,
2618
- readOnly: false,
2687
+ parameters: {
2688
+ type: "object",
2689
+ properties: {
2690
+ path: {
2691
+ type: "string",
2692
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2693
+ },
2694
+ old_text: {
2695
+ type: "string",
2696
+ description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09"
2697
+ },
2698
+ new_text: {
2699
+ type: "string",
2700
+ description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C"
2701
+ }
2702
+ },
2703
+ required: ["path", "old_text", "new_text"],
2704
+ additionalProperties: false
2705
+ },
2619
2706
  async execute(args, ctx) {
2620
- const params = args;
2621
- if (!params?.path || typeof params.path !== "string") {
2707
+ if (!args?.path || typeof args.path !== "string") {
2622
2708
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2623
2709
  }
2624
- if (typeof params.old_text !== "string") {
2710
+ if (typeof args.old_text !== "string") {
2625
2711
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 old_text", error: "INVALID_ARGS" };
2626
2712
  }
2627
- if (typeof params.new_text !== "string") {
2713
+ if (typeof args.new_text !== "string") {
2628
2714
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 new_text", error: "INVALID_ARGS" };
2629
2715
  }
2630
- const filePath = resolvePath(params.path, ctx.cwd);
2716
+ const filePath = resolvePath(args.path, ctx.cwd);
2631
2717
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2632
2718
  const conf = await confine(ctx.writeRoots, filePath);
2633
2719
  if (!conf.ok) {
@@ -2636,7 +2722,7 @@ var editFileTool = {
2636
2722
  }
2637
2723
  try {
2638
2724
  const content = await readFile6(filePath, "utf-8");
2639
- const firstIndex = content.indexOf(params.old_text);
2725
+ const firstIndex = content.indexOf(args.old_text);
2640
2726
  if (firstIndex === -1) {
2641
2727
  return {
2642
2728
  success: false,
@@ -2644,7 +2730,7 @@ var editFileTool = {
2644
2730
  error: "TEXT_NOT_FOUND"
2645
2731
  };
2646
2732
  }
2647
- const secondIndex = content.indexOf(params.old_text, firstIndex + 1);
2733
+ const secondIndex = content.indexOf(args.old_text, firstIndex + 1);
2648
2734
  if (secondIndex !== -1) {
2649
2735
  return {
2650
2736
  success: false,
@@ -2652,14 +2738,14 @@ var editFileTool = {
2652
2738
  error: "TEXT_MULTIPLE_MATCHES"
2653
2739
  };
2654
2740
  }
2655
- const newContent = content.replace(params.old_text, params.new_text);
2741
+ const newContent = content.replace(args.old_text, args.new_text);
2656
2742
  await writeFileWithEol(filePath, content, newContent);
2657
2743
  const diff = computeFileDiff(content, newContent, filePath);
2658
2744
  diff.existedBefore = true;
2659
2745
  const beforeText = content.slice(0, firstIndex);
2660
2746
  const startLine = beforeText.split("\n").length;
2661
- const oldLines = params.old_text.split("\n").length;
2662
- const newLines = params.new_text.split("\n").length;
2747
+ const oldLines = args.old_text.split("\n").length;
2748
+ const newLines = args.new_text.split("\n").length;
2663
2749
  const diffSummary = `+${diff.additions} -${diff.deletions}`;
2664
2750
  const summary = `\u{1F4DD} \u4FEE\u6539: ${basename2(filePath)} (+${diff.additions} -${diff.deletions})`;
2665
2751
  return {
@@ -2685,45 +2771,43 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
2685
2771
  // src/tool/builtins/multi-edit.ts
2686
2772
  import { readFile as readFile7 } from "fs/promises";
2687
2773
  import { basename as basename3 } from "path";
2688
- var multiEditSchema = {
2689
- type: "object",
2690
- properties: {
2691
- path: {
2692
- type: "string",
2693
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2694
- },
2695
- edits: {
2696
- type: "array",
2697
- description: "\u6709\u5E8F\u7684\u7F16\u8F91\u6B65\u9AA4\u5217\u8868\u3002\u6BCF\u4E2A\u6B65\u9AA4\u5305\u542B oldText\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3001newText\uFF08\u66FF\u6362\u5185\u5BB9\uFF09\u548C\u53EF\u9009\u7684 replaceAll\uFF08\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF09",
2698
- items: {
2699
- type: "object",
2700
- properties: {
2701
- oldText: { type: "string", description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09" },
2702
- newText: { type: "string", description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C" },
2703
- replaceAll: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF0C\u9ED8\u8BA4 false" }
2704
- },
2705
- required: ["oldText", "newText"],
2706
- additionalProperties: false
2707
- }
2708
- }
2709
- },
2710
- required: ["path", "edits"],
2711
- additionalProperties: false
2712
- };
2713
2774
  var multiEditTool = {
2714
2775
  name: "multi_edit",
2776
+ kind: "edit" /* Edit */,
2715
2777
  description: "\u5BF9\u6587\u4EF6\u8FDB\u884C\u539F\u5B50\u6279\u91CF\u66FF\u6362\u7F16\u8F91\u3002\u5728\u4E00\u4E2A\u8BF7\u6C42\u4E2D\u6267\u884C\u591A\u4E2A\u7CBE\u786E\u66FF\u6362\uFF0C\u4EFB\u4E00\u5931\u8D25\u5219\u5168\u90E8\u56DE\u6EDA\u3002\u652F\u6301 replaceAll \u53C2\u6570\u505A\u5168\u5C40\u66FF\u6362\u3002\u9002\u7528\u4E8E\u9700\u8981\u540C\u65F6\u4FEE\u6539\u6587\u4EF6\u591A\u5904\u7684\u573A\u666F\u3002",
2716
- parameters: multiEditSchema,
2717
- readOnly: false,
2778
+ parameters: {
2779
+ type: "object",
2780
+ properties: {
2781
+ path: {
2782
+ type: "string",
2783
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2784
+ },
2785
+ edits: {
2786
+ type: "array",
2787
+ description: "\u6709\u5E8F\u7684\u7F16\u8F91\u6B65\u9AA4\u5217\u8868\u3002\u6BCF\u4E2A\u6B65\u9AA4\u5305\u542B oldText\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3001newText\uFF08\u66FF\u6362\u5185\u5BB9\uFF09\u548C\u53EF\u9009\u7684 replaceAll\uFF08\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF09",
2788
+ items: {
2789
+ type: "object",
2790
+ properties: {
2791
+ oldText: { type: "string", description: "\u8981\u67E5\u627E\u7684\u539F\u59CB\u6587\u672C\uFF08\u7CBE\u786E\u5339\u914D\uFF09" },
2792
+ newText: { type: "string", description: "\u66FF\u6362\u540E\u7684\u65B0\u6587\u672C" },
2793
+ replaceAll: { type: "boolean", description: "\u662F\u5426\u66FF\u6362\u6240\u6709\u5339\u914D\u9879\uFF0C\u9ED8\u8BA4 false" }
2794
+ },
2795
+ required: ["oldText", "newText"],
2796
+ additionalProperties: false
2797
+ }
2798
+ }
2799
+ },
2800
+ required: ["path", "edits"],
2801
+ additionalProperties: false
2802
+ },
2718
2803
  async execute(args, ctx) {
2719
- const params = args;
2720
- if (!params?.path || typeof params.path !== "string") {
2804
+ if (!args?.path || typeof args.path !== "string") {
2721
2805
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2722
2806
  }
2723
- if (!Array.isArray(params.edits) || params.edits.length === 0) {
2807
+ if (!Array.isArray(args.edits) || args.edits.length === 0) {
2724
2808
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 edits\uFF08\u975E\u7A7A\u6570\u7EC4\uFF09", error: "INVALID_ARGS" };
2725
2809
  }
2726
- const filePath = resolvePath(params.path, ctx.cwd);
2810
+ const filePath = resolvePath(args.path, ctx.cwd);
2727
2811
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2728
2812
  const conf = await confine(ctx.writeRoots, filePath);
2729
2813
  if (!conf.ok) {
@@ -2733,8 +2817,8 @@ var multiEditTool = {
2733
2817
  try {
2734
2818
  const originalContent = await readFile7(filePath, "utf-8");
2735
2819
  let currentContent = originalContent;
2736
- for (let idx = 0; idx < params.edits.length; idx++) {
2737
- const step = params.edits[idx];
2820
+ for (let idx = 0; idx < args.edits.length; idx++) {
2821
+ const step = args.edits[idx];
2738
2822
  if (typeof step.oldText !== "string") {
2739
2823
  return {
2740
2824
  success: false,
@@ -2782,9 +2866,9 @@ var multiEditTool = {
2782
2866
  return {
2783
2867
  success: true,
2784
2868
  data: `\u6587\u4EF6\u5DF2\u7F16\u8F91\uFF1A${filePath}
2785
- \u5171\u6267\u884C ${params.edits.length} \u6B65\u66FF\u6362
2869
+ \u5171\u6267\u884C ${args.edits.length} \u6B65\u66FF\u6362
2786
2870
  \u53D8\u66F4\uFF1A+${diff.additions} -${diff.deletions}`,
2787
- summary: `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (${params.edits.length} \u6B65, +${diff.additions} -${diff.deletions})`,
2871
+ summary: `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (${args.edits.length} \u6B65, +${diff.additions} -${diff.deletions})`,
2788
2872
  diff
2789
2873
  };
2790
2874
  } catch (err) {
@@ -2801,29 +2885,6 @@ var multiEditTool = {
2801
2885
  // src/tool/builtins/delete-range.ts
2802
2886
  import { readFile as readFile8 } from "fs/promises";
2803
2887
  import { basename as basename4 } from "path";
2804
- var deleteRangeSchema = {
2805
- type: "object",
2806
- properties: {
2807
- path: {
2808
- type: "string",
2809
- description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2810
- },
2811
- startAnchor: {
2812
- type: "string",
2813
- description: "\u5220\u9664\u8303\u56F4\u7684\u8D77\u59CB\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF09"
2814
- },
2815
- endAnchor: {
2816
- type: "string",
2817
- description: "\u5220\u9664\u8303\u56F4\u7684\u7ED3\u675F\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF0C\u987B\u5728 start_anchor \u4E4B\u540E\uFF09"
2818
- },
2819
- inclusive: {
2820
- type: "boolean",
2821
- description: "\u662F\u5426\u5305\u542B\u951A\u70B9\u884C\u672C\u8EAB\uFF0C\u9ED8\u8BA4 false\uFF08\u53EA\u5220\u9664\u4E24\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\uFF09"
2822
- }
2823
- },
2824
- required: ["path", "startAnchor", "endAnchor"],
2825
- additionalProperties: false
2826
- };
2827
2888
  function findUniqueLine(lines, anchor, label) {
2828
2889
  const matches = [];
2829
2890
  for (let i = 0; i < lines.length; i++) {
@@ -2841,22 +2902,43 @@ function findUniqueLine(lines, anchor, label) {
2841
2902
  }
2842
2903
  var deleteRangeTool = {
2843
2904
  name: "delete_range",
2905
+ kind: "edit" /* Edit */,
2844
2906
  description: "\u5220\u9664\u6587\u4EF6\u4E2D\u4E24\u4E2A\u951A\u70B9\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\u3002\u901A\u8FC7\u4E24\u4E2A\u552F\u4E00\u7684\u884C\u5185\u5BB9\u7CBE\u786E\u5B9A\u4F4D\u8303\u56F4\u3002\u9002\u7528\u4E8E\u5220\u9664\u65B9\u6CD5\u3001\u4EE3\u7801\u5757\u3001\u914D\u7F6E\u6BB5\u7B49\u3002",
2845
- parameters: deleteRangeSchema,
2846
- readOnly: false,
2907
+ parameters: {
2908
+ type: "object",
2909
+ properties: {
2910
+ path: {
2911
+ type: "string",
2912
+ description: "\u6587\u4EF6\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09"
2913
+ },
2914
+ startAnchor: {
2915
+ type: "string",
2916
+ description: "\u5220\u9664\u8303\u56F4\u7684\u8D77\u59CB\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF09"
2917
+ },
2918
+ endAnchor: {
2919
+ type: "string",
2920
+ description: "\u5220\u9664\u8303\u56F4\u7684\u7ED3\u675F\u6807\u8BB0\u884C\u5185\u5BB9\uFF08\u5FC5\u987B\u5728\u6587\u4EF6\u4E2D\u552F\u4E00\uFF0C\u7CBE\u786E\u5339\u914D\u6574\u884C\uFF0C\u987B\u5728 start_anchor \u4E4B\u540E\uFF09"
2921
+ },
2922
+ inclusive: {
2923
+ type: "boolean",
2924
+ description: "\u662F\u5426\u5305\u542B\u951A\u70B9\u884C\u672C\u8EAB\uFF0C\u9ED8\u8BA4 false\uFF08\u53EA\u5220\u9664\u4E24\u884C\u4E4B\u95F4\u7684\u5185\u5BB9\uFF09"
2925
+ }
2926
+ },
2927
+ required: ["path", "startAnchor", "endAnchor"],
2928
+ additionalProperties: false
2929
+ },
2847
2930
  async execute(args, ctx) {
2848
- const params = args;
2849
- if (!params?.path || typeof params.path !== "string") {
2931
+ if (!args?.path || typeof args.path !== "string") {
2850
2932
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 path", error: "INVALID_ARGS" };
2851
2933
  }
2852
- if (typeof params.startAnchor !== "string") {
2934
+ if (typeof args.startAnchor !== "string") {
2853
2935
  return { success: false, data: "\u7F3A\u5C11\u6709\u6548\u53C2\u6570 startAnchor", error: "INVALID_ARGS" };
2854
2936
  }
2855
- if (typeof params.endAnchor !== "string") {
2937
+ if (typeof args.endAnchor !== "string") {
2856
2938
  return { success: false, data: "\u7F3A\u5C11\u6709\u6548\u53C2\u6570 endAnchor", error: "INVALID_ARGS" };
2857
2939
  }
2858
- const filePath = resolvePath(params.path, ctx.cwd);
2859
- const inclusive = params.inclusive ?? false;
2940
+ const filePath = resolvePath(args.path, ctx.cwd);
2941
+ const inclusive = args.inclusive ?? false;
2860
2942
  if (ctx.writeRoots && ctx.writeRoots.length > 0) {
2861
2943
  const conf = await confine(ctx.writeRoots, filePath);
2862
2944
  if (!conf.ok) {
@@ -2866,11 +2948,11 @@ var deleteRangeTool = {
2866
2948
  try {
2867
2949
  const content = await readFile8(filePath, "utf-8");
2868
2950
  const lines = content.split("\n");
2869
- const startResult = findUniqueLine(lines, params.startAnchor, "start_anchor");
2951
+ const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
2870
2952
  if ("error" in startResult) {
2871
2953
  return { success: false, data: startResult.error, error: "ANCHOR_NOT_FOUND" };
2872
2954
  }
2873
- const endResult = findUniqueLine(lines, params.endAnchor, "end_anchor");
2955
+ const endResult = findUniqueLine(lines, args.endAnchor, "end_anchor");
2874
2956
  if ("error" in endResult) {
2875
2957
  return { success: false, data: endResult.error, error: "ANCHOR_NOT_FOUND" };
2876
2958
  }
@@ -2921,36 +3003,33 @@ var deleteRangeTool = {
2921
3003
  // src/tool/builtins/bash.ts
2922
3004
  import process3 from "process";
2923
3005
  var isWindows2 = process3.platform === "win32";
2924
- var bashSchema = {
2925
- type: "object",
2926
- properties: {
2927
- command: {
2928
- type: "string",
2929
- description: "\u8981\u6267\u884C\u7684 shell \u547D\u4EE4"
2930
- },
2931
- timeout: {
2932
- type: "number",
2933
- description: "\u6267\u884C\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 30000"
2934
- }
2935
- },
2936
- required: ["command"],
2937
- additionalProperties: false
2938
- };
2939
3006
  var bashTool = {
2940
3007
  name: "bash",
3008
+ kind: "other" /* Other */,
2941
3009
  description: "\u5728 shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002\u8FD4\u56DE\u6807\u51C6\u8F93\u51FA\u3001\u6807\u51C6\u9519\u8BEF\u548C\u9000\u51FA\u7801\u3002\u652F\u6301\u8D85\u65F6\u63A7\u5236\u548C\u4FE1\u53F7\u4E2D\u6B62\u3002\u9002\u7528\u4E8E\u8FD0\u884C\u6784\u5EFA\u3001\u6D4B\u8BD5\u3001Git \u64CD\u4F5C\u7B49\u547D\u4EE4\u3002",
2942
- parameters: bashSchema,
2943
- readOnly: false,
2944
- // bash 有副作用,不能并行执行
3010
+ parameters: {
3011
+ type: "object",
3012
+ properties: {
3013
+ command: {
3014
+ type: "string",
3015
+ description: "\u8981\u6267\u884C\u7684 shell \u547D\u4EE4"
3016
+ },
3017
+ timeout: {
3018
+ type: "number",
3019
+ description: "\u6267\u884C\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09\uFF0C\u9ED8\u8BA4 30000"
3020
+ }
3021
+ },
3022
+ required: ["command"],
3023
+ additionalProperties: false
3024
+ },
2945
3025
  async execute(args, ctx) {
2946
- const params = args;
2947
- if (!params?.command || typeof params.command !== "string") {
3026
+ if (!args?.command || typeof args.command !== "string") {
2948
3027
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 command", error: "INVALID_ARGS" };
2949
3028
  }
2950
- const timeout = params.timeout ?? ctx.timeout ?? getDefaultTimeout();
3029
+ const timeout = args.timeout ?? ctx.timeout ?? getDefaultTimeout();
2951
3030
  try {
2952
3031
  const shellCommand = isWindows2 ? "cmd" : "sh";
2953
- const shellArgs = isWindows2 ? ["/c", params.command] : ["-c", params.command];
3032
+ const shellArgs = isWindows2 ? ["/c", args.command] : ["-c", args.command];
2954
3033
  const result = await execCommand(
2955
3034
  shellCommand,
2956
3035
  shellArgs,
@@ -2958,7 +3037,6 @@ var bashTool = {
2958
3037
  timeout,
2959
3038
  ctx.signal,
2960
3039
  true
2961
- // isShellCommand — 已指定 shell 程序,不需要二次包装
2962
3040
  );
2963
3041
  const parts = [];
2964
3042
  if (result.stdout) {
@@ -2970,7 +3048,7 @@ ${truncateOutput(result.stderr)}`);
2970
3048
  }
2971
3049
  const success = result.exitCode === 0;
2972
3050
  const output = parts.length > 0 ? parts.join("\n") : "(\u65E0\u8F93\u51FA)";
2973
- const cmdPreview = params.command.length > 60 ? params.command.slice(0, 57) + "..." : params.command;
3051
+ const cmdPreview = args.command.length > 60 ? args.command.slice(0, 57) + "..." : args.command;
2974
3052
  const summary = `\u{1F527} $ ${cmdPreview}\uFF08exit ${result.exitCode ?? "\u672A\u77E5"}\uFF09`;
2975
3053
  return {
2976
3054
  success,
@@ -2993,21 +3071,6 @@ ${truncateOutput(result.stderr)}`);
2993
3071
  // src/tool/builtins/glob.ts
2994
3072
  import { readdir as readdir2, stat as stat2 } from "fs/promises";
2995
3073
  import { join as join4, relative as relative4, isAbsolute as isAbsolute2 } from "path";
2996
- var globSchema = {
2997
- type: "object",
2998
- properties: {
2999
- pattern: {
3000
- type: "string",
3001
- description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u652F\u6301 * \u548C ** \u901A\u914D\u7B26\uFF0C\u5982 **/*.ts\u3001src/**/*.test.ts\uFF09"
3002
- },
3003
- directory: {
3004
- type: "string",
3005
- description: "\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3006
- }
3007
- },
3008
- required: ["pattern"],
3009
- additionalProperties: false
3010
- };
3011
3074
  function globToRegex(pattern) {
3012
3075
  let regexStr = pattern;
3013
3076
  regexStr = regexStr.replace(/\*\*\//g, "<<GLOBSTAR_SLASH>>");
@@ -3044,16 +3107,29 @@ async function walkDir(dir, baseDir) {
3044
3107
  }
3045
3108
  var globTool = {
3046
3109
  name: "glob",
3110
+ kind: "read" /* Read */,
3047
3111
  description: "\u6309\u6A21\u5F0F\u641C\u7D22\u6587\u4EF6\u8DEF\u5F84\u3002\u652F\u6301 *\uFF08\u5339\u914D\u6587\u4EF6\u540D\u90E8\u5206\uFF09\u548C **\uFF08\u5339\u914D\u591A\u5C42\u76EE\u5F55\uFF09\u901A\u914D\u7B26\u3002\u81EA\u52A8\u8DF3\u8FC7 node_modules \u548C .git \u76EE\u5F55\u3002",
3048
- parameters: globSchema,
3049
- readOnly: true,
3112
+ parameters: {
3113
+ type: "object",
3114
+ properties: {
3115
+ pattern: {
3116
+ type: "string",
3117
+ description: "\u641C\u7D22\u6A21\u5F0F\uFF08\u652F\u6301 * \u548C ** \u901A\u914D\u7B26\uFF0C\u5982 **/*.ts\u3001src/**/*.test.ts\uFF09"
3118
+ },
3119
+ directory: {
3120
+ type: "string",
3121
+ description: "\u641C\u7D22\u7684\u8D77\u59CB\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3122
+ }
3123
+ },
3124
+ required: ["pattern"],
3125
+ additionalProperties: false
3126
+ },
3050
3127
  async execute(args, ctx) {
3051
- const params = args;
3052
- if (!params?.pattern || typeof params.pattern !== "string") {
3128
+ if (!args?.pattern || typeof args.pattern !== "string") {
3053
3129
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
3054
3130
  }
3055
- const searchDir = params.directory ? isAbsolute2(params.directory) ? params.directory : join4(ctx.cwd, params.directory) : ctx.cwd;
3056
- const regex = globToRegex(params.pattern);
3131
+ const searchDir = args.directory ? isAbsolute2(args.directory) ? args.directory : join4(ctx.cwd, args.directory) : ctx.cwd;
3132
+ const regex = globToRegex(args.pattern);
3057
3133
  try {
3058
3134
  const dirStat = await stat2(searchDir);
3059
3135
  if (!dirStat.isDirectory()) {
@@ -3064,8 +3140,8 @@ var globTool = {
3064
3140
  if (matched.length === 0) {
3065
3141
  return {
3066
3142
  success: true,
3067
- data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u6587\u4EF6`,
3068
- summary: `${params.pattern} \u2192 0 \u4E2A\u6587\u4EF6`
3143
+ data: `\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u6587\u4EF6`,
3144
+ summary: `${args.pattern} \u2192 0 \u4E2A\u6587\u4EF6`
3069
3145
  };
3070
3146
  }
3071
3147
  const limit = 200;
@@ -3077,7 +3153,7 @@ var globTool = {
3077
3153
  return {
3078
3154
  success: true,
3079
3155
  data: truncateOutput(output + suffix),
3080
- summary: `${params.pattern} \u2192 ${matched.length} \u4E2A\u6587\u4EF6`
3156
+ summary: `${args.pattern} \u2192 ${matched.length} \u4E2A\u6587\u4EF6`
3081
3157
  };
3082
3158
  } catch (err) {
3083
3159
  const message = err instanceof Error ? err.message : String(err);
@@ -3093,33 +3169,6 @@ var globTool = {
3093
3169
  // src/tool/builtins/grep.ts
3094
3170
  import { readdir as readdir3, readFile as readFile9, stat as stat3 } from "fs/promises";
3095
3171
  import { join as join5, relative as relative5, isAbsolute as isAbsolute3 } from "path";
3096
- var grepSchema = {
3097
- type: "object",
3098
- properties: {
3099
- pattern: {
3100
- type: "string",
3101
- description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u641C\u7D22\u6A21\u5F0F"
3102
- },
3103
- directory: {
3104
- type: "string",
3105
- description: "\u641C\u7D22\u7684\u76EE\u5F55\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3106
- },
3107
- include: {
3108
- type: "string",
3109
- description: "\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\uFF08\u5982 ts\u3001json\uFF09\uFF0C\u4E0D\u542B\u70B9\u53F7"
3110
- },
3111
- case_sensitive: {
3112
- type: "boolean",
3113
- description: "\u662F\u5426\u5927\u5C0F\u5199\u654F\u611F\uFF0C\u9ED8\u8BA4 false"
3114
- },
3115
- max_files: {
3116
- type: "number",
3117
- description: "\u6700\u5927\u641C\u7D22\u6587\u4EF6\u6570\uFF0C\u9ED8\u8BA4 200"
3118
- }
3119
- },
3120
- required: ["pattern"],
3121
- additionalProperties: false
3122
- };
3123
3172
  async function collectFiles(dir, baseDir, extension, maxFiles = 200) {
3124
3173
  const results = [];
3125
3174
  let entries;
@@ -3147,24 +3196,49 @@ async function collectFiles(dir, baseDir, extension, maxFiles = 200) {
3147
3196
  }
3148
3197
  var grepTool = {
3149
3198
  name: "grep",
3199
+ kind: "read" /* Read */,
3150
3200
  description: "\u5728\u6587\u4EF6\u5185\u5BB9\u4E2D\u641C\u7D22\u6B63\u5219\u8868\u8FBE\u5F0F\u3002\u8FD4\u56DE\u5339\u914D\u884C\u7684\u6587\u4EF6\u8DEF\u5F84\u3001\u884C\u53F7\u548C\u5185\u5BB9\u3002\u652F\u6301\u5927\u5C0F\u5199\u654F\u611F\u3001\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\u3002",
3151
- parameters: grepSchema,
3152
- readOnly: true,
3201
+ parameters: {
3202
+ type: "object",
3203
+ properties: {
3204
+ pattern: {
3205
+ type: "string",
3206
+ description: "\u6B63\u5219\u8868\u8FBE\u5F0F\u641C\u7D22\u6A21\u5F0F"
3207
+ },
3208
+ directory: {
3209
+ type: "string",
3210
+ description: "\u641C\u7D22\u7684\u76EE\u5F55\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55"
3211
+ },
3212
+ include: {
3213
+ type: "string",
3214
+ description: "\u6587\u4EF6\u6269\u5C55\u540D\u8FC7\u6EE4\uFF08\u5982 ts\u3001json\uFF09\uFF0C\u4E0D\u542B\u70B9\u53F7"
3215
+ },
3216
+ case_sensitive: {
3217
+ type: "boolean",
3218
+ description: "\u662F\u5426\u5927\u5C0F\u5199\u654F\u611F\uFF0C\u9ED8\u8BA4 false"
3219
+ },
3220
+ max_files: {
3221
+ type: "number",
3222
+ description: "\u6700\u5927\u641C\u7D22\u6587\u4EF6\u6570\uFF0C\u9ED8\u8BA4 200"
3223
+ }
3224
+ },
3225
+ required: ["pattern"],
3226
+ additionalProperties: false
3227
+ },
3153
3228
  async execute(args, ctx) {
3154
- const params = args;
3155
- if (!params?.pattern || typeof params.pattern !== "string") {
3229
+ if (!args?.pattern || typeof args.pattern !== "string") {
3156
3230
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
3157
3231
  }
3158
- const searchDir = params.directory ? isAbsolute3(params.directory) ? params.directory : join5(ctx.cwd, params.directory) : ctx.cwd;
3159
- const maxFiles = params.max_files ?? 200;
3232
+ const searchDir = args.directory ? isAbsolute3(args.directory) ? args.directory : join5(ctx.cwd, args.directory) : ctx.cwd;
3233
+ const maxFiles = args.max_files ?? 200;
3160
3234
  try {
3161
- const flags = params.case_sensitive ? "g" : "gi";
3162
- const regex = new RegExp(params.pattern, flags);
3235
+ const flags = args.case_sensitive ? "g" : "gi";
3236
+ const regex = new RegExp(args.pattern, flags);
3163
3237
  const dirStat = await stat3(searchDir);
3164
3238
  if (!dirStat.isDirectory()) {
3165
3239
  return { success: false, data: `\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${searchDir}`, error: "NOT_DIRECTORY" };
3166
3240
  }
3167
- const files = await collectFiles(searchDir, searchDir, params.include, maxFiles);
3241
+ const files = await collectFiles(searchDir, searchDir, args.include, maxFiles);
3168
3242
  const matches = [];
3169
3243
  for (const filePath of files) {
3170
3244
  try {
@@ -3190,13 +3264,13 @@ var grepTool = {
3190
3264
  if (matches.length === 0) {
3191
3265
  return {
3192
3266
  success: true,
3193
- data: `\u672A\u627E\u5230\u5339\u914D "${params.pattern}" \u7684\u5185\u5BB9`,
3194
- summary: `\u{1F50D} "${params.pattern}" \u2192 0 \u6761\u547D\u4E2D`
3267
+ data: `\u672A\u627E\u5230\u5339\u914D "${args.pattern}" \u7684\u5185\u5BB9`,
3268
+ summary: `\u{1F50D} "${args.pattern}" \u2192 0 \u6761\u547D\u4E2D`
3195
3269
  };
3196
3270
  }
3197
3271
  const output = matches.map((m) => `${m.file}:${m.line}: ${m.content}`).join("\n");
3198
3272
  const fileSet = new Set(matches.map((m) => m.file));
3199
- const summary = `\u{1F50D} "${params.pattern}" \u2192 ${matches.length} \u6761\u547D\u4E2D / ${fileSet.size} \u4E2A\u6587\u4EF6`;
3273
+ const summary = `\u{1F50D} "${args.pattern}" \u2192 ${matches.length} \u6761\u547D\u4E2D / ${fileSet.size} \u4E2A\u6587\u4EF6`;
3200
3274
  return {
3201
3275
  success: true,
3202
3276
  data: truncateOutput(output),
@@ -3216,30 +3290,28 @@ var grepTool = {
3216
3290
  // src/tool/builtins/ls.ts
3217
3291
  import { readdir as readdir4, stat as stat4 } from "fs/promises";
3218
3292
  import { join as join6, relative as relative6 } from "path";
3219
- var lsSchema = {
3220
- type: "object",
3221
- properties: {
3222
- path: {
3223
- type: "string",
3224
- description: "\u76EE\u5F55\u8DEF\u5F84\uFF08\u76F8\u5BF9\u4E8E\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55"
3225
- },
3226
- all: {
3227
- type: "boolean",
3228
- description: "\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\uFF08\u4EE5 . \u5F00\u5934\u7684\u6587\u4EF6\uFF09\uFF0C\u9ED8\u8BA4 false"
3229
- }
3230
- },
3231
- required: [],
3232
- additionalProperties: false
3233
- };
3234
3293
  var lsTool = {
3235
3294
  name: "ls",
3295
+ kind: "read" /* Read */,
3236
3296
  description: "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9\u3002\u663E\u793A\u6761\u76EE\u7C7B\u578B\uFF08\u6587\u4EF6/\u76EE\u5F55/\u94FE\u63A5\uFF09\u548C\u5927\u5C0F\u3002\u53EF\u9009\u62E9\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\u3002",
3237
- parameters: lsSchema,
3238
- readOnly: true,
3297
+ parameters: {
3298
+ type: "object",
3299
+ properties: {
3300
+ path: {
3301
+ type: "string",
3302
+ 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"
3303
+ },
3304
+ all: {
3305
+ type: "boolean",
3306
+ description: "\u662F\u5426\u663E\u793A\u9690\u85CF\u6587\u4EF6\uFF08\u4EE5 . \u5F00\u5934\u7684\u6587\u4EF6\uFF09\uFF0C\u9ED8\u8BA4 false"
3307
+ }
3308
+ },
3309
+ required: [],
3310
+ additionalProperties: false
3311
+ },
3239
3312
  async execute(args, ctx) {
3240
- const params = args ?? {};
3241
- const dirPath = params.path ? resolvePath(params.path, ctx.cwd) : ctx.cwd;
3242
- const showAll = params.all ?? false;
3313
+ const dirPath = args.path ? resolvePath(args.path, ctx.cwd) : ctx.cwd;
3314
+ const showAll = args.all ?? false;
3243
3315
  try {
3244
3316
  const entries = await readdir4(dirPath, { withFileTypes: true });
3245
3317
  const lines = [];
@@ -3292,58 +3364,56 @@ ${lines.join("\n")}`),
3292
3364
  };
3293
3365
 
3294
3366
  // src/tool/builtins/fetch.ts
3295
- var fetchSchema = {
3296
- type: "object",
3297
- properties: {
3298
- url: {
3299
- type: "string",
3300
- description: "\u8BF7\u6C42\u7684 URL"
3301
- },
3302
- method: {
3303
- type: "string",
3304
- description: "HTTP \u65B9\u6CD5\uFF08GET\u3001POST\u3001PUT\u3001DELETE \u7B49\uFF09\uFF0C\u9ED8\u8BA4 GET"
3305
- },
3306
- headers: {
3307
- type: "object",
3308
- description: "\u8BF7\u6C42\u5934\u952E\u503C\u5BF9",
3309
- additionalProperties: { type: "string" }
3310
- },
3311
- body: {
3312
- type: "string",
3313
- description: "\u8BF7\u6C42\u4F53\u5185\u5BB9\uFF08POST/PUT \u65F6\u4F7F\u7528\uFF09"
3314
- },
3315
- max_length: {
3316
- type: "number",
3317
- description: "\u54CD\u5E94\u5185\u5BB9\u6700\u5927\u957F\u5EA6\uFF08\u5B57\u7B26\uFF09\uFF0C\u9ED8\u8BA4 50000"
3318
- }
3319
- },
3320
- required: ["url"],
3321
- additionalProperties: false
3322
- };
3323
3367
  var fetchTool = {
3324
3368
  name: "fetch",
3369
+ kind: "read" /* Read */,
3325
3370
  description: "\u53D1\u8D77 HTTP \u8BF7\u6C42\u5E76\u8FD4\u56DE\u54CD\u5E94\u5185\u5BB9\u3002\u652F\u6301\u81EA\u5B9A\u4E49\u65B9\u6CD5\u548C\u8BF7\u6C42\u5934\u3002\u9002\u7528\u4E8E\u83B7\u53D6\u7F51\u9875\u5185\u5BB9\u3001API \u8C03\u7528\u7B49\u573A\u666F\u3002",
3326
- parameters: fetchSchema,
3327
- readOnly: true,
3371
+ parameters: {
3372
+ type: "object",
3373
+ properties: {
3374
+ url: {
3375
+ type: "string",
3376
+ description: "\u8BF7\u6C42\u7684 URL"
3377
+ },
3378
+ method: {
3379
+ type: "string",
3380
+ description: "HTTP \u65B9\u6CD5\uFF08GET\u3001POST\u3001PUT\u3001DELETE \u7B49\uFF09\uFF0C\u9ED8\u8BA4 GET"
3381
+ },
3382
+ headers: {
3383
+ type: "object",
3384
+ description: "\u8BF7\u6C42\u5934\u952E\u503C\u5BF9",
3385
+ additionalProperties: { type: "string" }
3386
+ },
3387
+ body: {
3388
+ type: "string",
3389
+ description: "\u8BF7\u6C42\u4F53\u5185\u5BB9\uFF08POST/PUT \u65F6\u4F7F\u7528\uFF09"
3390
+ },
3391
+ max_length: {
3392
+ type: "number",
3393
+ description: "\u54CD\u5E94\u5185\u5BB9\u6700\u5927\u957F\u5EA6\uFF08\u5B57\u7B26\uFF09\uFF0C\u9ED8\u8BA4 50000"
3394
+ }
3395
+ },
3396
+ required: ["url"],
3397
+ additionalProperties: false
3398
+ },
3328
3399
  async execute(args, ctx) {
3329
- const params = args;
3330
- if (!params?.url || typeof params.url !== "string") {
3400
+ if (!args?.url || typeof args.url !== "string") {
3331
3401
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 url", error: "INVALID_ARGS" };
3332
3402
  }
3333
- const method = (params.method ?? "GET").toUpperCase();
3403
+ const method = (args.method ?? "GET").toUpperCase();
3334
3404
  const timeout = 3e4;
3335
- const maxLength = params.max_length ?? 5e4;
3405
+ const maxLength = args.max_length ?? 5e4;
3336
3406
  try {
3337
3407
  const fetchOptions = {
3338
3408
  method,
3339
- headers: params.headers ?? {},
3409
+ headers: args.headers ?? {},
3340
3410
  signal: ctx.signal ?? AbortSignal.timeout(timeout)
3341
3411
  };
3342
- if (params.body && (method === "POST" || method === "PUT" || method === "PATCH")) {
3412
+ if (args.body && (method === "POST" || method === "PUT" || method === "PATCH")) {
3343
3413
  fetchOptions.headers["Content-Type"] ??= "application/json";
3344
- fetchOptions.body = params.body;
3414
+ fetchOptions.body = args.body;
3345
3415
  }
3346
- const response = await fetch(params.url, fetchOptions);
3416
+ const response = await fetch(args.url, fetchOptions);
3347
3417
  const contentType = response.headers.get("content-type") ?? "unknown";
3348
3418
  const statusText = `${response.status} ${response.statusText}`;
3349
3419
  let body;
@@ -3356,7 +3426,7 @@ var fetchTool = {
3356
3426
  const header = `\u72B6\u6001: ${statusText}
3357
3427
  \u5185\u5BB9\u7C7B\u578B: ${contentType}`;
3358
3428
  const separator = body.length > 0 ? "\n---\n" : "";
3359
- const urlPreview = params.url.length > 60 ? params.url.slice(0, 57) + "..." : params.url;
3429
+ const urlPreview = args.url.length > 60 ? args.url.slice(0, 57) + "..." : args.url;
3360
3430
  const summary = `\u{1F310} ${method} ${urlPreview} \u2192 ${response.status}`;
3361
3431
  return {
3362
3432
  success: response.ok,
@@ -3383,16 +3453,16 @@ var fetchTool = {
3383
3453
 
3384
3454
  // src/tool/builtins/index.ts
3385
3455
  var builtinTools = [
3386
- readFileTool,
3387
- writeFileTool,
3388
- editFileTool,
3389
- multiEditTool,
3390
- deleteRangeTool,
3391
- bashTool,
3392
- globTool,
3393
- grepTool,
3394
- lsTool,
3395
- fetchTool
3456
+ eraseTool(readFileTool),
3457
+ eraseTool(writeFileTool),
3458
+ eraseTool(editFileTool),
3459
+ eraseTool(multiEditTool),
3460
+ eraseTool(deleteRangeTool),
3461
+ eraseTool(bashTool),
3462
+ eraseTool(globTool),
3463
+ eraseTool(grepTool),
3464
+ eraseTool(lsTool),
3465
+ eraseTool(fetchTool)
3396
3466
  ];
3397
3467
 
3398
3468
  // src/utils/gradient.ts
@@ -3483,6 +3553,8 @@ registerCommand("/help", {
3483
3553
  registerCommand("/clear", { desc: "\u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", handler: () => ({ kind: "clear" }) });
3484
3554
  registerCommand("/version", { desc: "\u663E\u793A\u7248\u672C\u4FE1\u606F", handler: () => ({ kind: "text", content: "dskcode v0.1.10" }) });
3485
3555
  registerCommand("/model", { desc: "\u5207\u6362\u6A21\u578B", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /model \u8FDB\u5165\u9009\u62E9\u754C\u9762" }) });
3556
+ registerCommand("/thinking", { desc: "\u5207\u6362\u6DF1\u5EA6\u601D\u8003\u6A21\u5F0F", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /thinking \u5207\u6362" }) });
3557
+ registerCommand("/effort", { desc: "\u5207\u6362\u63A8\u7406\u7B49\u7EA7 High/Max", handler: () => ({ kind: "text", content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /effort \u5207\u6362" }) });
3486
3558
  registerCommand("/game", { desc: "\u542F\u52A8\u6E38\u620F", handler: () => ({ kind: "navigate", target: "game" }) });
3487
3559
  registerCommand("/stock", { desc: "\u67E5\u770B\u80A1\u7968\u884C\u60C5", handler: () => ({ kind: "navigate", target: "stock" }) });
3488
3560
  var STREAMING_PLACEHOLDERS = [
@@ -3541,6 +3613,19 @@ function ChatSession({
3541
3613
  const [activeModel, setActiveModel] = useState3(model);
3542
3614
  const [streamingModel, setStreamingModel] = useState3(void 0);
3543
3615
  const [streamError, setStreamError] = useState3(void 0);
3616
+ const [thinkingEnabled, setThinkingEnabled] = useState3(true);
3617
+ const [thinkingEffort, setThinkingEffort] = useState3("high");
3618
+ const [responseFormat, setResponseFormat] = useState3("text");
3619
+ const [toolChoice, setToolChoice] = useState3(void 0);
3620
+ const sessionCost = useMemo(() => {
3621
+ return displayMessages.reduce((sum, msg) => {
3622
+ if (msg.assistantDetail?.cost) {
3623
+ return sum + msg.assistantDetail.cost;
3624
+ }
3625
+ return sum;
3626
+ }, 0);
3627
+ }, [displayMessages]);
3628
+ const hasConversationStarted = displayMessages.length > 0;
3544
3629
  const cmdTips = Array.from(getRegisteredCommands()).filter(([name]) => name !== "/exit" && name !== "/quit").map(([name, cmd]) => ({ name, desc: cmd.desc }));
3545
3630
  const [cmdTipIndex, setCmdTipIndex] = useState3(0);
3546
3631
  const [cmdTipGradientColors, setCmdTipGradientColors] = useState3([]);
@@ -3672,6 +3757,11 @@ function ChatSession({
3672
3757
  return;
3673
3758
  }
3674
3759
  }
3760
+ if (selectingModel) {
3761
+ if (key.upArrow || key.downArrow) {
3762
+ }
3763
+ return;
3764
+ }
3675
3765
  if (key.ctrl && _input === "c") {
3676
3766
  if (isStreaming) {
3677
3767
  abortRef.current?.abort();
@@ -3691,7 +3781,7 @@ function ChatSession({
3691
3781
  if (cmdTips.length <= 1) return;
3692
3782
  const timer = setInterval(() => {
3693
3783
  setCmdTipIndex((prev) => (prev + 1) % cmdTips.length);
3694
- }, 5e3);
3784
+ }, 2e3);
3695
3785
  return () => clearInterval(timer);
3696
3786
  }, [cmdTips.length]);
3697
3787
  useEffect3(() => {
@@ -3738,7 +3828,7 @@ function ChatSession({
3738
3828
  if (!apiKey || !baseUrl) return;
3739
3829
  let cancelled = false;
3740
3830
  setBalanceLoading(true);
3741
- import("./deepseek-UJXV2D6K.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
3831
+ import("./deepseek-YTT76XDE.js").then(({ DeepSeekProvider: DeepSeekProvider2 }) => {
3742
3832
  const provider = new DeepSeekProvider2({
3743
3833
  apiKey,
3744
3834
  baseUrl,
@@ -3807,14 +3897,48 @@ function ChatSession({
3807
3897
  const trimmed = value.trim();
3808
3898
  if (!trimmed) return;
3809
3899
  if (trimmed.startsWith("/") && trimmed.length > 1) {
3810
- if (trimmed.toLowerCase() === "/model") {
3900
+ const cmdLower = trimmed.toLowerCase();
3901
+ if (cmdLower === "/model") {
3811
3902
  const curIdx = modelOptions.indexOf(activeModel);
3812
3903
  setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
3813
3904
  setSelectingModel(true);
3814
3905
  setInput("");
3815
3906
  return;
3816
3907
  }
3817
- const cmd = commandRegistry.get(trimmed.toLowerCase());
3908
+ if (cmdLower === "/thinking") {
3909
+ setThinkingEnabled((prev) => !prev);
3910
+ setDisplayMessages((prev) => [
3911
+ ...prev,
3912
+ { role: "user", content: trimmed },
3913
+ { role: "assistant", content: `\u6DF1\u5EA6\u601D\u8003\u5DF2${thinkingEnabled ? "\u5173\u95ED" : "\u5F00\u542F"}` }
3914
+ ]);
3915
+ setInput("");
3916
+ return;
3917
+ }
3918
+ if (cmdLower === "/effort") {
3919
+ const next = thinkingEffort === "high" ? "max" : "high";
3920
+ setThinkingEffort(next);
3921
+ setDisplayMessages((prev) => [
3922
+ ...prev,
3923
+ { role: "user", content: trimmed },
3924
+ { role: "assistant", content: `\u63A8\u7406\u7B49\u7EA7\u5DF2\u5207\u6362\u4E3A ${next === "high" ? "High" : "Max"}` }
3925
+ ]);
3926
+ setInput("");
3927
+ return;
3928
+ }
3929
+ if (cmdLower === "/tools") {
3930
+ const next = toolChoice === void 0 ? "none" : toolChoice === "none" ? "required" : toolChoice === "required" ? "auto" : void 0;
3931
+ setToolChoice(next);
3932
+ const label = next === void 0 ? "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09" : next === "none" ? "\u7981\u6B62\u8C03\u7528" : next === "required" ? "\u5F3A\u5236\u8C03\u7528" : "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09";
3933
+ setDisplayMessages((prev) => [
3934
+ ...prev,
3935
+ { role: "user", content: trimmed },
3936
+ { role: "assistant", content: `\u5DE5\u5177\u8C03\u7528\u7B56\u7565\u5DF2\u5207\u6362\u4E3A ${label}` }
3937
+ ]);
3938
+ setInput("");
3939
+ return;
3940
+ }
3941
+ const cmd = commandRegistry.get(cmdLower);
3818
3942
  if (cmd) {
3819
3943
  const result = cmd.handler();
3820
3944
  switch (result.kind) {
@@ -3889,7 +4013,12 @@ function ChatSession({
3889
4013
  const abortController = new AbortController();
3890
4014
  abortRef.current = abortController;
3891
4015
  try {
3892
- for await (const event of session.chat(trimmed)) {
4016
+ for await (const event of session.chat(trimmed, {
4017
+ thinkingAllowed: thinkingEnabled || void 0,
4018
+ thinkingEffort: thinkingEnabled ? thinkingEffort : void 0,
4019
+ responseFormat: responseFormat !== "text" ? responseFormat : void 0,
4020
+ toolChoice
4021
+ })) {
3893
4022
  if (abortController.signal.aborted) break;
3894
4023
  switch (event.type) {
3895
4024
  case "text_delta":
@@ -3927,6 +4056,11 @@ function ChatSession({
3927
4056
  setStreamingModel(event.model);
3928
4057
  currentUsageRef.current = event.usage;
3929
4058
  currentModelRef.current = event.model;
4059
+ {
4060
+ const cost = calculateCost(event.usage, event.model);
4061
+ setCurrentCost(cost.totalCost);
4062
+ currentCostRef.current = cost.totalCost;
4063
+ }
3930
4064
  break;
3931
4065
  case "done":
3932
4066
  setCurrentElapsed(event.elapsed);
@@ -3968,23 +4102,14 @@ function ChatSession({
3968
4102
  ]);
3969
4103
  }
3970
4104
  }
3971
- }, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills]);
4105
+ }, [onLaunchGame, onLaunchStock, currentContent, currentToolCalls, skills, skillSelectIndex, getFilteredSkills, thinkingEnabled, thinkingEffort, responseFormat, toolChoice, activeModel]);
3972
4106
  useEffect3(() => {
3973
4107
  if (!isStreaming && externalCostTracker) {
3974
4108
  setTodayCost(externalCostTracker.todayTotalCost);
3975
4109
  }
3976
4110
  }, [isStreaming, externalCostTracker]);
3977
- useEffect3(() => {
3978
- if (currentUsage && streamingModel && !currentCost) {
3979
- import("./models-OL7DHYGK.js").then(({ calculateCost: calculateCost2 }) => {
3980
- const cost = calculateCost2(currentUsage, streamingModel);
3981
- setCurrentCost(cost.totalCost);
3982
- currentCostRef.current = cost.totalCost;
3983
- });
3984
- }
3985
- }, [currentUsage, streamingModel, currentCost]);
3986
4111
  return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
3987
- /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginBottom: 1, children: [
4112
+ !hasConversationStarted && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", marginBottom: 1, children: [
3988
4113
  /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
3989
4114
  const colorIndex = (i + offset) % CYBER_PALETTE.length;
3990
4115
  return /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
@@ -4006,6 +4131,15 @@ function ChatSession({
4006
4131
  " \u{1F527} \u6A21\u578B ",
4007
4132
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
4008
4133
  ] }),
4134
+ thinkingEnabled && /* @__PURE__ */ jsxs8(Text9, { color: "#ff9800", children: [
4135
+ " \u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
4136
+ thinkingEffort === "max" ? "Max" : "High"
4137
+ ] }),
4138
+ responseFormat === "json_object" && /* @__PURE__ */ jsx8(Text9, { color: "#4caf50", children: " \u{1F4C4} JSON" }),
4139
+ toolChoice !== void 0 && /* @__PURE__ */ jsxs8(Text9, { color: "#e91e63", children: [
4140
+ " \u{1F6E0} ",
4141
+ toolChoice === "none" ? "\u7981\u6B62\u5DE5\u5177" : toolChoice === "required" ? "\u5F3A\u5236\u5DE5\u5177" : ""
4142
+ ] }),
4009
4143
  cmdTips.length > 0 && (() => {
4010
4144
  const tip = cmdTips[cmdTipIndex % cmdTips.length];
4011
4145
  if (!tip) return null;
@@ -4113,7 +4247,21 @@ function ChatSession({
4113
4247
  ] }),
4114
4248
  /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) })
4115
4249
  ] }) : /* @__PURE__ */ jsxs8(Fragment, { children: [
4116
- /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4250
+ /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: hasConversationStarted && (balance !== null || sessionCost > 0 || isStreaming) ? /* @__PURE__ */ jsxs8(Text9, { color: "#00ffff", dimColor: true, children: [
4251
+ "\u2500".repeat(Math.max(dividerWidth - 35, 10)),
4252
+ balance !== null && /* @__PURE__ */ jsxs8(Text9, { color: "yellow", children: [
4253
+ " \u{1F4B0} \u4F59\u989D \xA5",
4254
+ balance.toFixed(2)
4255
+ ] }),
4256
+ isStreaming ? /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
4257
+ " \u{1F4CA} \u672C\u6B21 \xA5",
4258
+ sessionCost > 0 ? sessionCost.toFixed(4) + " " : "",
4259
+ /* @__PURE__ */ jsx8(InkSpinner2, { type: "dots" })
4260
+ ] }) : sessionCost > 0 ? /* @__PURE__ */ jsxs8(Text9, { color: "cyan", children: [
4261
+ " \u{1F4CA} \u672C\u6B21 \xA5",
4262
+ sessionCost.toFixed(4)
4263
+ ] }) : null
4264
+ ] }) : /* @__PURE__ */ jsx8(Text9, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }) }),
4117
4265
  /* @__PURE__ */ jsxs8(Box8, { children: [
4118
4266
  /* @__PURE__ */ jsx8(Box8, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx8(Text9, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
4119
4267
  /* @__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(