jinzd-ai-cli 0.1.62 → 0.1.63
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
|
@@ -6,7 +6,14 @@
|
|
|
6
6
|
带有 **AI 工具调用(Agentic)** 能力,支持执行 bash 命令、读写文件、运行交互式程序、流式生成大文档。
|
|
7
7
|
代理支持(`proxy` 配置字段 + 环境变量),Gemini 完整支持(2.5 Pro/Flash,array items schema 修复)。
|
|
8
8
|
**MCP 协议支持**:可接入外部 MCP 服务器,自动发现并注册工具,无缝融入 agentic 循环。
|
|
9
|
-
设计上可扩展至 Electron/Tauri 桌面 GUI。
|
|
9
|
+
设计上可扩展至 Electron/Tauri 桌面 GUI。
|
|
10
|
+
|
|
11
|
+
> 当前代码基线(2026-03-12):
|
|
12
|
+
> - 版本:`v0.1.62`
|
|
13
|
+
> - 默认 REPL 命令:35 个
|
|
14
|
+
> - 当前注册的内置工具:17 个
|
|
15
|
+
> - `stream_to_file` 已正式接入 `ToolRegistry`
|
|
16
|
+
> - `ora` 依赖已从 `package.json` 移除,spinner 使用 `src/repl/renderer.ts` 中的自实现版本
|
|
10
17
|
|
|
11
18
|
## 技术栈
|
|
12
19
|
|
|
@@ -41,7 +48,7 @@ src/
|
|
|
41
48
|
│ ├── session.ts # Session(addMessage / clear / compact / fork / toJSON / fromJSON)
|
|
42
49
|
│ └── session-manager.ts # CRUD + forkSession for ~/.aicli/history/*.json
|
|
43
50
|
├── repl/
|
|
44
|
-
│ ├── repl.ts # 主 REPL 循环(MAX_TOOL_ROUNDS=
|
|
51
|
+
│ ├── repl.ts # 主 REPL 循环(MAX_TOOL_ROUNDS=25,handleChatWithTools agentic loop)
|
|
45
52
|
│ ├── renderer.ts # 终端输出(renderStream / renderResponse 均不加前置 \n)
|
|
46
53
|
│ ├── theme.ts # 集中式主题系统(dark/light/custom 主题 + 语义色槽 Proxy 导出)
|
|
47
54
|
│ ├── dev-state.ts # 开发状态交接(provider/model 切换时快照生成、save/load/clear)
|
|
@@ -58,7 +65,7 @@ src/
|
|
|
58
65
|
│ └── manager.ts # McpManager(多服务器管理,工具发现与注册,MCP→Tool 转换)
|
|
59
66
|
└── tools/
|
|
60
67
|
├── types.ts # ToolDefinition / ToolCall / ToolResult / DangerLevel / getDangerLevel / isFileWriteTool
|
|
61
|
-
├── registry.ts # ToolRegistry(注册全部内置工具,共
|
|
68
|
+
├── registry.ts # ToolRegistry(注册全部内置工具,共17个)
|
|
62
69
|
├── hooks.ts # 工具执行钩子(runHook,shell 命令模板替换 + execSync)
|
|
63
70
|
├── permissions.ts # 基于规则的工具权限控制(checkPermission,首匹配规则)
|
|
64
71
|
├── executor.ts # ToolExecutor(确认逻辑 + 批量文件写入预览 + batchConfirm + hooks + permissions)
|
|
@@ -71,8 +78,9 @@ src/
|
|
|
71
78
|
├── ask-user.ts # ask_user 工具(agentic 循环中向用户提问,等待文本回答)
|
|
72
79
|
├── write-todos.ts # write_todos 工具(任务拆解与进度跟踪,终端实时渲染)
|
|
73
80
|
├── google-search.ts # google_search 工具(Google Custom Search API 搜索网页)
|
|
74
|
-
├──
|
|
75
|
-
|
|
81
|
+
├── stream-to-file.ts # stream_to_file 工具(流式生成大文档并直接写入文件)
|
|
82
|
+
├── spawn-agent.ts # spawn_agent 工具(独立子代理 agentic 循环 + SubAgentExecutor)
|
|
83
|
+
└── run-tests.ts # run_tests 工具(自动检测项目类型、运行测试、JUnit XML 解析、结构化报告)
|
|
76
84
|
```
|
|
77
85
|
|
|
78
86
|
## 常用命令
|
|
@@ -120,7 +128,7 @@ npm run pack:all # 同时打包所有平台
|
|
|
120
128
|
- **持久记忆**: `~/.aicli/memory.md`(AI 通过 `save_memory` 工具写入,跨会话自动加载)
|
|
121
129
|
- **开发状态快照**: `~/.aicli/dev-state.md`(provider/model 切换时由前一 AI 自动生成,新模型启动后注入 system prompt)
|
|
122
130
|
- **对话历史**: `~/.aicli/history/*.json`
|
|
123
|
-
- **插件目录**: `~/.aicli/plugins
|
|
131
|
+
- **插件目录**: `~/.aicli/plugins/`(已实现,默认关闭,需 `allowPlugins: true` 显式启用)
|
|
124
132
|
|
|
125
133
|
当前已配置(用户机器):
|
|
126
134
|
```json
|
|
@@ -210,9 +218,10 @@ AICLI_NO_STREAM 设为 1 禁用流式输出
|
|
|
210
218
|
| `grep_files` | safe | 正则搜索文件内容 |
|
|
211
219
|
| `glob_files` | safe | 按 glob 模式匹配文件路径 |
|
|
212
220
|
| `run_interactive` | safe | spawn 直连可执行文件 + stdin_lines 依次输入,用于交互式程序(猜数游戏等) |
|
|
213
|
-
| `web_fetch` | safe | 抓取网页内容并转为 Markdown(含私有 IP 防 SSRF) |
|
|
214
|
-
| `save_last_response` | write(需确认) | 保存上一次 AI 回答到文件(tee 流式写盘) |
|
|
215
|
-
| `
|
|
221
|
+
| `web_fetch` | safe | 抓取网页内容并转为 Markdown(含私有 IP 防 SSRF) |
|
|
222
|
+
| `save_last_response` | write(需确认) | 保存上一次 AI 回答到文件(tee 流式写盘) |
|
|
223
|
+
| `stream_to_file` | write(需确认) | 流式生成大文档并直接写入文件,规避长文本被 token 截断 |
|
|
224
|
+
| `save_memory` | safe | 将重要信息追加到 `~/.aicli/memory.md`,跨会话持久化,启动时自动注入 system prompt |
|
|
216
225
|
| `ask_user` | safe | AI 在 agentic 循环中向用户提问,等待文本回答后继续执行 |
|
|
217
226
|
| `write_todos` | safe | AI 拆解复杂任务为子任务列表,终端实时渲染进度(pending/in_progress/completed) |
|
|
218
227
|
| `google_search` | safe | Google Custom Search API 搜索网页,需配置 API Key + Search Engine ID (cx) |
|
|
@@ -232,7 +241,7 @@ AICLI_NO_STREAM 设为 1 禁用流式输出
|
|
|
232
241
|
```
|
|
233
242
|
用户输入 → rl.pause() + rl.output=null(静默 readline)
|
|
234
243
|
→ chatWithTools(messages + toolDefs) → AI 返回 { toolCalls } 或 { content }
|
|
235
|
-
→ 若 toolCalls:executor.executeAll() → buildToolResultMessages() → 下一轮(最多
|
|
244
|
+
→ 若 toolCalls:executor.executeAll() → buildToolResultMessages() → 下一轮(最多 25 轮)
|
|
236
245
|
→ 若 content:renderResponse() → rl.output=savedOutput + rl.resume() + showPrompt()
|
|
237
246
|
```
|
|
238
247
|
|
|
@@ -82,7 +82,7 @@ var AGENTIC_BEHAVIOR_GUIDELINE = `# \u91CD\u8981\u884C\u4E3A\u51C6\u5219
|
|
|
82
82
|
var AUTHOR = "\u664B\u6B63\u4E1C";
|
|
83
83
|
var AUTHOR_EMAIL = "zhengdong.jin@gmail.com";
|
|
84
84
|
var DESCRIPTION = "\u8DE8\u5E73\u53F0 REPL \u98CE\u683C AI \u5BF9\u8BDD\u5DE5\u5177\uFF0C\u652F\u6301\u591A Provider \u4E0E Agentic \u5DE5\u5177\u8C03\u7528";
|
|
85
|
-
var REPO_URL = "https://
|
|
85
|
+
var REPO_URL = "https://github.com/jinzhengdong/ai-cli";
|
|
86
86
|
|
|
87
87
|
// src/tools/builtin/run-tests.ts
|
|
88
88
|
var IS_WINDOWS = platform() === "win32";
|
package/dist/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
31
31
|
VERSION,
|
|
32
32
|
runTestsTool
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-J6WSEEPI.js";
|
|
34
34
|
|
|
35
35
|
// src/index.ts
|
|
36
36
|
import { program } from "commander";
|
|
@@ -369,7 +369,7 @@ var BaseProvider = class {
|
|
|
369
369
|
|
|
370
370
|
// src/tools/types.ts
|
|
371
371
|
function isFileWriteTool(name) {
|
|
372
|
-
return name === "write_file" || name === "edit_file";
|
|
372
|
+
return name === "write_file" || name === "edit_file" || name === "stream_to_file";
|
|
373
373
|
}
|
|
374
374
|
function getDangerLevel(toolName, args) {
|
|
375
375
|
if (toolName.startsWith("mcp__")) return "safe";
|
|
@@ -387,6 +387,7 @@ function getDangerLevel(toolName, args) {
|
|
|
387
387
|
if (toolName === "write_file") return "write";
|
|
388
388
|
if (toolName === "edit_file") return "write";
|
|
389
389
|
if (toolName === "save_last_response") return "write";
|
|
390
|
+
if (toolName === "stream_to_file") return "write";
|
|
390
391
|
if (toolName === "run_interactive") {
|
|
391
392
|
const exe = String(args["executable"] ?? "").toLowerCase();
|
|
392
393
|
if (/\b(rm|rmdir|del|format|mkfs|Remove-Item)\b/i.test(exe)) return "destructive";
|
|
@@ -2325,7 +2326,7 @@ var SessionManager = class {
|
|
|
2325
2326
|
// src/repl/repl.ts
|
|
2326
2327
|
import * as readline from "readline";
|
|
2327
2328
|
import { existsSync as existsSync19, readFileSync as readFileSync12, readdirSync as readdirSync11, statSync as statSync9 } from "fs";
|
|
2328
|
-
import { join as join14, resolve as resolve5, extname as extname4, dirname as
|
|
2329
|
+
import { join as join14, resolve as resolve5, extname as extname4, dirname as dirname7, basename as basename6 } from "path";
|
|
2329
2330
|
import chalk9 from "chalk";
|
|
2330
2331
|
|
|
2331
2332
|
// src/repl/renderer.ts
|
|
@@ -2527,7 +2528,7 @@ var Renderer = class {
|
|
|
2527
2528
|
console.log(theme.dim(" Gemini (Google) \xB7 \u667A\u8C31\u6E05\u8A00 \xB7 \u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9"));
|
|
2528
2529
|
console.log(HR);
|
|
2529
2530
|
const mcpToolCount = mcpInfo?.tools ?? 0;
|
|
2530
|
-
const toolTotal =
|
|
2531
|
+
const toolTotal = 17 + pluginCount + mcpToolCount;
|
|
2531
2532
|
const extras = [];
|
|
2532
2533
|
if (pluginCount > 0) extras.push(`${pluginCount} \u4E2A\u63D2\u4EF6`);
|
|
2533
2534
|
if (mcpToolCount > 0) extras.push(`${mcpToolCount} \u4E2A MCP`);
|
|
@@ -2544,6 +2545,7 @@ var Renderer = class {
|
|
|
2544
2545
|
console.log(tool("web_fetch", "\u6293\u53D6\u7F51\u9875\u5185\u5BB9\uFF08\u8F6C Markdown\uFF09"));
|
|
2545
2546
|
console.log(tool("google_search", "Google \u641C\u7D22\uFF08\u9700\u914D\u7F6E API Key + CX\uFF09"));
|
|
2546
2547
|
console.log(tool("save_last_response", "\u4FDD\u5B58 AI \u56DE\u7B54\u5230\u6587\u4EF6\uFF08tee \u6D41\u5F0F\u5199\u76D8\uFF09"));
|
|
2548
|
+
console.log(tool("stream_to_file", "\u6D41\u5F0F\u751F\u6210\u5927\u6587\u6863\u5E76\u76F4\u63A5\u5199\u5165\u6587\u4EF6\uFF08\u89C4\u907F token \u622A\u65AD\uFF09"));
|
|
2547
2549
|
console.log(tool("save_memory", "\u5C06\u91CD\u8981\u4FE1\u606F\u6301\u4E45\u5316\u5230 ~/.aicli/memory.md\uFF0C\u8DE8\u4F1A\u8BDD\u81EA\u52A8\u6CE8\u5165"));
|
|
2548
2550
|
console.log(tool("ask_user", "\u5411\u7528\u6237\u63D0\u95EE\u5E76\u7B49\u5F85\u56DE\u7B54\uFF08agentic \u5FAA\u73AF\u4E2D\u8BF7\u6C42\u6F84\u6E05\uFF09"));
|
|
2549
2551
|
console.log(tool("write_todos", "\u62C6\u89E3\u4EFB\u52A1\u4E3A\u5B50\u4EFB\u52A1\u5217\u8868\uFF0C\u5B9E\u65F6\u663E\u793A\u8FDB\u5EA6"));
|
|
@@ -4597,7 +4599,7 @@ ${hint}` : "")
|
|
|
4597
4599
|
description: "Run project tests and show structured report",
|
|
4598
4600
|
usage: "/test [command|filter]",
|
|
4599
4601
|
async execute(args, _ctx) {
|
|
4600
|
-
const { executeTests } = await import("./run-tests-
|
|
4602
|
+
const { executeTests } = await import("./run-tests-77ZV7BUW.js");
|
|
4601
4603
|
const argStr = args.join(" ").trim();
|
|
4602
4604
|
let testArgs = {};
|
|
4603
4605
|
if (argStr) {
|
|
@@ -6625,8 +6627,110 @@ var saveLastResponseTool = {
|
|
|
6625
6627
|
}
|
|
6626
6628
|
};
|
|
6627
6629
|
|
|
6630
|
+
// src/tools/builtin/stream-to-file.ts
|
|
6631
|
+
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync7 } from "fs";
|
|
6632
|
+
import { dirname as dirname6 } from "path";
|
|
6633
|
+
var streamToFileContext = {
|
|
6634
|
+
provider: null,
|
|
6635
|
+
model: "",
|
|
6636
|
+
systemPrompt: void 0,
|
|
6637
|
+
messages: [],
|
|
6638
|
+
extraMessages: []
|
|
6639
|
+
};
|
|
6640
|
+
var streamToFileTool = {
|
|
6641
|
+
definition: {
|
|
6642
|
+
name: "stream_to_file",
|
|
6643
|
+
description: `\u5C06\u5927\u578B\u5185\u5BB9\uFF08\u8D85\u8FC7 5KB \u6216 300 \u884C\u7684\u8BD5\u5377\u3001\u62A5\u544A\u7B49\uFF09\u76F4\u63A5\u4EE5\u6D41\u5F0F\u65B9\u5F0F\u751F\u6210\u5E76\u4FDD\u5B58\u5230\u6587\u4EF6\u3002
|
|
6644
|
+
\u9002\u7528\u573A\u666F\uFF1A\u5F53\u4F60\u9700\u8981\u751F\u6210\u5B8C\u6574\u7684\u6A21\u8003\u8BD5\u9898\uFF08600-700\u884C\uFF09\u3001\u957F\u7BC7\u62A5\u544A\u7B49\u5927\u6587\u6863\u65F6\uFF0C\u5FC5\u987B\u4F7F\u7528\u6B64\u5DE5\u5177\uFF0C
|
|
6645
|
+
\u4E0D\u8981\u5148\u5728\u5BF9\u8BDD\u4E2D\u8F93\u51FA\u518D\u4FDD\u5B58\uFF08\u90A3\u6837\u4F1A\u88AB maxTokens \u622A\u65AD\uFF09\u3002
|
|
6646
|
+
\u4F7F\u7528\u65B9\u6CD5\uFF1A\u4F20\u5165\u76EE\u6807\u6587\u4EF6\u8DEF\u5F84\u548C\u751F\u6210\u6307\u4EE4\uFF0C\u5DE5\u5177\u4F1A\u81EA\u52A8\u5411 AI \u53D1\u8D77\u6D41\u5F0F\u8BF7\u6C42\u5E76\u5C06\u5185\u5BB9\u5B9E\u65F6\u5199\u5165\u6587\u4EF6\u3002
|
|
6647
|
+
\u6CE8\u610F\uFF1Aprompt \u53C2\u6570\u5E94\u5305\u542B\u5B8C\u6574\u7684\u751F\u6210\u6307\u4EE4\uFF0C\u5982"\u8BF7\u751F\u6210\u4E00\u4EFD\u91D1\u6807\u98CE\u683C\u8FDB\u9636\u96BE\u5EA6\u7684\u5B8C\u6574\u6A21\u8003\u8BD5\u9898\uFF0C\u5305\u542B\u6240\u6709\u9898\u76EE\u548C\u53C2\u8003\u7B54\u6848"\u3002`,
|
|
6648
|
+
parameters: {
|
|
6649
|
+
path: {
|
|
6650
|
+
type: "string",
|
|
6651
|
+
description: "\u4FDD\u5B58\u6587\u4EF6\u7684\u8DEF\u5F84\uFF08\u542B\u6587\u4EF6\u540D\uFF09\uFF0C\u5982 exam_papers/20260221-01-\u6A21\u8003-\u8FDB\u9636.md",
|
|
6652
|
+
required: true
|
|
6653
|
+
},
|
|
6654
|
+
prompt: {
|
|
6655
|
+
type: "string",
|
|
6656
|
+
description: "\u751F\u6210\u5185\u5BB9\u7684\u5B8C\u6574\u6307\u4EE4\uFF08\u4F1A\u643A\u5E26\u5F53\u524D\u5BF9\u8BDD\u5386\u53F2\u4F5C\u4E3A\u4E0A\u4E0B\u6587\uFF09",
|
|
6657
|
+
required: true
|
|
6658
|
+
}
|
|
6659
|
+
},
|
|
6660
|
+
dangerous: false
|
|
6661
|
+
},
|
|
6662
|
+
async execute(args) {
|
|
6663
|
+
const filePath = String(args["path"] ?? "");
|
|
6664
|
+
const prompt = String(args["prompt"] ?? "");
|
|
6665
|
+
if (!filePath) throw new Error("path is required");
|
|
6666
|
+
if (!prompt) throw new Error("prompt is required");
|
|
6667
|
+
const ctx = streamToFileContext;
|
|
6668
|
+
if (!ctx.provider) {
|
|
6669
|
+
throw new Error("stream_to_file: provider not initialized");
|
|
6670
|
+
}
|
|
6671
|
+
const requestMessages = [
|
|
6672
|
+
...ctx.messages,
|
|
6673
|
+
{ role: "user", content: prompt, timestamp: /* @__PURE__ */ new Date() }
|
|
6674
|
+
];
|
|
6675
|
+
undoStack.push(filePath, `stream_to_file: ${filePath}`);
|
|
6676
|
+
mkdirSync7(dirname6(filePath), { recursive: true });
|
|
6677
|
+
const writeStream = createWriteStream2(filePath, { encoding: "utf-8" });
|
|
6678
|
+
let streamError = null;
|
|
6679
|
+
writeStream.on("error", (err) => {
|
|
6680
|
+
streamError = err;
|
|
6681
|
+
});
|
|
6682
|
+
let totalBytes = 0;
|
|
6683
|
+
let totalChars = 0;
|
|
6684
|
+
const startTime = Date.now();
|
|
6685
|
+
let lastProgressAt = 0;
|
|
6686
|
+
const showProgress = (done) => {
|
|
6687
|
+
const now = Date.now();
|
|
6688
|
+
if (!done && now - lastProgressAt < 200) return;
|
|
6689
|
+
lastProgressAt = now;
|
|
6690
|
+
const elapsed = ((now - startTime) / 1e3).toFixed(1);
|
|
6691
|
+
const kb = (totalBytes / 1024).toFixed(1);
|
|
6692
|
+
process.stdout.write(`\r \u270D Writing ${filePath} ... ${kb} KB (${elapsed}s)`);
|
|
6693
|
+
};
|
|
6694
|
+
try {
|
|
6695
|
+
const stream = ctx.provider.chatStream({
|
|
6696
|
+
messages: requestMessages,
|
|
6697
|
+
model: ctx.model,
|
|
6698
|
+
systemPrompt: ctx.systemPrompt,
|
|
6699
|
+
stream: true,
|
|
6700
|
+
temperature: ctx.temperature,
|
|
6701
|
+
maxTokens: 32768,
|
|
6702
|
+
// 大文档专用,放宽到 32K tokens(约 24000 汉字)
|
|
6703
|
+
timeout: ctx.timeout ?? 3e5,
|
|
6704
|
+
...ctx.extraMessages.length > 0 ? { _extraMessages: ctx.extraMessages } : {}
|
|
6705
|
+
});
|
|
6706
|
+
for await (const chunk of stream) {
|
|
6707
|
+
if (chunk.delta) {
|
|
6708
|
+
const bytes = Buffer.byteLength(chunk.delta, "utf-8");
|
|
6709
|
+
totalBytes += bytes;
|
|
6710
|
+
totalChars += chunk.delta.length;
|
|
6711
|
+
writeStream.write(chunk.delta);
|
|
6712
|
+
showProgress(false);
|
|
6713
|
+
}
|
|
6714
|
+
}
|
|
6715
|
+
if (streamError) throw streamError;
|
|
6716
|
+
await new Promise((resolve6, reject) => {
|
|
6717
|
+
writeStream.end((err) => {
|
|
6718
|
+
if (err) reject(err);
|
|
6719
|
+
else resolve6();
|
|
6720
|
+
});
|
|
6721
|
+
});
|
|
6722
|
+
process.stdout.write("\r\x1B[2K");
|
|
6723
|
+
const lines = totalChars > 0 ? Math.round(totalChars / 40) : 0;
|
|
6724
|
+
return `File saved: ${filePath} (~${lines} lines, ${(totalBytes / 1024).toFixed(1)} KB)`;
|
|
6725
|
+
} catch (err) {
|
|
6726
|
+
writeStream.destroy();
|
|
6727
|
+
throw err;
|
|
6728
|
+
}
|
|
6729
|
+
}
|
|
6730
|
+
};
|
|
6731
|
+
|
|
6628
6732
|
// src/tools/builtin/save-memory.ts
|
|
6629
|
-
import { existsSync as existsSync13, statSync as statSync8, appendFileSync as appendFileSync3, mkdirSync as
|
|
6733
|
+
import { existsSync as existsSync13, statSync as statSync8, appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
|
|
6630
6734
|
import { join as join9 } from "path";
|
|
6631
6735
|
import { homedir as homedir3 } from "os";
|
|
6632
6736
|
function getMemoryFilePath() {
|
|
@@ -6656,7 +6760,7 @@ var saveMemoryTool = {
|
|
|
6656
6760
|
const memoryPath = getMemoryFilePath();
|
|
6657
6761
|
const configDir = join9(homedir3(), CONFIG_DIR_NAME);
|
|
6658
6762
|
if (!existsSync13(configDir)) {
|
|
6659
|
-
|
|
6763
|
+
mkdirSync8(configDir, { recursive: true });
|
|
6660
6764
|
}
|
|
6661
6765
|
const timestamp = formatTimestamp();
|
|
6662
6766
|
const entry = `
|
|
@@ -7212,7 +7316,7 @@ var spawnAgentTool = {
|
|
|
7212
7316
|
|
|
7213
7317
|
// src/tools/registry.ts
|
|
7214
7318
|
import { pathToFileURL } from "url";
|
|
7215
|
-
import { existsSync as existsSync14, mkdirSync as
|
|
7319
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync8 } from "fs";
|
|
7216
7320
|
import { join as join10 } from "path";
|
|
7217
7321
|
var ToolRegistry = class {
|
|
7218
7322
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -7229,6 +7333,7 @@ var ToolRegistry = class {
|
|
|
7229
7333
|
this.register(runInteractiveTool);
|
|
7230
7334
|
this.register(webFetchTool);
|
|
7231
7335
|
this.register(saveLastResponseTool);
|
|
7336
|
+
this.register(streamToFileTool);
|
|
7232
7337
|
this.register(saveMemoryTool);
|
|
7233
7338
|
this.register(askUserTool);
|
|
7234
7339
|
this.register(writeTodosTool);
|
|
@@ -7288,7 +7393,7 @@ var ToolRegistry = class {
|
|
|
7288
7393
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
7289
7394
|
if (!existsSync14(pluginsDir)) {
|
|
7290
7395
|
try {
|
|
7291
|
-
|
|
7396
|
+
mkdirSync9(pluginsDir, { recursive: true });
|
|
7292
7397
|
} catch {
|
|
7293
7398
|
}
|
|
7294
7399
|
return 0;
|
|
@@ -7806,15 +7911,6 @@ var ToolExecutor = class {
|
|
|
7806
7911
|
}
|
|
7807
7912
|
};
|
|
7808
7913
|
|
|
7809
|
-
// src/tools/builtin/stream-to-file.ts
|
|
7810
|
-
var streamToFileContext = {
|
|
7811
|
-
provider: null,
|
|
7812
|
-
model: "",
|
|
7813
|
-
systemPrompt: void 0,
|
|
7814
|
-
messages: [],
|
|
7815
|
-
extraMessages: []
|
|
7816
|
-
};
|
|
7817
|
-
|
|
7818
7914
|
// src/repl/setup-wizard.ts
|
|
7819
7915
|
import { password, select, input } from "@inquirer/prompts";
|
|
7820
7916
|
var PROVIDERS = [
|
|
@@ -8043,7 +8139,7 @@ Managing ${displayName} API Key`);
|
|
|
8043
8139
|
};
|
|
8044
8140
|
|
|
8045
8141
|
// src/repl/custom-commands.ts
|
|
8046
|
-
import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync9, mkdirSync as
|
|
8142
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync9, mkdirSync as mkdirSync10 } from "fs";
|
|
8047
8143
|
import { join as join11, extname as extname3 } from "path";
|
|
8048
8144
|
import { execSync as execSync7 } from "child_process";
|
|
8049
8145
|
|
|
@@ -8152,7 +8248,7 @@ var CustomCommandManager = class {
|
|
|
8152
8248
|
loadCommands() {
|
|
8153
8249
|
this.commands.clear();
|
|
8154
8250
|
if (!existsSync16(this.commandsDir)) {
|
|
8155
|
-
|
|
8251
|
+
mkdirSync10(this.commandsDir, { recursive: true });
|
|
8156
8252
|
return 0;
|
|
8157
8253
|
}
|
|
8158
8254
|
let count = 0;
|
|
@@ -8175,7 +8271,7 @@ var CustomCommandManager = class {
|
|
|
8175
8271
|
};
|
|
8176
8272
|
|
|
8177
8273
|
// src/repl/dev-state.ts
|
|
8178
|
-
import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3, mkdirSync as
|
|
8274
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3, mkdirSync as mkdirSync11 } from "fs";
|
|
8179
8275
|
import { join as join12 } from "path";
|
|
8180
8276
|
import { homedir as homedir4 } from "os";
|
|
8181
8277
|
var DEV_STATE_MAX_CHARS = 6e3;
|
|
@@ -8235,7 +8331,7 @@ function getDevStatePath() {
|
|
|
8235
8331
|
function saveDevState(content) {
|
|
8236
8332
|
const configDir = join12(homedir4(), CONFIG_DIR_NAME);
|
|
8237
8333
|
if (!existsSync17(configDir)) {
|
|
8238
|
-
|
|
8334
|
+
mkdirSync11(configDir, { recursive: true });
|
|
8239
8335
|
}
|
|
8240
8336
|
let trimmed = content.trim();
|
|
8241
8337
|
if (trimmed.length > DEV_STATE_MAX_CHARS) {
|
|
@@ -8762,7 +8858,7 @@ var McpManager = class {
|
|
|
8762
8858
|
};
|
|
8763
8859
|
|
|
8764
8860
|
// src/skills/manager.ts
|
|
8765
|
-
import { existsSync as existsSync18, readdirSync as readdirSync10, mkdirSync as
|
|
8861
|
+
import { existsSync as existsSync18, readdirSync as readdirSync10, mkdirSync as mkdirSync12 } from "fs";
|
|
8766
8862
|
import { join as join13 } from "path";
|
|
8767
8863
|
var SKILL_CONTENT_WARN_CHARS = 5e3;
|
|
8768
8864
|
var SkillManager = class {
|
|
@@ -8777,7 +8873,7 @@ var SkillManager = class {
|
|
|
8777
8873
|
this.skills.clear();
|
|
8778
8874
|
if (!existsSync18(this.skillsDir)) {
|
|
8779
8875
|
try {
|
|
8780
|
-
|
|
8876
|
+
mkdirSync12(this.skillsDir, { recursive: true });
|
|
8781
8877
|
} catch {
|
|
8782
8878
|
}
|
|
8783
8879
|
return 0;
|
|
@@ -10061,7 +10157,7 @@ Session '${this.resumeSessionId}' not found.
|
|
|
10061
10157
|
completeFilePath(partial) {
|
|
10062
10158
|
try {
|
|
10063
10159
|
const normalized = partial.replace(/\\/g, "/");
|
|
10064
|
-
const dir = normalized.includes("/") ?
|
|
10160
|
+
const dir = normalized.includes("/") ? dirname7(normalized) : ".";
|
|
10065
10161
|
const prefix = normalized.includes("/") ? basename6(normalized) : normalized;
|
|
10066
10162
|
const absDir = resolve5(process.cwd(), dir);
|
|
10067
10163
|
if (!existsSync19(absDir)) return [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jinzd-ai-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.63",
|
|
4
4
|
"description": "Cross-platform REPL-style AI CLI with multi-provider support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"marked": "^15.0.0",
|
|
72
72
|
"marked-terminal": "^7.3.0",
|
|
73
73
|
"openai": "^4.77.0",
|
|
74
|
-
"ora": "^8.2.0",
|
|
75
74
|
"undici": "^7.22.0",
|
|
76
75
|
"uuid": "^11.0.5",
|
|
77
76
|
"zod": "^3.24.1"
|