jinzd-ai-cli 0.1.48 → 0.1.49

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/CLAUDE.md CHANGED
@@ -38,8 +38,8 @@ src/
38
38
  │ ├── config-manager.ts # 读写 ~/.aicli/config.json,三层优先级:env > file > default
39
39
  │ └── env-loader.ts # AICLI_API_KEY_* 等环境变量映射
40
40
  ├── session/
41
- │ ├── session.ts # Session(addMessage / clear / compact / toJSON / fromJSON)
42
- │ └── session-manager.ts # CRUD for ~/.aicli/history/*.json
41
+ │ ├── session.ts # Session(addMessage / clear / compact / fork / toJSON / fromJSON)
42
+ │ └── session-manager.ts # CRUD + forkSession for ~/.aicli/history/*.json
43
43
  ├── repl/
44
44
  │ ├── repl.ts # 主 REPL 循环(MAX_TOOL_ROUNDS=20,handleChatWithTools agentic loop)
45
45
  │ ├── renderer.ts # 终端输出(renderStream / renderResponse 均不加前置 \n)
@@ -47,7 +47,7 @@ src/
47
47
  │ ├── dev-state.ts # 开发状态交接(provider/model 切换时快照生成、save/load/clear)
48
48
  │ ├── setup-wizard.ts # @inquirer/prompts 首次运行交互式设置
49
49
  │ └── commands/
50
- │ └── index.ts # CommandRegistry + 33个命令(/help /about /provider /model /clear /compact /plan /session /system /context /status /search /undo /export /copy /cost /init /skill /tools /plugins /mcp /config /checkpoint /review /commands /test /scaffold /add-dir /memory /doctor /bug /think /exit)
50
+ │ └── index.ts # CommandRegistry + 35个命令(/help /about /provider /model /clear /compact /plan /session /system /context /status /search /undo /export /copy /cost /init /skill /tools /plugins /mcp /config /checkpoint /review /commands /test /scaffold /add-dir /memory /doctor /bug /think /diff /fork /exit)
51
51
  │ ├── custom-commands.ts # CustomCommandManager(~/.aicli/commands/*.md 用户自定义命令)
52
52
  ├── skills/
53
53
  │ ├── types.ts # Skill/SkillMeta 接口、parseSkillFile(YAML frontmatter 解析)
@@ -350,6 +350,81 @@ const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String)
350
350
  - [x] **web_fetch DNS 解析时 SSRF 防护**(v0.1.25):新增 `resolveAndCheck()` 函数,用 `dns.promises.lookup()` 预解析域名,检查结果 IP 是否为私有地址。初始 URL 和 redirect 目标均校验。
351
351
  - [ ] **`persistentCwd` 全局状态**:bash 工具的当前工作目录是模块级全局变量,多 session 并发时可能串扰。现阶段单 session REPL 无影响,GUI 多会话扩展时需重构为 per-session 状态。
352
352
 
353
+ ## 本轮开发完成记录(2026-03-08,v0.1.47 → v0.1.48)
354
+
355
+ ### Tier 2 体验增强:/undo 增强 + /fork 对话分支
356
+
357
+ **Feature 1:/undo 增强 — bash 工具文件追踪 + 命令增强**
358
+
359
+ | 文件 | 变更 |
360
+ |------|------|
361
+ | `src/tools/undo-stack.ts` | `UndoEntry` 新增 `isDirectory?: boolean` + `pushNewFile()` / `pushNewDir()` 方法 + `undo()` 目录分支 |
362
+ | `src/tools/builtin/bash.ts` | 三辅助函数 + `execute()` 集成 |
363
+ | `src/repl/commands/index.ts` | `/undo` 重写为 `/undo [list\|<n>]` |
364
+
365
+ - **UndoStack 扩展**:新增 `pushNewFile(filePath, desc)` 和 `pushNewDir(dirPath, desc)` 方法,previousContent=null 表示新建(undo 时删除)。`undo()` 新增 `isDirectory` 分支,用 `rmdirSync` 尝试删除空目录,非空给出提示。
366
+ - **Bash 工具文件追踪**(浅层 CWD 快照 + 命令模式解析):
367
+ - `snapshotDir(dir)` — `readdirSync` 获取目录下所有条目的绝对路径 Set
368
+ - `parseCreationTargets(command, cwd)` — 正则解析 touch/mkdir/echo>/cp/New-Item 等常见创建命令的目标路径
369
+ - `pushBashUndoEntries(beforeSnapshot, parsedTargetsBefore, cwd)` — 对比前后快照 + 解析目标,为新建文件/目录推入 undo 条目
370
+ - 集成到 `execute()`:执行前快照 + 构建目标存在状态 Map;执行后(成功/失败均)调用 pushBashUndoEntries
371
+ - **/undo 命令增强**:
372
+ - `/undo` — 撤销最近 1 次(向后兼容)
373
+ - `/undo list` — 显示完整 undo 栈(编号、类型标签 `[new]`/`[mod]`/`[dir]`、描述、时间)
374
+ - `/undo <n>` — 连续撤销最近 N 次操作,逐条显示进度
375
+
376
+ **Feature 2:/fork 对话分支**
377
+
378
+ | 文件 | 变更 |
379
+ |------|------|
380
+ | `src/session/session.ts` | 静态 `fork(original, newId, messageCount, newTitle?)` 方法 |
381
+ | `src/session/session-manager.ts` | `forkSession(messageCount, title?)` 方法 |
382
+ | `src/repl/commands/index.ts` | `/fork` 命令 + `CommandContext.forkSession` |
383
+ | `src/repl/repl.ts` | ctx.forkSession 注入 + tab 补全(/undo list, /fork checkpoint 名称) |
384
+
385
+ - **Session.fork()**:复制 messages[0..messageCount],保留范围内 checkpoints(深拷贝),新 UUID,title 默认 "Fork of <原标题>"
386
+ - **SessionManager.forkSession()**:先保存原始 session → Session.fork 创建分叉 → 设为当前 → 保存并返回
387
+ - **/fork 命令**:
388
+ - `/fork` — 从当前位置分叉(复制全部消息)
389
+ - `/fork <checkpoint-name>` — 从指定 checkpoint 分叉(仅复制到该 checkpoint 的消息)
390
+ - 显示原始/新 session ID、title、消息数、保留 checkpoint 数
391
+ - 提示用户 `/session load <id>` 切回原始
392
+ - **Tab 补全**:`/undo` 提供 `list`;`/fork` 提供当前 session 的 checkpoint 名称列表
393
+
394
+ ### 版本与收尾
395
+ - `src/core/constants.ts`:VERSION `0.1.47` → `0.1.48`
396
+ - `package.json`:version 同步
397
+ - `src/repl/renderer.ts`:命令计数 34 → 35,命令列表新增 `/fork`,新增 1 条特性(/fork 对话分支),更新 /undo 描述
398
+ - 构建验证:`npm run build` 零错误(ESM + CJS 双产物)
399
+ - 发布:`npm publish` → `jinzd-ai-cli@0.1.48`
400
+
401
+ ### 本轮变更文件汇总
402
+
403
+ | 文件 | 变更类型 | 说明 |
404
+ |------|---------|------|
405
+ | `src/core/constants.ts` | 修改 | VERSION 0.1.47 → 0.1.48 |
406
+ | `src/tools/undo-stack.ts` | 修改 | isDirectory 字段 + pushNewFile/pushNewDir + undo 目录支持 |
407
+ | `src/tools/builtin/bash.ts` | 修改 | snapshotDir + parseCreationTargets + pushBashUndoEntries + execute 集成 |
408
+ | `src/session/session.ts` | 修改 | 静态 fork() 方法 |
409
+ | `src/session/session-manager.ts` | 修改 | forkSession() 方法 |
410
+ | `src/repl/commands/index.ts` | 修改 | /undo 增强 + /fork 命令 + CommandContext.forkSession + /help 更新 |
411
+ | `src/repl/repl.ts` | 修改 | ctx.forkSession 注入 + tab 补全(/undo, /fork) |
412
+ | `src/repl/renderer.ts` | 修改 | /about 35 命令 + 特性更新 |
413
+ | `package.json` | 修改 | version 0.1.47 → 0.1.48 |
414
+
415
+ ### 下一步建议
416
+
417
+ #### Tier 2 — 体验增强(剩余)
418
+ 1. **L1 低危**:`run-tests.ts` 的 `JSON.parse(package.json)` 细粒度错误处理
419
+ 2. **IDE 集成**:VS Code 扩展(架构已准备就绪,core/providers/tools 无终端依赖)
420
+ 3. **OAuth/浏览器登录**:无需手动填 API Key,打开浏览器完成 OAuth 流程自动保存 token
421
+
422
+ #### Tier 3 — 长远方向
423
+ 4. **Web UI**:基于 EventBus + WebSocket 的浏览器界面,复用 core/providers/tools 层
424
+ 5. **GitHub 仓库迁移**:从 gitee 迁移到 GitHub,npm 包受众更广
425
+
426
+ ---
427
+
353
428
  ## 本轮开发完成记录(2026-03-07,v0.1.40 → v0.1.41)
354
429
 
355
430
  ### Bug 修复:Kimi 虚假完成声明(方案 C)
@@ -536,8 +611,8 @@ const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String)
536
611
  4. **L1 低危**:`run-tests.ts` 的 `JSON.parse(package.json)` 细粒度错误处理
537
612
  5. **IDE 集成**:VS Code 扩展(架构已准备就绪,core/providers/tools 无终端依赖)
538
613
  6. **OAuth/浏览器登录**:无需手动填 API Key,打开浏览器完成 OAuth 流程自动保存 token
539
- 7. **`/undo` 增强**:支持 bash 工具创建的文件/目录的撤销(当前仅支持 write_file / edit_file)
540
- 8. **对话分支(fork)**:`/fork` 从当前对话某个 checkpoint 分叉为新 session,探索不同方案
614
+ 7. ~~**`/undo` 增强**~~:✅ 已在 v0.1.48 实现(bash 文件追踪 + /undo list + /undo <n>)
615
+ 8. ~~**对话分支(fork)**~~:✅ 已在 v0.1.48 实现(/fork [checkpoint-name])
541
616
 
542
617
  #### Tier 3 — 长远方向
543
618
  9. **Web UI**:基于 EventBus + WebSocket 的浏览器界面,复用 core/providers/tools 层
@@ -8,7 +8,7 @@ import { platform } from "os";
8
8
  import chalk from "chalk";
9
9
 
10
10
  // src/core/constants.ts
11
- var VERSION = "0.1.48";
11
+ var VERSION = "0.1.49";
12
12
  var APP_NAME = "ai-cli";
13
13
  var CONFIG_DIR_NAME = ".aicli";
14
14
  var CONFIG_FILE_NAME = "config.json";
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  SUBAGENT_MAX_ROUNDS_LIMIT,
30
30
  VERSION,
31
31
  runTestsTool
32
- } from "./chunk-XDSNK7WW.js";
32
+ } from "./chunk-P4XKHPXU.js";
33
33
 
34
34
  // src/index.ts
35
35
  import { program } from "commander";
@@ -2061,8 +2061,8 @@ var SessionManager = class {
2061
2061
 
2062
2062
  // src/repl/repl.ts
2063
2063
  import * as readline from "readline";
2064
- import { existsSync as existsSync19, readFileSync as readFileSync13, readdirSync as readdirSync10, statSync as statSync8 } from "fs";
2065
- import { join as join14, resolve as resolve4, extname as extname4, dirname as dirname5, basename as basename5 } from "path";
2064
+ import { existsSync as existsSync19, readFileSync as readFileSync13, readdirSync as readdirSync11, statSync as statSync8 } from "fs";
2065
+ import { join as join14, resolve as resolve5, extname as extname4, dirname as dirname6, basename as basename6 } from "path";
2066
2066
  import chalk10 from "chalk";
2067
2067
 
2068
2068
  // src/repl/renderer.ts
@@ -2426,8 +2426,8 @@ var Renderer = class {
2426
2426
  process.stdout.write("\n\n");
2427
2427
  }
2428
2428
  if (fileStream) {
2429
- await new Promise((resolve5, reject) => {
2430
- fileStream.end((err) => err ? reject(err) : resolve5());
2429
+ await new Promise((resolve6, reject) => {
2430
+ fileStream.end((err) => err ? reject(err) : resolve6());
2431
2431
  });
2432
2432
  const kb = (Buffer.byteLength(fullContent, "utf-8") / 1024).toFixed(1);
2433
2433
  process.stdout.write(theme.success(` \u2705 \u5DF2\u4FDD\u5B58: ${options.saveToFile} (${kb} KB)
@@ -2482,7 +2482,7 @@ var Renderer = class {
2482
2482
  process.stdout.write(displayed.slice(pos, end));
2483
2483
  pos = end;
2484
2484
  if (pos < displayed.length) {
2485
- await new Promise((resolve5) => setTimeout(resolve5, DELAY_MS));
2485
+ await new Promise((resolve6) => setTimeout(resolve6, DELAY_MS));
2486
2486
  }
2487
2487
  }
2488
2488
  process.stdout.write("\n\n");
@@ -4288,7 +4288,7 @@ ${hint}` : "")
4288
4288
  description: "Run project tests and show structured report",
4289
4289
  usage: "/test [command|filter]",
4290
4290
  async execute(args, _ctx) {
4291
- const { executeTests } = await import("./run-tests-2TCRQBHR.js");
4291
+ const { executeTests } = await import("./run-tests-JJVZWQKI.js");
4292
4292
  const argStr = args.join(" ").trim();
4293
4293
  let testArgs = {};
4294
4294
  if (argStr) {
@@ -4685,7 +4685,7 @@ var IGNORE_ENTER_MS = 80;
4685
4685
  function selectFromList(prompt, items, initialIndex = 0) {
4686
4686
  if (items.length === 0) return Promise.resolve(null);
4687
4687
  const PAGE = 12;
4688
- return new Promise((resolve5) => {
4688
+ return new Promise((resolve6) => {
4689
4689
  let selected = Math.max(0, Math.min(initialIndex, items.length - 1));
4690
4690
  let windowStart = Math.max(0, selected - Math.floor(PAGE / 2));
4691
4691
  let lastRenderedLines = 0;
@@ -4760,7 +4760,7 @@ function selectFromList(prompt, items, initialIndex = 0) {
4760
4760
  process.stdout.write(chalk5.dim(` \u2714 ${result}
4761
4761
  `));
4762
4762
  }
4763
- resolve5(result);
4763
+ resolve6(result);
4764
4764
  };
4765
4765
  const handleSequence = (seq) => {
4766
4766
  if (seq === "\x1B") {
@@ -4824,13 +4824,13 @@ function selectFromList(prompt, items, initialIndex = 0) {
4824
4824
  }
4825
4825
  };
4826
4826
  if (!process.stdin.isTTY) {
4827
- resolve5(items[0]?.value ?? null);
4827
+ resolve6(items[0]?.value ?? null);
4828
4828
  return;
4829
4829
  }
4830
4830
  try {
4831
4831
  process.stdin.setRawMode(true);
4832
4832
  } catch {
4833
- resolve5(items[0]?.value ?? null);
4833
+ resolve6(items[0]?.value ?? null);
4834
4834
  return;
4835
4835
  }
4836
4836
  savedDataListeners = process.stdin.rawListeners("data");
@@ -5051,8 +5051,9 @@ function updateCwdFromCommand(command, baseCwd) {
5051
5051
  }
5052
5052
 
5053
5053
  // src/tools/builtin/read-file.ts
5054
- import { readFileSync as readFileSync5, existsSync as existsSync8, statSync as statSync4 } from "fs";
5055
- import { extname, resolve as resolve3, basename as basename2, sep } from "path";
5054
+ import { readFileSync as readFileSync5, existsSync as existsSync8, statSync as statSync4, readdirSync as readdirSync4 } from "fs";
5055
+ import { execSync as execSync5 } from "child_process";
5056
+ import { extname, resolve as resolve3, basename as basename2, sep, dirname as dirname3 } from "path";
5056
5057
  import { homedir as homedir2 } from "os";
5057
5058
  var MAX_FILE_BYTES = 10 * 1024 * 1024;
5058
5059
  function getSensitiveWarning(normalizedPath) {
@@ -5120,6 +5121,55 @@ function isBinaryBuffer(buf) {
5120
5121
  }
5121
5122
  return nullCount / sample.length > 0.1;
5122
5123
  }
5124
+ function findSimilarFiles(filePath) {
5125
+ const targetName = basename2(filePath).toLowerCase();
5126
+ if (!targetName) return [];
5127
+ const cwd = process.cwd();
5128
+ const candidates = [];
5129
+ try {
5130
+ for (const entry of readdirSync4(cwd, { withFileTypes: true })) {
5131
+ if (entry.isFile() && entry.name.toLowerCase() === targetName) {
5132
+ candidates.push(entry.name);
5133
+ }
5134
+ if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
5135
+ try {
5136
+ const subDir = resolve3(cwd, entry.name);
5137
+ for (const sub of readdirSync4(subDir, { withFileTypes: true })) {
5138
+ if (sub.isFile() && sub.name.toLowerCase() === targetName) {
5139
+ candidates.push(`${entry.name}/${sub.name}`);
5140
+ }
5141
+ }
5142
+ } catch {
5143
+ }
5144
+ }
5145
+ }
5146
+ } catch {
5147
+ }
5148
+ return candidates.slice(0, 5);
5149
+ }
5150
+ function tryExtractPdfText(absPath) {
5151
+ try {
5152
+ const output = execSync5(`pdftotext "${absPath}" -`, {
5153
+ timeout: 15e3,
5154
+ encoding: "utf-8",
5155
+ stdio: ["pipe", "pipe", "pipe"]
5156
+ });
5157
+ if (output.trim().length > 0) return output;
5158
+ } catch {
5159
+ }
5160
+ try {
5161
+ const pyScript = `import sys; exec("try:\\n from pdfminer.high_level import extract_text\\n print(extract_text(sys.argv[1]))\\nexcept: pass")`;
5162
+ const output = execSync5(`python -c "${pyScript}" "${absPath}"`, {
5163
+ timeout: 15e3,
5164
+ encoding: "utf-8",
5165
+ stdio: ["pipe", "pipe", "pipe"],
5166
+ env: { ...process.env, PYTHONUTF8: "1", PYTHONIOENCODING: "utf-8" }
5167
+ });
5168
+ if (output.trim().length > 0) return output;
5169
+ } catch {
5170
+ }
5171
+ return null;
5172
+ }
5123
5173
  var readFileTool = {
5124
5174
  definition: {
5125
5175
  name: "read_file",
@@ -5144,7 +5194,23 @@ var readFileTool = {
5144
5194
  const encoding = args["encoding"] ?? "utf-8";
5145
5195
  if (!filePath) throw new Error("path is required");
5146
5196
  const normalizedPath = resolve3(filePath);
5147
- if (!existsSync8(normalizedPath)) throw new Error(`File not found: ${filePath}`);
5197
+ if (!existsSync8(normalizedPath)) {
5198
+ const suggestions = findSimilarFiles(filePath);
5199
+ if (suggestions.length > 0) {
5200
+ throw new Error(
5201
+ `File not found: ${filePath}
5202
+ \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${process.cwd()}
5203
+ \u627E\u5230\u540C\u540D\u6587\u4EF6\uFF0C\u4F60\u662F\u5426\u8981\u627E\uFF1A
5204
+ ` + suggestions.map((s) => ` \u2192 ${s}`).join("\n") + `
5205
+ \u8BF7\u4F7F\u7528\u6B63\u786E\u7684\u76F8\u5BF9\u8DEF\u5F84\u91CD\u8BD5\u3002`
5206
+ );
5207
+ }
5208
+ throw new Error(
5209
+ `File not found: ${filePath}
5210
+ \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${process.cwd()}
5211
+ \u8BF7\u4F7F\u7528 list_dir \u786E\u8BA4\u6587\u4EF6\u8DEF\u5F84\u540E\u91CD\u8BD5\u3002`
5212
+ );
5213
+ }
5148
5214
  const { size } = statSync4(normalizedPath);
5149
5215
  if (size > MAX_FILE_BYTES) {
5150
5216
  const mb = (size / 1024 / 1024).toFixed(1);
@@ -5157,12 +5223,31 @@ var readFileTool = {
5157
5223
  }
5158
5224
  const sensitiveWarning = getSensitiveWarning(normalizedPath);
5159
5225
  const ext = extname(normalizedPath).toLowerCase();
5226
+ if (ext === ".pdf") {
5227
+ const pdfText = tryExtractPdfText(normalizedPath);
5228
+ if (pdfText) {
5229
+ const lines2 = pdfText.split("\n").length;
5230
+ return `[PDF extracted: ${filePath} | ${lines2} lines]
5231
+
5232
+ ${pdfText}`;
5233
+ }
5234
+ const dir = dirname3(normalizedPath);
5235
+ const nameNoExt = basename2(normalizedPath, ext);
5236
+ const textAlts = [".md", ".txt", ".html"].map((e) => resolve3(dir, nameNoExt + e)).filter(existsSync8);
5237
+ return `[Binary file: ${filePath}]
5238
+ PDF \u6587\u672C\u63D0\u53D6\u5931\u8D25\uFF08pdftotext \u548C pdfminer \u5747\u4E0D\u53EF\u7528\uFF09\u3002
5239
+ ` + (textAlts.length > 0 ? `\u627E\u5230\u53EF\u66FF\u4EE3\u7684\u6587\u672C\u7248\u672C\uFF1A
5240
+ ${textAlts.map((p) => ` \u2192 ${basename2(p)}`).join("\n")}
5241
+ \u8BF7\u4F7F\u7528 read_file \u8BFB\u53D6\u4E0A\u8FF0\u6587\u4EF6\u3002` : `\u5982\u9700\u4F7F\u7528\u5176\u5185\u5BB9\uFF0C\u8BF7\u4F7F\u7528 bash \u5DE5\u5177\u5B89\u88C5\u5E76\u8C03\u7528 pdftotext\uFF1A
5242
+ pip install pdfminer.six # \u5B89\u88C5 Python PDF \u5E93
5243
+ \u6216\u5C06 PDF \u624B\u52A8\u8F6C\u6362\u4E3A .md / .txt \u6587\u4EF6\u540E\u518D\u8BFB\u53D6\u3002`);
5244
+ }
5160
5245
  if (BINARY_EXTENSIONS.has(ext)) {
5161
5246
  return `[Binary file: ${filePath}]
5162
5247
  \u6B64\u6587\u4EF6\u4E3A\u4E8C\u8FDB\u5236\u683C\u5F0F\uFF08${ext}\uFF09\uFF0C\u65E0\u6CD5\u4F5C\u4E3A\u6587\u672C\u8BFB\u53D6\u3002
5163
5248
  \u5982\u9700\u4F7F\u7528\u5176\u5185\u5BB9\uFF0C\u8BF7\u8003\u8651\uFF1A
5164
5249
  1. \u5C06\u6587\u4EF6\u8F6C\u6362\u4E3A\u6587\u672C\u683C\u5F0F\u540E\u518D\u8BFB\u53D6
5165
- 2. \u4F7F\u7528 bash \u5DE5\u5177\u8C03\u7528\u5916\u90E8\u8F6C\u6362\u7A0B\u5E8F\uFF08\u5982 pdftotext\u3001pandoc \u7B49\uFF09
5250
+ 2. \u4F7F\u7528 bash \u5DE5\u5177\u8C03\u7528\u5916\u90E8\u8F6C\u6362\u7A0B\u5E8F\uFF08\u5982 pandoc \u7B49\uFF09
5166
5251
  3. \u82E5\u6709\u5BF9\u5E94\u7684\u7EAF\u6587\u672C\u7248\u672C\uFF08.md / .txt\uFF09\uFF0C\u8BF7\u76F4\u63A5\u8BFB\u53D6\u90A3\u4E2A\u6587\u4EF6`;
5167
5252
  }
5168
5253
  const buf = readFileSync5(normalizedPath);
@@ -5186,7 +5271,7 @@ ${content}`;
5186
5271
 
5187
5272
  // src/tools/builtin/write-file.ts
5188
5273
  import { writeFileSync as writeFileSync5, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "fs";
5189
- import { dirname as dirname3 } from "path";
5274
+ import { dirname as dirname4 } from "path";
5190
5275
  var writeFileTool = {
5191
5276
  definition: {
5192
5277
  name: "write_file",
@@ -5226,7 +5311,7 @@ var writeFileTool = {
5226
5311
  if (!appendMode) {
5227
5312
  undoStack.push(filePath, `write_file: ${filePath}`);
5228
5313
  }
5229
- mkdirSync5(dirname3(filePath), { recursive: true });
5314
+ mkdirSync5(dirname4(filePath), { recursive: true });
5230
5315
  if (appendMode) {
5231
5316
  appendFileSync2(filePath, content, encoding);
5232
5317
  } else {
@@ -5458,8 +5543,8 @@ function truncatePreview(str, maxLen = 80) {
5458
5543
  }
5459
5544
 
5460
5545
  // src/tools/builtin/list-dir.ts
5461
- import { readdirSync as readdirSync4, statSync as statSync5, existsSync as existsSync10 } from "fs";
5462
- import { join as join6 } from "path";
5546
+ import { readdirSync as readdirSync5, statSync as statSync5, existsSync as existsSync10 } from "fs";
5547
+ import { join as join6, basename as basename3 } from "path";
5463
5548
  var listDirTool = {
5464
5549
  definition: {
5465
5550
  name: "list_dir",
@@ -5481,7 +5566,33 @@ var listDirTool = {
5481
5566
  async execute(args) {
5482
5567
  const dirPath = String(args["path"] ?? process.cwd());
5483
5568
  const recursive = Boolean(args["recursive"] ?? false);
5484
- if (!existsSync10(dirPath)) throw new Error(`Directory not found: ${dirPath}`);
5569
+ if (!existsSync10(dirPath)) {
5570
+ const targetName = basename3(dirPath).toLowerCase();
5571
+ const cwd = process.cwd();
5572
+ const suggestions = [];
5573
+ try {
5574
+ for (const entry of readdirSync5(cwd, { withFileTypes: true })) {
5575
+ if (entry.isDirectory() && entry.name.toLowerCase() === targetName) {
5576
+ suggestions.push(entry.name);
5577
+ }
5578
+ }
5579
+ } catch {
5580
+ }
5581
+ if (suggestions.length > 0) {
5582
+ throw new Error(
5583
+ `Directory not found: ${dirPath}
5584
+ \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${cwd}
5585
+ \u627E\u5230\u540C\u540D\u76EE\u5F55\uFF1A
5586
+ ` + suggestions.map((s) => ` \u2192 ${s}`).join("\n") + `
5587
+ \u8BF7\u4F7F\u7528\u6B63\u786E\u7684\u76F8\u5BF9\u8DEF\u5F84\u91CD\u8BD5\u3002`
5588
+ );
5589
+ }
5590
+ throw new Error(
5591
+ `Directory not found: ${dirPath}
5592
+ \u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55: ${cwd}
5593
+ \u8BF7\u5148\u4F7F\u7528 list_dir\uFF08\u4E0D\u4F20 path\uFF09\u67E5\u770B\u5F53\u524D\u76EE\u5F55\u7ED3\u6784\u3002`
5594
+ );
5595
+ }
5485
5596
  const lines = [`Directory: ${dirPath}
5486
5597
  `];
5487
5598
  listRecursive(dirPath, "", recursive, lines);
@@ -5491,7 +5602,7 @@ var listDirTool = {
5491
5602
  function listRecursive(basePath, indent, recursive, lines) {
5492
5603
  let entries;
5493
5604
  try {
5494
- entries = readdirSync4(basePath, { withFileTypes: true });
5605
+ entries = readdirSync5(basePath, { withFileTypes: true });
5495
5606
  } catch {
5496
5607
  lines.push(`${indent}(permission denied)`);
5497
5608
  return;
@@ -5530,7 +5641,7 @@ function formatSize(bytes) {
5530
5641
  }
5531
5642
 
5532
5643
  // src/tools/builtin/grep-files.ts
5533
- import { readdirSync as readdirSync5, readFileSync as readFileSync7, statSync as statSync6, existsSync as existsSync11 } from "fs";
5644
+ import { readdirSync as readdirSync6, readFileSync as readFileSync7, statSync as statSync6, existsSync as existsSync11 } from "fs";
5534
5645
  import { join as join7, relative } from "path";
5535
5646
  var grepFilesTool = {
5536
5647
  definition: {
@@ -5647,7 +5758,7 @@ function collectFiles(dirPath, filePattern, results, regex, contextLines, maxRes
5647
5758
  if (results.length >= maxResults) return;
5648
5759
  let entries;
5649
5760
  try {
5650
- entries = readdirSync5(dirPath, { withFileTypes: true });
5761
+ entries = readdirSync6(dirPath, { withFileTypes: true });
5651
5762
  } catch {
5652
5763
  return;
5653
5764
  }
@@ -5700,8 +5811,8 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
5700
5811
  }
5701
5812
 
5702
5813
  // src/tools/builtin/glob-files.ts
5703
- import { readdirSync as readdirSync6, statSync as statSync7, existsSync as existsSync12 } from "fs";
5704
- import { join as join8, relative as relative2, basename as basename3 } from "path";
5814
+ import { readdirSync as readdirSync7, statSync as statSync7, existsSync as existsSync12 } from "fs";
5815
+ import { join as join8, relative as relative2, basename as basename4 } from "path";
5705
5816
  var globFilesTool = {
5706
5817
  definition: {
5707
5818
  name: "glob_files",
@@ -5805,7 +5916,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
5805
5916
  if (results.length >= maxResults) return;
5806
5917
  let entries;
5807
5918
  try {
5808
- entries = readdirSync6(dirPath, { withFileTypes: true });
5919
+ entries = readdirSync7(dirPath, { withFileTypes: true });
5809
5920
  } catch {
5810
5921
  return;
5811
5922
  }
@@ -5817,7 +5928,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
5817
5928
  collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
5818
5929
  } else if (entry.isFile()) {
5819
5930
  const relPath = relative2(rootPath, fullPath).replace(/\\/g, "/");
5820
- if (regex.test(relPath) || regex.test(basename3(relPath))) {
5931
+ if (regex.test(relPath) || regex.test(basename4(relPath))) {
5821
5932
  try {
5822
5933
  const stat = statSync7(fullPath);
5823
5934
  results.push({ relPath, absPath: fullPath, mtime: stat.mtimeMs });
@@ -5893,7 +6004,7 @@ var runInteractiveTool = {
5893
6004
  PYTHONDONTWRITEBYTECODE: "1"
5894
6005
  };
5895
6006
  const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
5896
- return new Promise((resolve5) => {
6007
+ return new Promise((resolve6) => {
5897
6008
  const child = spawn(executable, cmdArgs.map(String), {
5898
6009
  cwd: process.cwd(),
5899
6010
  env,
@@ -5926,22 +6037,22 @@ var runInteractiveTool = {
5926
6037
  setTimeout(writeNextLine, 400);
5927
6038
  const timer = setTimeout(() => {
5928
6039
  child.kill();
5929
- resolve5(`${prefixWarnings}[Timeout after ${timeout}ms]
6040
+ resolve6(`${prefixWarnings}[Timeout after ${timeout}ms]
5930
6041
  ${buildOutput(stdout, stderr)}`);
5931
6042
  }, timeout);
5932
6043
  child.on("close", (code) => {
5933
6044
  clearTimeout(timer);
5934
6045
  const output = buildOutput(stdout, stderr);
5935
6046
  if (code !== 0 && code !== null) {
5936
- resolve5(`${prefixWarnings}Exit code ${code}:
6047
+ resolve6(`${prefixWarnings}Exit code ${code}:
5937
6048
  ${output}`);
5938
6049
  } else {
5939
- resolve5(`${prefixWarnings}${output || "(no output)"}`);
6050
+ resolve6(`${prefixWarnings}${output || "(no output)"}`);
5940
6051
  }
5941
6052
  });
5942
6053
  child.on("error", (err) => {
5943
6054
  clearTimeout(timer);
5944
- resolve5(
6055
+ resolve6(
5945
6056
  `${prefixWarnings}Failed to start process "${executable}": ${err.message}
5946
6057
  Hint: On Windows, use the full path to the executable, e.g.:
5947
6058
  C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
@@ -6162,7 +6273,7 @@ var webFetchTool = {
6162
6273
 
6163
6274
  // src/tools/builtin/save-last-response.ts
6164
6275
  import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "fs";
6165
- import { dirname as dirname4 } from "path";
6276
+ import { dirname as dirname5 } from "path";
6166
6277
  var lastResponseStore = { content: "" };
6167
6278
  var saveLastResponseTool = {
6168
6279
  definition: {
@@ -6195,7 +6306,7 @@ var saveLastResponseTool = {
6195
6306
  throw new Error("\u6CA1\u6709\u53EF\u4FDD\u5B58\u7684\u5185\u5BB9\uFF1AAI \u5C1A\u672A\u4EA7\u751F\u4EFB\u4F55\u56DE\u590D\uFF0C\u6216\u4E0A\u6B21\u56DE\u590D\u4E3A\u7A7A\u3002");
6196
6307
  }
6197
6308
  undoStack.push(filePath, `save_last_response: ${filePath}`);
6198
- mkdirSync6(dirname4(filePath), { recursive: true });
6309
+ mkdirSync6(dirname5(filePath), { recursive: true });
6199
6310
  writeFileSync7(filePath, content, "utf-8");
6200
6311
  const lines = content.split("\n").length;
6201
6312
  return `File saved: ${filePath} (${lines} lines, ${content.length} bytes)`;
@@ -6288,7 +6399,7 @@ function promptUser(rl, question) {
6288
6399
  console.log();
6289
6400
  console.log(chalk6.cyan("\u2753 ") + chalk6.bold(question));
6290
6401
  process.stdout.write(chalk6.cyan("> "));
6291
- return new Promise((resolve5) => {
6402
+ return new Promise((resolve6) => {
6292
6403
  let completed = false;
6293
6404
  const cleanup = (answer) => {
6294
6405
  if (completed) return;
@@ -6298,7 +6409,7 @@ function promptUser(rl, question) {
6298
6409
  rl.pause();
6299
6410
  rlAny.output = savedOutput;
6300
6411
  askUserContext.prompting = false;
6301
- resolve5(answer);
6412
+ resolve6(answer);
6302
6413
  };
6303
6414
  const onLine = (line) => {
6304
6415
  cleanup(line);
@@ -6790,7 +6901,7 @@ var spawnAgentTool = {
6790
6901
 
6791
6902
  // src/tools/registry.ts
6792
6903
  import { pathToFileURL } from "url";
6793
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync7 } from "fs";
6904
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readdirSync as readdirSync8 } from "fs";
6794
6905
  import { join as join10 } from "path";
6795
6906
  var ToolRegistry = class {
6796
6907
  tools = /* @__PURE__ */ new Map();
@@ -6873,7 +6984,7 @@ var ToolRegistry = class {
6873
6984
  }
6874
6985
  let files;
6875
6986
  try {
6876
- files = readdirSync7(pluginsDir).filter((f) => f.endsWith(".js"));
6987
+ files = readdirSync8(pluginsDir).filter((f) => f.endsWith(".js"));
6877
6988
  } catch {
6878
6989
  return 0;
6879
6990
  }
@@ -6927,7 +7038,7 @@ import chalk9 from "chalk";
6927
7038
  import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
6928
7039
 
6929
7040
  // src/tools/hooks.ts
6930
- import { execSync as execSync5 } from "child_process";
7041
+ import { execSync as execSync6 } from "child_process";
6931
7042
  function runHook(template, vars) {
6932
7043
  if (!template) return;
6933
7044
  let cmd = template;
@@ -6936,7 +7047,7 @@ function runHook(template, vars) {
6936
7047
  cmd = cmd.replace(/\{args\}/g, vars.args ?? "");
6937
7048
  cmd = cmd.replace(/\{status\}/g, vars.status ?? "");
6938
7049
  try {
6939
- execSync5(cmd, {
7050
+ execSync6(cmd, {
6940
7051
  timeout: 5e3,
6941
7052
  stdio: ["pipe", "pipe", "pipe"],
6942
7053
  encoding: "utf-8"
@@ -7197,7 +7308,7 @@ var ToolExecutor = class {
7197
7308
  rl.resume();
7198
7309
  process.stdout.write(prompt);
7199
7310
  this.confirming = true;
7200
- return new Promise((resolve5) => {
7311
+ return new Promise((resolve6) => {
7201
7312
  let completed = false;
7202
7313
  const cleanup = (result) => {
7203
7314
  if (completed) return;
@@ -7207,7 +7318,7 @@ var ToolExecutor = class {
7207
7318
  rl.pause();
7208
7319
  rlAny.output = savedOutput;
7209
7320
  this.confirming = false;
7210
- resolve5(result);
7321
+ resolve6(result);
7211
7322
  };
7212
7323
  const onLine = (line) => {
7213
7324
  const input2 = line.trim().toLowerCase();
@@ -7368,7 +7479,7 @@ var ToolExecutor = class {
7368
7479
  rl.resume();
7369
7480
  process.stdout.write(color("Proceed? [y/N] (type y + Enter to confirm) "));
7370
7481
  this.confirming = true;
7371
- return new Promise((resolve5) => {
7482
+ return new Promise((resolve6) => {
7372
7483
  let completed = false;
7373
7484
  const cleanup = (answer) => {
7374
7485
  if (completed) return;
@@ -7378,7 +7489,7 @@ var ToolExecutor = class {
7378
7489
  rl.pause();
7379
7490
  rlAny.output = savedOutput;
7380
7491
  this.confirming = false;
7381
- resolve5(answer === "y");
7492
+ resolve6(answer === "y");
7382
7493
  };
7383
7494
  const onLine = (line) => {
7384
7495
  cleanup(line.trim().toLowerCase());
@@ -7633,9 +7744,9 @@ Managing ${displayName} API Key`);
7633
7744
  };
7634
7745
 
7635
7746
  // src/repl/custom-commands.ts
7636
- import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync8, mkdirSync as mkdirSync9 } from "fs";
7747
+ import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync9, mkdirSync as mkdirSync9 } from "fs";
7637
7748
  import { join as join11, extname as extname3 } from "path";
7638
- import { execSync as execSync6 } from "child_process";
7749
+ import { execSync as execSync7 } from "child_process";
7639
7750
  function parseSimpleYaml(text) {
7640
7751
  const result = {};
7641
7752
  for (const line of text.split("\n")) {
@@ -7680,7 +7791,7 @@ function expandTemplate(template, args) {
7680
7791
  });
7681
7792
  result = result.replace(/\{\{git-diff\}\}/g, () => {
7682
7793
  try {
7683
- return execSync6("git diff", { encoding: "utf-8", timeout: 1e4 }).trim();
7794
+ return execSync7("git diff", { encoding: "utf-8", timeout: 1e4 }).trim();
7684
7795
  } catch {
7685
7796
  return "[No git diff available]";
7686
7797
  }
@@ -7703,7 +7814,7 @@ var CustomCommandManager = class {
7703
7814
  return 0;
7704
7815
  }
7705
7816
  let count = 0;
7706
- for (const file of readdirSync8(this.commandsDir)) {
7817
+ for (const file of readdirSync9(this.commandsDir)) {
7707
7818
  if (extname3(file) !== ".md") continue;
7708
7819
  const cmd = parseCommandFile(join11(this.commandsDir, file));
7709
7820
  if (cmd) {
@@ -7930,7 +8041,7 @@ var McpClient = class {
7930
8041
  // 内部方法:JSON-RPC 通信
7931
8042
  // ══════════════════════════════════════════════════════════════════
7932
8043
  sendRequest(method, params) {
7933
- return new Promise((resolve5, reject) => {
8044
+ return new Promise((resolve6, reject) => {
7934
8045
  if (!this.process?.stdin?.writable) {
7935
8046
  return reject(new Error(`MCP server [${this.serverId}] stdin not writable`));
7936
8047
  }
@@ -7953,7 +8064,7 @@ var McpClient = class {
7953
8064
  this.pendingRequests.set(id, {
7954
8065
  resolve: (result) => {
7955
8066
  cleanup();
7956
- resolve5(result);
8067
+ resolve6(result);
7957
8068
  },
7958
8069
  reject: (error) => {
7959
8070
  cleanup();
@@ -8024,13 +8135,13 @@ var McpClient = class {
8024
8135
  }
8025
8136
  /** Promise 超时包装 */
8026
8137
  withTimeout(promise, ms, label) {
8027
- return new Promise((resolve5, reject) => {
8138
+ return new Promise((resolve6, reject) => {
8028
8139
  const timer = setTimeout(() => {
8029
8140
  reject(new Error(`MCP [${this.serverId}] ${label} timed out after ${ms}ms`));
8030
8141
  }, ms);
8031
8142
  promise.then((val) => {
8032
8143
  clearTimeout(timer);
8033
- resolve5(val);
8144
+ resolve6(val);
8034
8145
  }).catch((err) => {
8035
8146
  clearTimeout(timer);
8036
8147
  reject(err);
@@ -8295,12 +8406,12 @@ var McpManager = class {
8295
8406
  };
8296
8407
 
8297
8408
  // src/skills/manager.ts
8298
- import { existsSync as existsSync18, readdirSync as readdirSync9, mkdirSync as mkdirSync11 } from "fs";
8409
+ import { existsSync as existsSync18, readdirSync as readdirSync10, mkdirSync as mkdirSync11 } from "fs";
8299
8410
  import { join as join13 } from "path";
8300
8411
 
8301
8412
  // src/skills/types.ts
8302
8413
  import { readFileSync as readFileSync12 } from "fs";
8303
- import { basename as basename4 } from "path";
8414
+ import { basename as basename5 } from "path";
8304
8415
  function parseSimpleYaml2(yaml) {
8305
8416
  const result = {};
8306
8417
  for (const line of yaml.split("\n")) {
@@ -8329,7 +8440,7 @@ function parseSkillFile(filePath) {
8329
8440
  if (!frontmatterMatch) {
8330
8441
  return {
8331
8442
  meta: {
8332
- name: basename4(filePath, ".md"),
8443
+ name: basename5(filePath, ".md"),
8333
8444
  description: ""
8334
8445
  },
8335
8446
  content: raw.trim(),
@@ -8340,7 +8451,7 @@ function parseSkillFile(filePath) {
8340
8451
  const parsed = parseSimpleYaml2(yaml);
8341
8452
  return {
8342
8453
  meta: {
8343
- name: parsed["name"] ?? basename4(filePath, ".md"),
8454
+ name: parsed["name"] ?? basename5(filePath, ".md"),
8344
8455
  description: parsed["description"] ?? "",
8345
8456
  tools: parsed["tools"] ? parseYamlArray(parsed["tools"]) : void 0
8346
8457
  },
@@ -8370,7 +8481,7 @@ var SkillManager = class {
8370
8481
  }
8371
8482
  let entries;
8372
8483
  try {
8373
- entries = readdirSync9(this.skillsDir);
8484
+ entries = readdirSync10(this.skillsDir);
8374
8485
  } catch {
8375
8486
  return 0;
8376
8487
  }
@@ -8481,7 +8592,7 @@ function parseAtReferences(input2, cwd) {
8481
8592
  let match;
8482
8593
  while ((match = atPattern.exec(input2)) !== null) {
8483
8594
  const rawPath = match[1] ?? match[2] ?? match[3] ?? "";
8484
- const absPath = resolve4(cwd, rawPath);
8595
+ const absPath = resolve5(cwd, rawPath);
8485
8596
  const ext = extname4(rawPath).toLowerCase();
8486
8597
  const mime = IMAGE_MIME[ext];
8487
8598
  if (!existsSync19(absPath)) {
@@ -8687,7 +8798,7 @@ var Repl = class {
8687
8798
  if (depth > 2 || entryCount >= MAX_TREE_ENTRIES) return;
8688
8799
  let entries;
8689
8800
  try {
8690
- entries = readdirSync10(dir);
8801
+ entries = readdirSync11(dir);
8691
8802
  } catch {
8692
8803
  return;
8693
8804
  }
@@ -8721,7 +8832,7 @@ ${treeLines.join("\n")}`
8721
8832
  if (totalChars >= MAX_TOTAL_CHARS) return;
8722
8833
  let entries;
8723
8834
  try {
8724
- entries = readdirSync10(dir);
8835
+ entries = readdirSync11(dir);
8725
8836
  } catch {
8726
8837
  return;
8727
8838
  }
@@ -8772,7 +8883,7 @@ ${content}
8772
8883
  * 已添加时返回 added=false(无重复添加)。
8773
8884
  */
8774
8885
  addExtraContextDir(dirPath) {
8775
- const absPath = resolve4(dirPath);
8886
+ const absPath = resolve5(dirPath);
8776
8887
  if (!existsSync19(absPath)) {
8777
8888
  return { success: false, charCount: 0, added: false, error: `Directory not found: ${dirPath}` };
8778
8889
  }
@@ -8795,7 +8906,7 @@ ${content}
8795
8906
  }
8796
8907
  /** 从额外上下文中移除目录。返回 true 表示成功移除,false 表示未找到。 */
8797
8908
  removeExtraContextDir(dirPath) {
8798
- const absPath = resolve4(dirPath);
8909
+ const absPath = resolve5(dirPath);
8799
8910
  const idx = this.extraContextDirs.findIndex((d) => d.dir === absPath);
8800
8911
  if (idx === -1) return false;
8801
8912
  this.extraContextDirs.splice(idx, 1);
@@ -8878,8 +8989,8 @@ ${content}
8878
8989
  if (setting === false) return { layers: [], mergedContent: "" };
8879
8990
  const cwd = process.cwd();
8880
8991
  if (setting !== "auto") {
8881
- const fullPath = resolve4(cwd, String(setting));
8882
- if (!fullPath.startsWith(resolve4(cwd))) {
8992
+ const fullPath = resolve5(cwd, String(setting));
8993
+ if (!fullPath.startsWith(resolve5(cwd))) {
8883
8994
  process.stderr.write(
8884
8995
  `[Warning] contextFile path "${setting}" is outside current directory, ignoring.
8885
8996
  `
@@ -8922,8 +9033,8 @@ ${content}
8922
9033
  charCount: projectCtx.content.length
8923
9034
  });
8924
9035
  }
8925
- const normalizedCwd = resolve4(cwd);
8926
- const normalizedRoot = resolve4(projectRoot);
9036
+ const normalizedCwd = resolve5(cwd);
9037
+ const normalizedRoot = resolve5(projectRoot);
8927
9038
  if (normalizedCwd !== normalizedRoot) {
8928
9039
  const localCtx = this.findContextFile(cwd);
8929
9040
  if (localCtx) {
@@ -9329,7 +9440,7 @@ Session '${this.resumeSessionId}' not found.
9329
9440
  this.handleExit();
9330
9441
  });
9331
9442
  this.showPrompt();
9332
- await new Promise((resolve5) => {
9443
+ await new Promise((resolve6) => {
9333
9444
  let processing = false;
9334
9445
  this.rl.on("line", async (line) => {
9335
9446
  if (this.toolExecutor.confirming) return;
@@ -9364,13 +9475,13 @@ Session '${this.resumeSessionId}' not found.
9364
9475
  process.stdin.resume();
9365
9476
  this.showPrompt();
9366
9477
  } else {
9367
- resolve5();
9478
+ resolve6();
9368
9479
  }
9369
9480
  }
9370
9481
  });
9371
9482
  this.rl.on("close", () => {
9372
9483
  if (!processing) {
9373
- resolve5();
9484
+ resolve6();
9374
9485
  }
9375
9486
  });
9376
9487
  });
@@ -9645,11 +9756,11 @@ Session '${this.resumeSessionId}' not found.
9645
9756
  completeFilePath(partial) {
9646
9757
  try {
9647
9758
  const normalized = partial.replace(/\\/g, "/");
9648
- const dir = normalized.includes("/") ? dirname5(normalized) : ".";
9649
- const prefix = normalized.includes("/") ? basename5(normalized) : normalized;
9650
- const absDir = resolve4(process.cwd(), dir);
9759
+ const dir = normalized.includes("/") ? dirname6(normalized) : ".";
9760
+ const prefix = normalized.includes("/") ? basename6(normalized) : normalized;
9761
+ const absDir = resolve5(process.cwd(), dir);
9651
9762
  if (!existsSync19(absDir)) return [];
9652
- const entries = readdirSync10(absDir);
9763
+ const entries = readdirSync11(absDir);
9653
9764
  const results = [];
9654
9765
  for (const entry of entries) {
9655
9766
  if (entry.startsWith(".")) continue;
@@ -10315,10 +10426,10 @@ async function setupProxy(configProxy) {
10315
10426
  }
10316
10427
  async function readStdin() {
10317
10428
  if (process.stdin.isTTY) return "";
10318
- return new Promise((resolve5, reject) => {
10429
+ return new Promise((resolve6, reject) => {
10319
10430
  const chunks = [];
10320
10431
  process.stdin.on("data", (chunk) => chunks.push(chunk));
10321
- process.stdin.on("end", () => resolve5(Buffer.concat(chunks).toString("utf-8").trimEnd()));
10432
+ process.stdin.on("end", () => resolve6(Buffer.concat(chunks).toString("utf-8").trimEnd()));
10322
10433
  process.stdin.on("error", reject);
10323
10434
  });
10324
10435
  }
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-XDSNK7WW.js";
5
+ } from "./chunk-P4XKHPXU.js";
6
6
  export {
7
7
  executeTests,
8
8
  runTestsTool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.1.48",
3
+ "version": "0.1.49",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",