jinzd-ai-cli 0.4.71 → 0.4.73

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.
@@ -1,330 +1,24 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ schemaToJsonSchema,
4
+ truncateForPersist
5
+ } from "./chunk-H65WPFDO.js";
2
6
  import {
3
7
  AuthError,
4
- ConfigError,
5
- EnvLoader,
6
8
  ProviderError,
7
9
  ProviderNotFoundError,
8
- RateLimitError,
9
- schemaToJsonSchema,
10
- truncateForPersist
11
- } from "./chunk-UHZ6YANH.js";
10
+ RateLimitError
11
+ } from "./chunk-2ZD3YTVM.js";
12
12
  import {
13
13
  APP_NAME,
14
14
  CONFIG_DIR_NAME,
15
- CONFIG_FILE_NAME,
16
15
  DEV_STATE_FILE_NAME,
17
- HISTORY_DIR_NAME,
18
16
  MCP_CALL_TIMEOUT,
19
17
  MCP_CONNECT_TIMEOUT,
20
18
  MCP_PROTOCOL_VERSION,
21
19
  MCP_TOOL_PREFIX,
22
- PLUGINS_DIR_NAME,
23
20
  VERSION
24
- } from "./chunk-6OKAZIY7.js";
25
-
26
- // src/config/config-manager.ts
27
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
28
- import { join } from "path";
29
- import { homedir } from "os";
30
-
31
- // src/config/schema.ts
32
- import { z } from "zod";
33
- var CustomModelSchema = z.object({
34
- id: z.string(),
35
- displayName: z.string().optional(),
36
- contextWindow: z.number().optional()
37
- });
38
- var CustomProviderConfigSchema = z.object({
39
- id: z.string(),
40
- // 唯一 ID,不能与内置 provider 重名
41
- displayName: z.string(),
42
- // 显示名称
43
- apiKey: z.string().optional(),
44
- // 可选:直接在此写 key(也可通过 apiKeys 字段或环境变量提供)
45
- baseUrl: z.string(),
46
- // OpenAI 兼容 API 的 base URL(必填)
47
- defaultModel: z.string(),
48
- // 默认使用的模型 ID
49
- models: z.array(CustomModelSchema).default([]),
50
- timeout: z.number().optional()
51
- // 请求超时(ms),覆盖全局默认值
52
- });
53
- var ModelParamsSchema = z.object({
54
- temperature: z.number().min(0).max(2).optional(),
55
- maxTokens: z.number().int().positive().optional(),
56
- timeout: z.number().int().positive().optional(),
57
- /** 是否启用深度思考(thinking)模式,Claude Sonnet/Opus、GLM-5 等 */
58
- thinking: z.boolean().optional(),
59
- /** thinking 模式的 token 预算(最小 1024,仅 Claude Extended Thinking 使用) */
60
- thinkingBudget: z.number().int().min(1024).optional()
61
- });
62
- var UserProfileSchema = z.object({
63
- /** 真实姓名(如 "Jin Zhengdong") */
64
- name: z.string().optional(),
65
- /** 昵称/称呼偏好(如 "东叔"),AI 会以此称呼你 */
66
- nickname: z.string().optional(),
67
- /** 职业角色(如 "Full-stack developer"、"Data scientist") */
68
- role: z.string().optional(),
69
- /** 个人简介 / 专长描述(1-3 句话) */
70
- bio: z.string().optional(),
71
- /** 兴趣领域或技术栈(如 ["TypeScript", "Rust", "AI/ML"]) */
72
- interests: z.array(z.string()).default([]),
73
- /** 语言偏好(如 "zh-CN"、"en"),AI 将据此选择交流语言 */
74
- locale: z.string().optional(),
75
- /** 自定义人设补充(自由格式,直接注入 system prompt) */
76
- extra: z.string().optional()
77
- }).default({});
78
- var ConfigSchema = z.object({
79
- version: z.string().default("1.0.0"),
80
- // 用户身份档案 — 跨 Provider 的 "灵魂"
81
- userProfile: UserProfileSchema,
82
- defaultProvider: z.string().default("claude"),
83
- // 每个 provider 的默认模型(key 为 provider ID)
84
- defaultModels: z.record(z.string()).default({}),
85
- // API Keys:放宽为任意 record,支持自定义 provider ID
86
- apiKeys: z.record(z.string()).default({}),
87
- customBaseUrls: z.record(z.string()).default({}),
88
- // Per-provider timeout in ms (e.g. { deepseek: 60000 })
89
- // ⚠️ Timeout 优先级说明(L5):
90
- // 1. modelParams[modelId].timeout — 最高优先级,精确到具体模型(如 deepseek-reasoner 需要更长超时)
91
- // 2. timeouts[providerId] — Provider 级默认,覆盖内置默认值
92
- // 3. 内置 Provider 的硬编码默认值 — 最低兜底(如 OpenAI 兼容系列默认 60000ms)
93
- // 实现位置:src/providers/registry.ts initialize(),将 timeouts[id] 注入 provider
94
- timeouts: z.record(z.number()).default({}),
95
- // HTTP/HTTPS 代理地址(Node.js 不自动使用系统代理,需显式配置)
96
- // 例:http://127.0.0.1:10809
97
- // 也可通过环境变量 HTTPS_PROXY / HTTP_PROXY 覆盖
98
- proxy: z.string().optional(),
99
- // 自定义 Provider 列表(OpenAI 兼容接口,无需改代码)
100
- customProviders: z.array(CustomProviderConfigSchema).default([]),
101
- // 按模型 ID 存储的推理参数(key 为模型 ID,如 "deepseek-chat")
102
- modelParams: z.record(ModelParamsSchema).default({}),
103
- ui: z.object({
104
- streaming: z.boolean().default(true),
105
- markdownRendering: z.boolean().default(true),
106
- showTokenCount: z.boolean().default(true),
107
- /** 桌面通知阈值(毫秒):AI 任务耗时超过此值时发送系统通知。0 = 禁用。默认 10000 (10s) */
108
- notificationThreshold: z.number().default(1e4),
109
- /** 终端输出折行宽度。0 = 自动(使用终端宽度),>0 = 固定列宽。默认 0 */
110
- wordWrap: z.number().int().min(0).default(0),
111
- /** 颜色主题:'dark'(默认)| 'light' | 'custom' */
112
- theme: z.enum(["dark", "light", "custom"]).default("dark"),
113
- /** 自定义颜色覆盖(仅在 theme='custom' 时生效)。值为 chalk 颜色名或 '#hex',支持 'bold.cyan' 组合 */
114
- colors: z.object({
115
- prompt: z.string().optional(),
116
- info: z.string().optional(),
117
- warning: z.string().optional(),
118
- error: z.string().optional(),
119
- success: z.string().optional(),
120
- dim: z.string().optional(),
121
- accent: z.string().optional(),
122
- toolCall: z.string().optional(),
123
- toolResult: z.string().optional(),
124
- heading: z.string().optional()
125
- }).optional()
126
- }).default({}),
127
- session: z.object({
128
- autoSave: z.boolean().default(true),
129
- maxHistoryDays: z.number().default(30),
130
- systemPrompt: z.string().optional()
131
- }).default({}),
132
- // 项目上下文文件配置
133
- // 启动时自动读取并注入 system prompt,类似 Claude Code 的 CLAUDE.md 机制
134
- // 默认按顺序查找:AICLI.md → CLAUDE.md → .aicli/context.md
135
- // 设为 false 可禁用此功能
136
- contextFile: z.union([z.string(), z.literal(false)]).default("auto"),
137
- // Google Custom Search API 的 Search Engine ID (cx 参数)
138
- // API Key 通过 apiKeys['google-search'] 或 AICLI_API_KEY_GOOGLESEARCH 环境变量配置
139
- // CX 也可通过 AICLI_GOOGLE_CX 环境变量覆盖
140
- googleSearchEngineId: z.string().optional(),
141
- // MCP (Model Context Protocol) 服务器配置
142
- // 声明外部 MCP 服务器,启动时自动连接、发现工具并注册
143
- // 配置格式兼容 Claude Desktop(command + args + env)
144
- // 示例:{ "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"] } }
145
- mcpServers: z.record(z.object({
146
- command: z.string(),
147
- args: z.array(z.string()).default([]),
148
- env: z.record(z.string()).optional(),
149
- timeout: z.number().default(3e4)
150
- })).default({}),
151
- // 工具执行钩子(shell 命令,模板变量:{tool} {dangerLevel} {args} {status})
152
- hooks: z.object({
153
- preToolExecution: z.string().optional(),
154
- postToolExecution: z.string().optional()
155
- }).optional(),
156
- // 工具权限规则(按顺序匹配第一个生效)
157
- permissionRules: z.array(z.object({
158
- tool: z.string(),
159
- action: z.enum(["auto-approve", "deny", "confirm"]),
160
- when: z.object({
161
- dangerLevel: z.enum(["safe", "write", "destructive"]).optional(),
162
- pathPattern: z.string().optional()
163
- }).optional()
164
- })).default([]),
165
- // 无规则匹配时的默认权限动作
166
- defaultPermission: z.enum(["auto-approve", "deny", "confirm"]).default("confirm"),
167
- // 自动上下文压缩开关
168
- // 当对话估算 token 数超过模型 contextWindow 的 80% 时,自动触发 compact 压缩旧消息
169
- // 默认开启。设为 false 则仅在手动 /compact 时压缩
170
- autoCompact: z.boolean().default(true),
171
- // Agentic 工具调用循环单次对话最大轮次(默认 200)。
172
- // 超过此值后 AI 被强制停止调用工具并生成总结。
173
- // 建议范围:25(保守)~ 1000(宽松,接近 Claude Code)。
174
- // CLI `--max-tool-rounds <n>` 可覆盖此值。
175
- maxToolRounds: z.number().int().min(1).max(1e4).default(200),
176
- // Auto-pause checkpoint:Agentic 循环每隔多少轮暂停一次,让用户确认方向或中途介入。
177
- // 默认 50;设为 0 禁用(完全自动执行到完成或 maxToolRounds 用尽)。
178
- // CLI 与 Web UI 行为一致:CLI 用 readline question 提示,Web UI 弹出对话框。
179
- autoPauseInterval: z.number().int().min(0).max(1e4).default(50),
180
- // 单次工具输出(如 read_file、bash、grep_files)返回给 AI 的最大字符数上限。
181
- // 默认 500_000 (~500K chars ≈ 6000-8000 行代码)。
182
- // 实际上限还会受模型 contextWindow 动态约束(取 contextWindow/4 作为下限)。
183
- // 设置为 0 或未配置时使用默认值;不建议设为小于 12_000 或大于模型 contextWindow/2。
184
- maxToolOutputChars: z.number().int().min(0).default(5e5),
185
- // 月度成本预算(USD)。
186
- // 设置后,每次 AI 回复后会跟踪成本,接近或超过预算时在 /status 和 /cost 中显示警告。
187
- // 默认 0 = 不限制。例:50 表示每月最多花 $50。
188
- monthlyBudget: z.number().min(0).default(0),
189
- // 插件加载开关(安全控制)
190
- // 默认 false:不自动加载 ~/.aicli/plugins/ 中的插件文件。
191
- // 插件以完整 Node.js 权限在主进程中执行(可读写文件、访问网络、执行命令),
192
- // 必须确认插件来源可信后,再设为 true 启用。
193
- // 可通过 /config 命令或直接编辑 ~/.aicli/config.json 开启。
194
- allowPlugins: z.boolean().default(false),
195
- // 智能模型路由(v0.4.68+)
196
- // 按用户每轮输入的内容/标签/长度动态选择模型,在同一 provider 内切换,
197
- // 例:短问题走 haiku(省钱),planning 走 opus(质量)。
198
- // enabled=false 时永远返回当前模型。rules 按顺序匹配,首个命中的规则生效。
199
- // 每个 rule 的 match 必须至少有一个条件(tag/contains/maxLength/minLength)。
200
- // 详见 src/core/model-router.ts。
201
- routing: z.object({
202
- enabled: z.boolean().default(false),
203
- rules: z.array(z.object({
204
- match: z.object({
205
- contains: z.array(z.string()).optional(),
206
- maxLength: z.number().int().positive().optional(),
207
- minLength: z.number().int().positive().optional(),
208
- tag: z.string().optional()
209
- }),
210
- model: z.string(),
211
- name: z.string().optional()
212
- })).default([]),
213
- fallback: z.string().optional()
214
- }).default({ enabled: false, rules: [] })
215
- });
216
-
217
- // src/config/config-manager.ts
218
- var ConfigManager = class {
219
- configDir;
220
- configPath;
221
- config;
222
- constructor(configDir) {
223
- this.configDir = configDir ?? join(homedir(), CONFIG_DIR_NAME);
224
- this.configPath = join(this.configDir, CONFIG_FILE_NAME);
225
- this.config = this.load();
226
- }
227
- load() {
228
- if (!existsSync(this.configPath)) {
229
- return ConfigSchema.parse({});
230
- }
231
- try {
232
- const raw = JSON.parse(readFileSync(this.configPath, "utf-8"));
233
- return ConfigSchema.parse(raw);
234
- } catch (err) {
235
- throw new ConfigError(
236
- `Config file at ${this.configPath} is invalid. Delete it and run 'ai-cli config' to recreate.
237
- ${err}`
238
- );
239
- }
240
- }
241
- save() {
242
- mkdirSync(this.configDir, { recursive: true });
243
- writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), "utf-8");
244
- }
245
- getApiKey(providerId) {
246
- const envKey = EnvLoader.getApiKey(providerId);
247
- if (envKey) return envKey;
248
- return this.config.apiKeys[providerId];
249
- }
250
- setApiKey(providerId, key) {
251
- this.config.apiKeys[providerId] = key;
252
- this.save();
253
- }
254
- get(key) {
255
- return this.config[key];
256
- }
257
- set(key, value) {
258
- this.config[key] = value;
259
- this.save();
260
- }
261
- /**
262
- * 仅修改内存中的配置值,不持久化到磁盘。
263
- * 用于 CLI 命令行参数覆盖(-p, -m, --no-stream),使其只对当前进程生效。
264
- */
265
- setTransient(key, value) {
266
- this.config[key] = value;
267
- }
268
- isFirstRun() {
269
- return !existsSync(this.configPath);
270
- }
271
- getConfigDir() {
272
- return this.configDir;
273
- }
274
- getHistoryDir() {
275
- return join(this.configDir, HISTORY_DIR_NAME);
276
- }
277
- getPluginsDir() {
278
- return join(this.configDir, PLUGINS_DIR_NAME);
279
- }
280
- getDefaultProvider() {
281
- return EnvLoader.getDefaultProvider() ?? this.config.defaultProvider;
282
- }
283
- /** 点分路径读取配置值,如 `ui.theme` → config.ui.theme */
284
- getByPath(path) {
285
- const keys = path.split(".");
286
- let current = this.config;
287
- for (const key of keys) {
288
- if (current == null || typeof current !== "object") return void 0;
289
- current = current[key];
290
- }
291
- return current;
292
- }
293
- /** 点分路径写入配置值,自动类型转换(boolean/number/string)并持久化 */
294
- setByPath(path, rawValue) {
295
- const keys = path.split(".");
296
- if (keys.length === 0) return;
297
- let value = rawValue;
298
- if (rawValue === "true") value = true;
299
- else if (rawValue === "false") value = false;
300
- else if (rawValue !== "" && !isNaN(Number(rawValue))) value = Number(rawValue);
301
- const draft = JSON.parse(JSON.stringify(this.config));
302
- let current = draft;
303
- for (let i = 0; i < keys.length - 1; i++) {
304
- const key = keys[i];
305
- if (current[key] == null || typeof current[key] !== "object") {
306
- current[key] = {};
307
- }
308
- current = current[key];
309
- }
310
- current[keys[keys.length - 1]] = value;
311
- const result = ConfigSchema.safeParse(draft);
312
- if (!result.success) {
313
- const firstErr = result.error.errors[0];
314
- throw new ConfigError(`Invalid config value for "${path}": ${firstErr?.message ?? "validation failed"}`);
315
- }
316
- this.config = result.data;
317
- this.save();
318
- }
319
- /** 获取完整配置对象的格式化 JSON 字符串(用于 /config show 等展示) */
320
- toFormattedJSON() {
321
- return JSON.stringify(this.config, null, 2);
322
- }
323
- /** 获取完整配置对象(JSON 兼容的原始对象) */
324
- toJSON() {
325
- return structuredClone(this.config);
326
- }
327
- };
21
+ } from "./chunk-T2OUKQOX.js";
328
22
 
329
23
  // src/providers/claude.ts
330
24
  import Anthropic from "@anthropic-ai/sdk";
@@ -2427,8 +2121,8 @@ var ProviderRegistry = class {
2427
2121
  };
2428
2122
 
2429
2123
  // src/session/session-manager.ts
2430
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, unlinkSync, renameSync, openSync, readSync, closeSync } from "fs";
2431
- import { join as join2 } from "path";
2124
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, unlinkSync, renameSync, openSync, readSync, closeSync } from "fs";
2125
+ import { join } from "path";
2432
2126
  import { v4 as uuidv4 } from "uuid";
2433
2127
 
2434
2128
  // src/core/types.ts
@@ -2707,20 +2401,20 @@ var SessionManager = class {
2707
2401
  }
2708
2402
  async save() {
2709
2403
  if (!this._current) return;
2710
- mkdirSync2(this.historyDir, { recursive: true });
2711
- const filePath = join2(this.historyDir, `${this._current.id}.json`);
2404
+ mkdirSync(this.historyDir, { recursive: true });
2405
+ const filePath = join(this.historyDir, `${this._current.id}.json`);
2712
2406
  const tmpPath = filePath + ".tmp";
2713
- writeFileSync2(tmpPath, JSON.stringify(this._current.toJSON(), null, 2), "utf-8");
2407
+ writeFileSync(tmpPath, JSON.stringify(this._current.toJSON(), null, 2), "utf-8");
2714
2408
  renameSync(tmpPath, filePath);
2715
2409
  }
2716
2410
  loadSession(id) {
2717
- const filePath = join2(this.historyDir, `${id}.json`);
2718
- if (!existsSync2(filePath)) {
2411
+ const filePath = join(this.historyDir, `${id}.json`);
2412
+ if (!existsSync(filePath)) {
2719
2413
  throw new Error(`Session ${id} not found`);
2720
2414
  }
2721
2415
  let data;
2722
2416
  try {
2723
- data = JSON.parse(readFileSync2(filePath, "utf-8"));
2417
+ data = JSON.parse(readFileSync(filePath, "utf-8"));
2724
2418
  } catch (err) {
2725
2419
  throw new Error(`Session ${id} is corrupted: ${err instanceof Error ? err.message : String(err)}`);
2726
2420
  }
@@ -2729,12 +2423,12 @@ var SessionManager = class {
2729
2423
  return session;
2730
2424
  }
2731
2425
  listSessions() {
2732
- if (!existsSync2(this.historyDir)) return [];
2426
+ if (!existsSync(this.historyDir)) return [];
2733
2427
  const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json"));
2734
2428
  const metas = [];
2735
2429
  for (const file of files) {
2736
2430
  try {
2737
- const meta = this.readSessionMeta(join2(this.historyDir, file));
2431
+ const meta = this.readSessionMeta(join(this.historyDir, file));
2738
2432
  if (meta) metas.push(meta);
2739
2433
  } catch (err) {
2740
2434
  process.stderr.write(
@@ -2772,7 +2466,7 @@ var SessionManager = class {
2772
2466
  if (id && provider && model) {
2773
2467
  let messageCount = 0;
2774
2468
  try {
2775
- const full = readFileSync2(filePath, "utf-8");
2469
+ const full = readFileSync(filePath, "utf-8");
2776
2470
  const matches = full.match(/"role"\s*:/g);
2777
2471
  messageCount = matches ? matches.length : 0;
2778
2472
  } catch {
@@ -2787,7 +2481,7 @@ var SessionManager = class {
2787
2481
  title: title || void 0
2788
2482
  };
2789
2483
  }
2790
- const data = JSON.parse(readFileSync2(filePath, "utf-8"));
2484
+ const data = JSON.parse(readFileSync(filePath, "utf-8"));
2791
2485
  return {
2792
2486
  id: data.id,
2793
2487
  provider: data.provider,
@@ -2799,8 +2493,8 @@ var SessionManager = class {
2799
2493
  };
2800
2494
  }
2801
2495
  deleteSession(id) {
2802
- const filePath = join2(this.historyDir, `${id}.json`);
2803
- if (!existsSync2(filePath)) return false;
2496
+ const filePath = join(this.historyDir, `${id}.json`);
2497
+ if (!existsSync(filePath)) return false;
2804
2498
  try {
2805
2499
  unlinkSync(filePath);
2806
2500
  if (this._current && this._current.id === id) {
@@ -2837,14 +2531,14 @@ var SessionManager = class {
2837
2531
  * 每个 session 最多返回 3 条匹配片段,全局最多 maxResults 个 session。
2838
2532
  */
2839
2533
  searchMessages(query, maxResults = 20) {
2840
- if (!existsSync2(this.historyDir)) return [];
2534
+ if (!existsSync(this.historyDir)) return [];
2841
2535
  const q = query.toLowerCase();
2842
- const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json")).map((f) => join2(this.historyDir, f));
2536
+ const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json")).map((f) => join(this.historyDir, f));
2843
2537
  const results = [];
2844
2538
  for (const filePath of files) {
2845
2539
  if (results.length >= maxResults) break;
2846
2540
  try {
2847
- const data = JSON.parse(readFileSync2(filePath, "utf-8"));
2541
+ const data = JSON.parse(readFileSync(filePath, "utf-8"));
2848
2542
  const messages = data.messages ?? [];
2849
2543
  const matches = [];
2850
2544
  for (const msg of messages) {
@@ -2891,8 +2585,8 @@ var SessionManager = class {
2891
2585
 
2892
2586
  // src/tools/git-context.ts
2893
2587
  import { execSync } from "child_process";
2894
- import { existsSync as existsSync3 } from "fs";
2895
- import { join as join3 } from "path";
2588
+ import { existsSync as existsSync2 } from "fs";
2589
+ import { join as join2 } from "path";
2896
2590
  function runGit(cmd, cwd) {
2897
2591
  try {
2898
2592
  return execSync(`git ${cmd}`, {
@@ -2909,7 +2603,7 @@ function getGitRoot(cwd = process.cwd()) {
2909
2603
  return runGit("rev-parse --show-toplevel", cwd);
2910
2604
  }
2911
2605
  function getGitContext(cwd = process.cwd()) {
2912
- if (!existsSync3(join3(cwd, ".git"))) {
2606
+ if (!existsSync2(join2(cwd, ".git"))) {
2913
2607
  const result = runGit("rev-parse --git-dir", cwd);
2914
2608
  if (!result) return null;
2915
2609
  }
@@ -3489,11 +3183,11 @@ var McpManager = class {
3489
3183
  };
3490
3184
 
3491
3185
  // src/skills/manager.ts
3492
- import { existsSync as existsSync4, readdirSync as readdirSync2, mkdirSync as mkdirSync3, statSync } from "fs";
3493
- import { join as join4 } from "path";
3186
+ import { existsSync as existsSync3, readdirSync as readdirSync2, mkdirSync as mkdirSync2, statSync } from "fs";
3187
+ import { join as join3 } from "path";
3494
3188
 
3495
3189
  // src/skills/types.ts
3496
- import { readFileSync as readFileSync3 } from "fs";
3190
+ import { readFileSync as readFileSync2 } from "fs";
3497
3191
  import { basename } from "path";
3498
3192
  function parseSimpleYaml(yaml) {
3499
3193
  const result = {};
@@ -3515,7 +3209,7 @@ function parseYamlArray(value) {
3515
3209
  function parseSkillFile(filePath) {
3516
3210
  let raw;
3517
3211
  try {
3518
- raw = readFileSync3(filePath, "utf-8");
3212
+ raw = readFileSync2(filePath, "utf-8");
3519
3213
  } catch {
3520
3214
  return null;
3521
3215
  }
@@ -3555,9 +3249,9 @@ var SkillManager = class {
3555
3249
  /** 发现并加载 skillsDir 下所有 .md 文件,返回加载数量 */
3556
3250
  loadSkills() {
3557
3251
  this.skills.clear();
3558
- if (!existsSync4(this.skillsDir)) {
3252
+ if (!existsSync3(this.skillsDir)) {
3559
3253
  try {
3560
- mkdirSync3(this.skillsDir, { recursive: true });
3254
+ mkdirSync2(this.skillsDir, { recursive: true });
3561
3255
  } catch {
3562
3256
  }
3563
3257
  return 0;
@@ -3570,14 +3264,14 @@ var SkillManager = class {
3570
3264
  }
3571
3265
  for (const entry of entries) {
3572
3266
  let filePath;
3573
- const fullPath = join4(this.skillsDir, entry);
3267
+ const fullPath = join3(this.skillsDir, entry);
3574
3268
  if (entry.endsWith(".md")) {
3575
3269
  filePath = fullPath;
3576
3270
  } else {
3577
3271
  try {
3578
3272
  if (statSync(fullPath).isDirectory()) {
3579
- const skillMd = join4(fullPath, "SKILL.md");
3580
- if (existsSync4(skillMd)) {
3273
+ const skillMd = join3(fullPath, "SKILL.md");
3274
+ if (existsSync3(skillMd)) {
3581
3275
  filePath = skillMd;
3582
3276
  } else {
3583
3277
  continue;
@@ -3880,9 +3574,9 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
3880
3574
  }
3881
3575
 
3882
3576
  // src/repl/dev-state.ts
3883
- import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, mkdirSync as mkdirSync4 } from "fs";
3884
- import { join as join5 } from "path";
3885
- import { homedir as homedir2 } from "os";
3577
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3 } from "fs";
3578
+ import { join as join4 } from "path";
3579
+ import { homedir } from "os";
3886
3580
  var DEV_STATE_MAX_CHARS = 6e3;
3887
3581
  var SNAPSHOT_PROMPT = `You are about to be replaced by a different AI model. Please generate a structured development state snapshot so the next model can continue seamlessly.
3888
3582
 
@@ -3935,12 +3629,12 @@ function sessionHasMeaningfulContent(messages) {
3935
3629
  return hasUser && hasAssistant;
3936
3630
  }
3937
3631
  function getDevStatePath() {
3938
- return join5(homedir2(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
3632
+ return join4(homedir(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
3939
3633
  }
3940
3634
  function saveDevState(content) {
3941
- const configDir = join5(homedir2(), CONFIG_DIR_NAME);
3942
- if (!existsSync5(configDir)) {
3943
- mkdirSync4(configDir, { recursive: true });
3635
+ const configDir = join4(homedir(), CONFIG_DIR_NAME);
3636
+ if (!existsSync4(configDir)) {
3637
+ mkdirSync3(configDir, { recursive: true });
3944
3638
  }
3945
3639
  let trimmed = content.trim();
3946
3640
  if (trimmed.length > DEV_STATE_MAX_CHARS) {
@@ -3951,17 +3645,17 @@ function saveDevState(content) {
3951
3645
  }
3952
3646
  trimmed += "\n\n[...truncated]";
3953
3647
  }
3954
- writeFileSync3(getDevStatePath(), trimmed, "utf-8");
3648
+ writeFileSync2(getDevStatePath(), trimmed, "utf-8");
3955
3649
  }
3956
3650
  function loadDevState() {
3957
3651
  const path = getDevStatePath();
3958
- if (!existsSync5(path)) return null;
3959
- const content = readFileSync4(path, "utf-8").trim();
3652
+ if (!existsSync4(path)) return null;
3653
+ const content = readFileSync3(path, "utf-8").trim();
3960
3654
  return content || null;
3961
3655
  }
3962
3656
  function clearDevState() {
3963
3657
  const path = getDevStatePath();
3964
- if (existsSync5(path)) {
3658
+ if (existsSync4(path)) {
3965
3659
  try {
3966
3660
  unlinkSync2(path);
3967
3661
  } catch {
@@ -3970,7 +3664,6 @@ function clearDevState() {
3970
3664
  }
3971
3665
 
3972
3666
  export {
3973
- ConfigManager,
3974
3667
  detectsHallucinatedFileOp,
3975
3668
  hadPreviousWriteToolCalls,
3976
3669
  TOOL_CALL_REMINDER,
@@ -385,7 +385,7 @@ ${content}`);
385
385
  }
386
386
  }
387
387
  async function runTaskMode(config, providers, configManager, topic) {
388
- const { TaskOrchestrator } = await import("./task-orchestrator-WX5NZZJR.js");
388
+ const { TaskOrchestrator } = await import("./task-orchestrator-M7Y32LNH.js");
389
389
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
390
390
  let interrupted = false;
391
391
  const onSigint = () => {