dskcode 0.1.31 → 0.1.34

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
@@ -1175,7 +1175,7 @@ function formatArgsSummary(args) {
1175
1175
  return ` ${truncated}`;
1176
1176
  }
1177
1177
  }
1178
- function ToolCallBlock({ call, showPendingHint = true }) {
1178
+ function ToolCallBlock({ call }) {
1179
1179
  const argsDisplay = formatArgsSummary(call.arguments);
1180
1180
  return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: [
1181
1181
  /* @__PURE__ */ jsxs3(Box3, { children: [
@@ -1188,8 +1188,7 @@ function ToolCallBlock({ call, showPendingHint = true }) {
1188
1188
  "\u2500".repeat(Math.max(1, 30 - call.name.length))
1189
1189
  ] })
1190
1190
  ] }),
1191
- /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay }) }),
1192
- showPendingHint && /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: "\u23F3 \u7B49\u5F85\u6267\u884C" }) })
1191
+ /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: /* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay }) })
1193
1192
  ] });
1194
1193
  }
1195
1194
 
@@ -2099,6 +2098,79 @@ function TodoListPanel({ items }) {
2099
2098
  ] });
2100
2099
  }
2101
2100
 
2101
+ // package.json
2102
+ var package_default = {
2103
+ name: "dskcode",
2104
+ version: "0.1.34",
2105
+ repository: {
2106
+ type: "git",
2107
+ url: "git+https://github.com/Awu12277/deepseek-agent-cli/tree/main"
2108
+ },
2109
+ keywords: [
2110
+ "cli",
2111
+ "ink",
2112
+ "commander",
2113
+ "deepseek",
2114
+ "asciichart"
2115
+ ],
2116
+ description: "A DeepSeek-native AI coding agent for your terminal",
2117
+ type: "module",
2118
+ bin: {
2119
+ dskcode: "dist/index.js"
2120
+ },
2121
+ exports: {
2122
+ ".": {
2123
+ import: "./dist/index.js",
2124
+ types: "./dist/index.d.ts"
2125
+ }
2126
+ },
2127
+ files: [
2128
+ "dist",
2129
+ "README.md",
2130
+ "LICENSE"
2131
+ ],
2132
+ scripts: {
2133
+ dev: "tsup --watch",
2134
+ build: "tsup",
2135
+ "type-check": "tsc --noEmit",
2136
+ lint: "oxlint src/ tests/",
2137
+ "lint:fix": "oxlint --fix src/ tests/",
2138
+ format: "prettier --write src/ tests/",
2139
+ "format:check": "prettier --check src/ tests/",
2140
+ test: "vitest run",
2141
+ "test:watch": "vitest",
2142
+ "test:coverage": "vitest run --coverage",
2143
+ prepublishOnly: "npm run build && npm run test"
2144
+ },
2145
+ dependencies: {
2146
+ asciichart: "^1.5.25",
2147
+ chalk: "^5.6.2",
2148
+ commander: "^13.1.0",
2149
+ handlebars: "^4.7.9",
2150
+ ink: "^7.1.0",
2151
+ "ink-spinner": "^5.0.0",
2152
+ "ink-text-input": "^6.0.0",
2153
+ react: "^19.2.7"
2154
+ },
2155
+ devDependencies: {
2156
+ "@types/node": "^22.14.0",
2157
+ "@types/react": "^19.2.17",
2158
+ oxlint: "^1.71.0",
2159
+ "oxlint-tsgolint": "^0.23.0",
2160
+ prettier: "^3.5.3",
2161
+ tsup: "^8.4.0",
2162
+ typescript: "^5.8.3",
2163
+ vitest: "^3.1.1"
2164
+ },
2165
+ engines: {
2166
+ node: ">=22.0.0"
2167
+ },
2168
+ license: "MIT"
2169
+ };
2170
+
2171
+ // src/utils/version.ts
2172
+ var VERSION = package_default.version;
2173
+
2102
2174
  // src/provider/registry.ts
2103
2175
  var ProviderRegistry = class {
2104
2176
  #factories = /* @__PURE__ */ new Map();
@@ -2658,7 +2730,7 @@ var Reflector = class {
2658
2730
  const reflections = [];
2659
2731
  for (const item of items) {
2660
2732
  if (item.result.success) continue;
2661
- const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
2733
+ const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#ruleTextNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
2662
2734
  if (r) reflections.push(r);
2663
2735
  if (reflections.length >= this.#maxReflections) break;
2664
2736
  }
@@ -2734,6 +2806,26 @@ var Reflector = class {
2734
2806
  hint: `\`${item.name}\` \u5931\u8D25\uFF1A\u6587\u4EF6\u4E0D\u5B58\u5728\u3002\u8BF7\u5148\u7528 \`ls\` / \`glob\` \u770B\u4E00\u4E0B\u76EE\u5F55\u7ED3\u6784\uFF0C\u6216\u786E\u8BA4\u8DEF\u5F84\u62FC\u5199\uFF08\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u89C1 system prompt\uFF09\u3002`
2735
2807
  };
2736
2808
  }
2809
+ /**
2810
+ * R2.5 文本未找到:edit_file / multi_edit 报 TEXT_NOT_FOUND 或 TEXT_MULTIPLE_MATCHES。
2811
+ *
2812
+ * 这是编辑工具最高频的失败。工具内部已对 CRLF 做归一化,仍报此错通常是
2813
+ * old_text 与当前文件内容不一致(缩进 / 已被改过 / 多次出现)。给一条明确
2814
+ * 的「重新读文件、逐字复制」指引,避免模型用同一份旧 old_text 反复重试。
2815
+ *
2816
+ * @pure 仅读入参
2817
+ */
2818
+ #ruleTextNotFound(item) {
2819
+ const isTextErr = item.result.error === "TEXT_NOT_FOUND" || item.result.error === "TEXT_MULTIPLE_MATCHES";
2820
+ if (!isTextErr) return null;
2821
+ const multiple = item.result.error === "TEXT_MULTIPLE_MATCHES";
2822
+ const hint = multiple ? `\`${item.name}\`\uFF1Aold_text \u5728\u6587\u4EF6\u4E2D\u51FA\u73B0\u591A\u6B21\u3002\u8BF7\u8865\u5145\u4E0A\u4E0B\u6587\u8BA9 old_text \u552F\u4E00\uFF0C\u6216\u6539\u7528 multi_edit \u7684 replaceAll\u3002` : `\`${item.name}\`\uFF1A\u672A\u627E\u5230 old_text\u3002\u8BF7\u91CD\u65B0 \`read_file\` \u770B\u5F53\u524D\u5185\u5BB9\uFF0C\u9010\u5B57\u590D\u5236\u8981\u66FF\u6362\u7684\u7247\u6BB5\uFF08\u6CE8\u610F\u7F29\u8FDB\u4E0E\u7A7A\u683C\uFF09\uFF1B\u884C\u5C3E\u5DF2\u505A CRLF \u5F52\u4E00\u5316\uFF0C\u65E0\u9700\u624B\u5199 \\r\\n\u3002`;
2823
+ return {
2824
+ category: "text_not_found",
2825
+ toolName: item.name,
2826
+ hint
2827
+ };
2828
+ }
2737
2829
  /**
2738
2830
  * R3 权限拒绝:GATE_DENIED 错误码 或 data 含 EACCES / permission / denied(不区分大小写)。
2739
2831
  *
@@ -2751,13 +2843,19 @@ var Reflector = class {
2751
2843
  };
2752
2844
  }
2753
2845
  /**
2754
- * R4 写根外:kind ∈ Edit/Delete/Move 且失败。
2846
+ * R4 写根外:kind ∈ Edit/Delete/Move 且错误码为 OUTSIDE_WRITE_ROOTS。
2847
+ *
2848
+ * 仅在工具本身明确报「路径超出写根」时才命中。旧实现只要写类工具失败就
2849
+ * 触发,会把 TEXT_NOT_FOUND / EXECUTION_ERROR 等误报为「写根外」,注入
2850
+ * 误导性提示(见会话日志 e65f0205 round 13:edit_file 因 CRLF 失配返回
2851
+ * TEXT_NOT_FOUND,却被反射为 out_of_write_root)。
2755
2852
  *
2756
2853
  * @pure 仅读入参
2757
2854
  */
2758
2855
  #ruleOutOfWriteRoot(item, writeRoots) {
2759
2856
  const isWriteKind = item.kind === "edit" /* Edit */ || item.kind === "delete" /* Delete */ || item.kind === "move" /* Move */;
2760
2857
  if (!isWriteKind) return null;
2858
+ if (item.result.error !== "OUTSIDE_WRITE_ROOTS") return null;
2761
2859
  const primary = writeRoots[0] ?? "<\u672A\u914D\u7F6E>";
2762
2860
  return {
2763
2861
  category: "out_of_write_root",
@@ -3929,7 +4027,7 @@ var Session = class _Session {
3929
4027
  };
3930
4028
  });
3931
4029
  for (const item of results.items) {
3932
- const todoSnapshot = item.name.startsWith("todo_") && this.#todoList ? this.#todoList.items : void 0;
4030
+ const todoSnapshot = item.name.startsWith("todo_") && this.#todoList ? this.#todoList.items.map((it) => ({ ...it })) : void 0;
3933
4031
  yield {
3934
4032
  type: "tool_result",
3935
4033
  name: item.name,
@@ -4335,8 +4433,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
4335
4433
  var DEFAULT_MAX_OUTPUT_LENGTH = 5e4;
4336
4434
  var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
4337
4435
  var isWindows = process2.platform === "win32";
4436
+ function stripMentionPrefix(inputPath) {
4437
+ if (inputPath.startsWith("@")) return inputPath.slice(1);
4438
+ return inputPath;
4439
+ }
4338
4440
  function resolvePath(inputPath, cwd) {
4339
- const resolved = isAbsolute(inputPath) ? inputPath : resolve(cwd, inputPath);
4441
+ const stripped = stripMentionPrefix(inputPath);
4442
+ const resolved = isAbsolute(stripped) ? stripped : resolve(cwd, stripped);
4340
4443
  return resolve(resolved);
4341
4444
  }
4342
4445
  async function realPath(target) {
@@ -4732,6 +4835,10 @@ function detectEol(text) {
4732
4835
  function hasTrailingNewline(text) {
4733
4836
  return text.endsWith("\n") || text.endsWith("\r\n");
4734
4837
  }
4838
+ function toLf(text) {
4839
+ if (!text.includes("\r")) return text;
4840
+ return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
4841
+ }
4735
4842
  function normalizeEol(originalContent, newContent) {
4736
4843
  const targetEol = detectEol(originalContent);
4737
4844
  const lines = newContent.replace(/\r\n/g, "\n").split("\n");
@@ -4823,7 +4930,7 @@ var readFileTool = {
4823
4930
  }
4824
4931
  }
4825
4932
  const content = await readFile5(filePath, "utf-8");
4826
- const lines = content.split("\n");
4933
+ const lines = toLf(content).split("\n");
4827
4934
  if (lines.length > 0 && lines[lines.length - 1] === "" && content.endsWith("\n")) {
4828
4935
  lines.pop();
4829
4936
  }
@@ -4931,6 +5038,7 @@ var writeFileTool = {
4931
5038
 
4932
5039
  // src/tool/builtins/edit-file.ts
4933
5040
  import { readFile as readFile7 } from "fs/promises";
5041
+ import { writeFile as writeFile5 } from "fs/promises";
4934
5042
  import { basename as basename3 } from "path";
4935
5043
  var editFileTool = {
4936
5044
  name: "edit_file",
@@ -4974,7 +5082,9 @@ var editFileTool = {
4974
5082
  }
4975
5083
  try {
4976
5084
  const content = await readFile7(filePath, "utf-8");
4977
- const firstIndex = content.indexOf(args.old_text);
5085
+ const contentN = toLf(content);
5086
+ const oldTextN = toLf(args.old_text);
5087
+ const firstIndex = contentN.indexOf(oldTextN);
4978
5088
  if (firstIndex === -1) {
4979
5089
  return {
4980
5090
  success: false,
@@ -4982,7 +5092,7 @@ var editFileTool = {
4982
5092
  error: "TEXT_NOT_FOUND"
4983
5093
  };
4984
5094
  }
4985
- const secondIndex = content.indexOf(args.old_text, firstIndex + 1);
5095
+ const secondIndex = contentN.indexOf(oldTextN, firstIndex + 1);
4986
5096
  if (secondIndex !== -1) {
4987
5097
  return {
4988
5098
  success: false,
@@ -4990,14 +5100,15 @@ var editFileTool = {
4990
5100
  error: "TEXT_MULTIPLE_MATCHES"
4991
5101
  };
4992
5102
  }
4993
- const newContent = content.replace(args.old_text, args.new_text);
4994
- await writeFileWithEol(filePath, content, newContent);
4995
- const diff = computeFileDiff(content, newContent, filePath);
5103
+ const newContentN = contentN.slice(0, firstIndex) + toLf(args.new_text) + contentN.slice(firstIndex + oldTextN.length);
5104
+ const writtenContent = normalizeEol(content, newContentN);
5105
+ await writeFile5(filePath, writtenContent, "utf-8");
5106
+ const diff = computeFileDiff(content, writtenContent, filePath);
4996
5107
  diff.existedBefore = true;
4997
- const beforeText = content.slice(0, firstIndex);
5108
+ const beforeText = contentN.slice(0, firstIndex);
4998
5109
  const startLine = beforeText.split("\n").length;
4999
- const oldLines = args.old_text.split("\n").length;
5000
- const newLines = args.new_text.split("\n").length;
5110
+ const oldLines = oldTextN.split("\n").length;
5111
+ const newLines = toLf(args.new_text).split("\n").length;
5001
5112
  const diffSummary = `+${diff.additions} -${diff.deletions}`;
5002
5113
  const summary = `\u{1F4DD} \u4FEE\u6539: ${basename3(filePath)} (+${diff.additions} -${diff.deletions})`;
5003
5114
  return {
@@ -5022,6 +5133,7 @@ ${oldLines} \u884C \u2192 ${newLines} \u884C
5022
5133
 
5023
5134
  // src/tool/builtins/multi-edit.ts
5024
5135
  import { readFile as readFile8 } from "fs/promises";
5136
+ import { writeFile as writeFile6 } from "fs/promises";
5025
5137
  import { basename as basename4 } from "path";
5026
5138
  var multiEditTool = {
5027
5139
  name: "multi_edit",
@@ -5068,7 +5180,7 @@ var multiEditTool = {
5068
5180
  }
5069
5181
  try {
5070
5182
  const originalContent = await readFile8(filePath, "utf-8");
5071
- let currentContent = originalContent;
5183
+ let currentContent = toLf(originalContent);
5072
5184
  for (let idx = 0; idx < args.edits.length; idx++) {
5073
5185
  const step = args.edits[idx];
5074
5186
  if (typeof step.oldText !== "string") {
@@ -5078,10 +5190,19 @@ var multiEditTool = {
5078
5190
  error: "INVALID_STEP_ARGS"
5079
5191
  };
5080
5192
  }
5193
+ if (typeof step.newText !== "string") {
5194
+ return {
5195
+ success: false,
5196
+ data: `\u7B2C ${idx + 1} \u6B65\uFF1A\u7F3A\u5C11\u6709\u6548\u7684 newText`,
5197
+ error: "INVALID_STEP_ARGS"
5198
+ };
5199
+ }
5200
+ const oldTextN = toLf(step.oldText);
5201
+ const newTextN = toLf(step.newText);
5081
5202
  if (step.replaceAll) {
5082
5203
  let count = 0;
5083
5204
  let pos = -1;
5084
- while ((pos = currentContent.indexOf(step.oldText, pos + 1)) !== -1) {
5205
+ while ((pos = currentContent.indexOf(oldTextN, pos + 1)) !== -1) {
5085
5206
  count++;
5086
5207
  }
5087
5208
  if (count === 0) {
@@ -5091,9 +5212,9 @@ var multiEditTool = {
5091
5212
  error: "TEXT_NOT_FOUND"
5092
5213
  };
5093
5214
  }
5094
- currentContent = currentContent.split(step.oldText).join(step.newText);
5215
+ currentContent = currentContent.split(oldTextN).join(newTextN);
5095
5216
  } else {
5096
- const firstIdx = currentContent.indexOf(step.oldText);
5217
+ const firstIdx = currentContent.indexOf(oldTextN);
5097
5218
  if (firstIdx === -1) {
5098
5219
  return {
5099
5220
  success: false,
@@ -5101,7 +5222,7 @@ var multiEditTool = {
5101
5222
  error: "TEXT_NOT_FOUND"
5102
5223
  };
5103
5224
  }
5104
- const secondIdx = currentContent.indexOf(step.oldText, firstIdx + 1);
5225
+ const secondIdx = currentContent.indexOf(oldTextN, firstIdx + 1);
5105
5226
  if (secondIdx !== -1) {
5106
5227
  return {
5107
5228
  success: false,
@@ -5109,11 +5230,12 @@ var multiEditTool = {
5109
5230
  error: "TEXT_MULTIPLE_MATCHES"
5110
5231
  };
5111
5232
  }
5112
- currentContent = currentContent.replace(step.oldText, step.newText);
5233
+ currentContent = currentContent.slice(0, firstIdx) + newTextN + currentContent.slice(firstIdx + oldTextN.length);
5113
5234
  }
5114
5235
  }
5115
- await writeFileWithEol(filePath, originalContent, currentContent);
5116
- const diff = computeFileDiff(originalContent, currentContent, filePath);
5236
+ const writtenContent = normalizeEol(originalContent, currentContent);
5237
+ await writeFile6(filePath, writtenContent, "utf-8");
5238
+ const diff = computeFileDiff(originalContent, writtenContent, filePath);
5117
5239
  diff.existedBefore = true;
5118
5240
  return {
5119
5241
  success: true,
@@ -5136,11 +5258,13 @@ var multiEditTool = {
5136
5258
 
5137
5259
  // src/tool/builtins/delete-range.ts
5138
5260
  import { readFile as readFile9 } from "fs/promises";
5261
+ import { writeFile as writeFile7 } from "fs/promises";
5139
5262
  import { basename as basename5 } from "path";
5140
5263
  function findUniqueLine(lines, anchor, label) {
5264
+ const anchorN = toLf(anchor);
5141
5265
  const matches = [];
5142
5266
  for (let i = 0; i < lines.length; i++) {
5143
- if (lines[i] === anchor) {
5267
+ if (toLf(lines[i]) === anchorN) {
5144
5268
  matches.push(i);
5145
5269
  }
5146
5270
  }
@@ -5199,7 +5323,7 @@ var deleteRangeTool = {
5199
5323
  }
5200
5324
  try {
5201
5325
  const content = await readFile9(filePath, "utf-8");
5202
- const lines = content.split("\n");
5326
+ const lines = toLf(content).split("\n");
5203
5327
  const startResult = findUniqueLine(lines, args.startAnchor, "start_anchor");
5204
5328
  if ("error" in startResult) {
5205
5329
  return { success: false, data: startResult.error, error: "ANCHOR_NOT_FOUND" };
@@ -5227,9 +5351,10 @@ var deleteRangeTool = {
5227
5351
  };
5228
5352
  }
5229
5353
  const newLines = [...lines.slice(0, rangeStart), ...lines.slice(rangeEnd + 1)];
5230
- const newContent = newLines.join("\n");
5231
- await writeFileWithEol(filePath, content, newContent);
5232
- const diff = computeFileDiff(content, newContent, filePath);
5354
+ const newContentN = newLines.join("\n");
5355
+ const writtenContent = normalizeEol(content, newContentN);
5356
+ await writeFile7(filePath, writtenContent, "utf-8");
5357
+ const diff = computeFileDiff(content, writtenContent, filePath);
5233
5358
  diff.existedBefore = true;
5234
5359
  const deletedLines = rangeEnd - rangeStart + 1;
5235
5360
  const summary = `\u{1F4DD} \u4FEE\u6539: ${basename5(filePath)} (\u5220 ${deletedLines} \u884C, +${diff.additions} -${diff.deletions})`;
@@ -5425,7 +5550,8 @@ var globTool = {
5425
5550
  if (!args?.pattern || typeof args.pattern !== "string") {
5426
5551
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
5427
5552
  }
5428
- const searchDir = args.directory ? isAbsolute2(args.directory) ? args.directory : join7(ctx.cwd, args.directory) : ctx.cwd;
5553
+ const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
5554
+ const searchDir = dir ? isAbsolute2(dir) ? dir : join7(ctx.cwd, dir) : ctx.cwd;
5429
5555
  const regex = globToRegex(args.pattern);
5430
5556
  try {
5431
5557
  const dirStat = await stat2(searchDir);
@@ -5526,7 +5652,8 @@ var grepTool = {
5526
5652
  if (!args?.pattern || typeof args.pattern !== "string") {
5527
5653
  return { success: false, data: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570 pattern", error: "INVALID_ARGS" };
5528
5654
  }
5529
- const searchDir = args.directory ? isAbsolute3(args.directory) ? args.directory : join8(ctx.cwd, args.directory) : ctx.cwd;
5655
+ const dir = args.directory ? stripMentionPrefix(args.directory) : void 0;
5656
+ const searchDir = dir ? isAbsolute3(dir) ? dir : join8(ctx.cwd, dir) : ctx.cwd;
5530
5657
  const maxFiles = args.max_files ?? 200;
5531
5658
  try {
5532
5659
  const flags = args.case_sensitive ? "g" : "gi";
@@ -5836,6 +5963,11 @@ var PHASE_CONFIG = {
5836
5963
  function isFileMutatingTool(name) {
5837
5964
  return name === "edit_file" || name === "write_file" || name === "multi_edit" || name === "delete_range";
5838
5965
  }
5966
+ function filterTodoToolCalls(calls) {
5967
+ if (!calls) return void 0;
5968
+ const filtered = calls.filter((tc) => !tc.name.startsWith("todo_"));
5969
+ return filtered.length > 0 ? filtered : void 0;
5970
+ }
5839
5971
  var commandRegistry = /* @__PURE__ */ new Map();
5840
5972
  function registerCommand(name, cmd) {
5841
5973
  commandRegistry.set(name, cmd);
@@ -5859,7 +5991,7 @@ registerCommand("/help", {
5859
5991
  registerCommand("/clear", { desc: "\u6E05\u7A7A\u5BF9\u8BDD\u5386\u53F2", handler: () => ({ kind: "clear" }) });
5860
5992
  registerCommand("/version", {
5861
5993
  desc: "\u663E\u793A\u7248\u672C\u4FE1\u606F",
5862
- handler: () => ({ kind: "text", content: "dskcode v0.1.10" })
5994
+ handler: () => ({ kind: "text", content: `dskcode v${VERSION}` })
5863
5995
  });
5864
5996
  registerCommand("/model", {
5865
5997
  desc: "\u5207\u6362\u6A21\u578B",
@@ -5957,6 +6089,8 @@ function ChatSession({
5957
6089
  const [_streamingModel, setStreamingModel] = useState4(void 0);
5958
6090
  const [streamError, setStreamError] = useState4(void 0);
5959
6091
  const [todoSnapshot, setTodoSnapshot] = useState4([]);
6092
+ const [todoPanelVisible, setTodoPanelVisible] = useState4(true);
6093
+ const todoHideTimerRef = useRef3(null);
5960
6094
  const [sessionMode, setSessionMode] = useState4("code");
5961
6095
  const [thinkingEnabled, setThinkingEnabled] = useState4(true);
5962
6096
  const [thinkingEffort, setThinkingEffort] = useState4("high");
@@ -6014,6 +6148,20 @@ function ChatSession({
6014
6148
  }
6015
6149
  };
6016
6150
  }, []);
6151
+ useEffect4(() => {
6152
+ if (todoHideTimerRef.current) {
6153
+ clearTimeout(todoHideTimerRef.current);
6154
+ todoHideTimerRef.current = null;
6155
+ }
6156
+ if (todoSnapshot.length === 0) {
6157
+ setTodoPanelVisible(false);
6158
+ return;
6159
+ }
6160
+ const hasUnfinished = todoSnapshot.some(
6161
+ (it) => it.status === "pending" || it.status === "running" || it.status === "failed"
6162
+ );
6163
+ setTodoPanelVisible(hasUnfinished);
6164
+ }, [todoSnapshot]);
6017
6165
  const getFilteredSkills = useCallback2(
6018
6166
  (value) => {
6019
6167
  const match = value.match(/(?:^|\s)\/([^/]*)$/);
@@ -6055,7 +6203,7 @@ function ChatSession({
6055
6203
  content: m.content,
6056
6204
  assistantDetail: {
6057
6205
  content: m.content,
6058
- toolCalls: m.toolCalls
6206
+ toolCalls: filterTodoToolCalls(m.toolCalls)
6059
6207
  }
6060
6208
  });
6061
6209
  } else if (m.role === "tool") {
@@ -6664,6 +6812,7 @@ function ChatSession({
6664
6812
  clearTimeout(rewindHintTimerRef.current);
6665
6813
  rewindHintTimerRef.current = null;
6666
6814
  }
6815
+ setTodoSnapshot([]);
6667
6816
  const session = sessionRef.current;
6668
6817
  const abortController = new AbortController();
6669
6818
  abortRef.current = abortController;
@@ -6721,7 +6870,14 @@ function ChatSession({
6721
6870
  currentToolCallsRef.current = [];
6722
6871
  const r = event.result;
6723
6872
  if (event.name.startsWith("todo_") && event.todoSnapshot) {
6724
- setTodoSnapshot(event.todoSnapshot);
6873
+ const allTerminated = event.todoSnapshot.length > 0 && event.todoSnapshot.every(
6874
+ (it) => it.status === "done" || it.status === "failed" || it.status === "skipped"
6875
+ );
6876
+ if (allTerminated) {
6877
+ setTodoSnapshot([]);
6878
+ } else {
6879
+ setTodoSnapshot(event.todoSnapshot);
6880
+ }
6725
6881
  } else {
6726
6882
  const line = r.success ? r.summary ?? `\u2705 ${event.name}: ${r.data.slice(0, 500)}${r.data.length > 500 ? "..." : ""}` : `\u274C ${event.name}: ${r.error ?? "\u6267\u884C\u5931\u8D25"}`;
6727
6883
  setDisplayMessages((prev) => [
@@ -6769,7 +6925,7 @@ function ChatSession({
6769
6925
  abortRef.current = null;
6770
6926
  const finContent = currentContentRef.current;
6771
6927
  const finReasoning = currentReasoningRef.current.map((s) => s.trim()).filter((s) => s.length > 0);
6772
- const finToolCalls = currentToolCallsRef.current.length > 0 ? currentToolCallsRef.current : void 0;
6928
+ const finToolCalls = filterTodoToolCalls(currentToolCallsRef.current);
6773
6929
  const finStreamError = streamErrorRef.current;
6774
6930
  if (finContent || finToolCalls || finStreamError) {
6775
6931
  const completed = {
@@ -6826,10 +6982,16 @@ function ChatSession({
6826
6982
  }, [isStreaming, externalCostTracker]);
6827
6983
  return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
6828
6984
  !hasConversationStarted && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", marginBottom: 1, children: [
6829
- /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", marginRight: 4, children: LOGO_LINES.map((line, i) => {
6830
- const colorIndex = (i + offset) % CYBER_PALETTE.length;
6831
- return /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
6832
- }) }),
6985
+ /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginRight: 4, children: [
6986
+ LOGO_LINES.map((line, i) => {
6987
+ const colorIndex = (i + offset) % CYBER_PALETTE.length;
6988
+ return /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsx10(Text11, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }) }, i);
6989
+ }),
6990
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: "#808080", children: [
6991
+ " \u{1F4E6} v",
6992
+ VERSION
6993
+ ] }) })
6994
+ ] }),
6833
6995
  /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", justifyContent: "center", children: [
6834
6996
  /* @__PURE__ */ jsxs10(Text11, { color: "#00ff41", children: [
6835
6997
  " \u2714 ",
@@ -6944,7 +7106,7 @@ function ChatSession({
6944
7106
  streamError
6945
7107
  ] }) })
6946
7108
  ] }),
6947
- todoSnapshot.length > 0 && /* @__PURE__ */ jsx10(TodoListPanel, { items: todoSnapshot }),
7109
+ todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx10(TodoListPanel, { items: todoSnapshot }),
6948
7110
  selectingModel ? /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
6949
7111
  /* @__PURE__ */ jsx10(Text11, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(dividerWidth) }),
6950
7112
  /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
@@ -8708,7 +8870,7 @@ var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"
8708
8870
  function createCli() {
8709
8871
  const program2 = new Command();
8710
8872
  program2.exitOverride();
8711
- program2.name("dskcode").description("\u57FA\u4E8E DeepSeek \u7684 AI \u7F16\u7A0B\u52A9\u624B\u7EC8\u7AEF\u5DE5\u5177").version("0.0.0", "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").option("--verbose", "\u5F00\u542F\u8BE6\u7EC6\u65E5\u5FD7\u8F93\u51FA").option("--config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84");
8873
+ program2.name("dskcode").description("\u57FA\u4E8E DeepSeek \u7684 AI \u7F16\u7A0B\u52A9\u624B\u7EC8\u7AEF\u5DE5\u5177").version(VERSION, "-V, --version", "\u663E\u793A\u7248\u672C\u53F7").option("--verbose", "\u5F00\u542F\u8BE6\u7EC6\u65E5\u5FD7\u8F93\u51FA").option("--config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84");
8712
8874
  program2.helpInformation = () => customHelp(program2);
8713
8875
  program2.hook("preAction", async (thisCommand, actionCommand) => {
8714
8876
  const ctx = await loadConfigMiddleware.call(thisCommand);