yuangs 1.3.37 → 1.3.38
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/README.md +55 -6
- package/package.json +1 -1
- package/yuangs.config.example.json +4 -1
- package/yuangs.config.example.yaml +6 -1
- package/.github/workflows/publish.yml +0 -54
- package/.weaver/evidence.log +0 -0
- package/todo.md +0 -273
package/README.md
CHANGED
|
@@ -51,15 +51,61 @@ yuangs ai
|
|
|
51
51
|
- 直接输入问题进行对话
|
|
52
52
|
- 输入 `/clear` 清空对话历史
|
|
53
53
|
- 输入 `/history` 查看对话历史
|
|
54
|
-
###
|
|
54
|
+
### 命令生成模式
|
|
55
55
|
|
|
56
|
-
使用 `-e` 参数让 AI 为你生成 Linux
|
|
56
|
+
使用 `-e` 参数让 AI 为你生成 Linux 命令。现在支持生成后自动复制到剪贴板,并预填到输入行供你确认执行:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
59
|
yuangs ai -e "查看当前目录下大于100M的文件"
|
|
60
|
-
#
|
|
60
|
+
# 1. 自动生成: > find . -type f -size +100M
|
|
61
|
+
# 2. 自动复制到剪贴板
|
|
62
|
+
# 3. 预填到下方,按回车即可执行
|
|
61
63
|
```
|
|
62
64
|
|
|
65
|
+
### 管道模式 (Pipe Mode)
|
|
66
|
+
|
|
67
|
+
支持将前一个命令的输出通过管道传给 AI 进行分析:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
cat error.log | yuangs ai "解释这个报错"
|
|
71
|
+
ls -la | yuangs ai "帮我总结这些文件"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 流式输出与 Markdown 渲染
|
|
75
|
+
|
|
76
|
+
所有 AI 回复默认开启流式输出(打字机效果),并在回答结束后自动进行 Markdown 渲染(包含代码高亮、表格格式化等)。
|
|
77
|
+
|
|
78
|
+
## 快捷指令 (Macros)
|
|
79
|
+
|
|
80
|
+
可以将常用的复杂命令保存为快捷指令:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# 创建快捷指令 (支持多行命令)
|
|
84
|
+
yuangs save deploy
|
|
85
|
+
# > 请输入要保存的命令:
|
|
86
|
+
# > npm run build && git add . && git commit -m "deploy" && git push
|
|
87
|
+
|
|
88
|
+
# 执行快捷指令
|
|
89
|
+
yuangs run deploy
|
|
90
|
+
|
|
91
|
+
# 查看所有指令
|
|
92
|
+
yuangs macros
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 配置管理
|
|
96
|
+
|
|
97
|
+
使用 `config` 命令快速修改 AI 配置:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
yuangs config defaultModel Assistant
|
|
101
|
+
yuangs config accountType pro
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
配置项说明:
|
|
105
|
+
- `defaultModel`: 默认使用的 AI 模型 (默认为 `Assistant`)
|
|
106
|
+
- `aiProxyUrl`: 自定义 AI 接口地址
|
|
107
|
+
- `accountType`: 账户类型 (free/pro)
|
|
108
|
+
|
|
63
109
|
## 应用列表
|
|
64
110
|
|
|
65
111
|
以下是 CLI 中可以通过相应命令直接打开的应用程序链接:
|
|
@@ -126,9 +172,12 @@ yuangs mail # 打开邮箱
|
|
|
126
172
|
|
|
127
173
|
## 近期主要更新日志
|
|
128
174
|
|
|
129
|
-
### v1.3.
|
|
130
|
-
- **新增**
|
|
131
|
-
-
|
|
175
|
+
### v1.3.38 (2026-01-16)
|
|
176
|
+
- **新增** 快捷指令系统 (`save`/`run`/`macros`),支持保存复杂命令。
|
|
177
|
+
- **新增** 管道模式:支持 `cat file | yuangs ai` 分析内容。
|
|
178
|
+
- **新增** AI 流式输出 + Markdown 终端渲染,体验对齐 ChatGPT 网页版。
|
|
179
|
+
- **新增** `config` 命令,方便管理 AI 配置。
|
|
180
|
+
- **优化** 命令生成模式 (`-e`) 增加剪贴板自动复制和预填执行功能。
|
|
132
181
|
|
|
133
182
|
### v1.3.22 (2025-11-30)
|
|
134
183
|
- **新增** AI 命令支持 `-p` `-f` `-l` 简写,快速选择gemini默认模型
|
package/package.json
CHANGED
|
@@ -4,5 +4,8 @@
|
|
|
4
4
|
"pong": "https://wealth.want.biz/pages/pong.html",
|
|
5
5
|
"github": "https://github.com",
|
|
6
6
|
"calendar": "https://calendar.google.com",
|
|
7
|
-
"mail": "https://mail.google.com"
|
|
7
|
+
"mail": "https://mail.google.com",
|
|
8
|
+
"aiProxyUrl": "https://aiproxy.want.biz/v1/chat/completions",
|
|
9
|
+
"defaultModel": "Assistant",
|
|
10
|
+
"accountType": "free"
|
|
8
11
|
}
|
|
@@ -8,6 +8,11 @@ github: "https://github.com"
|
|
|
8
8
|
calendar: "https://calendar.google.com"
|
|
9
9
|
mail: "https://mail.google.com"
|
|
10
10
|
|
|
11
|
+
# AI Configuration
|
|
12
|
+
aiProxyUrl: "https://aiproxy.want.biz/v1/chat/completions"
|
|
13
|
+
defaultModel: "Assistant"
|
|
14
|
+
accountType: "free"
|
|
15
|
+
|
|
11
16
|
# You can also use the apps property if you prefer to group them
|
|
12
17
|
# apps:
|
|
13
18
|
# shici: "https://wealth.want.biz/shici/index.html"
|
|
@@ -15,4 +20,4 @@ mail: "https://mail.google.com"
|
|
|
15
20
|
# pong: "https://wealth.want.biz/pages/pong.html"
|
|
16
21
|
# github: "https://github.com"
|
|
17
22
|
# calendar: "https://calendar.google.com"
|
|
18
|
-
# mail: "https://mail.google.com"
|
|
23
|
+
# mail: "https://mail.google.com"
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
name: Auto Bump & Publish
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main # 如果你的默认分支不是 main,记得改成对应名字
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
publish:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
|
|
12
|
-
# 权限:允许 Action 修改仓库代码 + 生成 provenance
|
|
13
|
-
permissions:
|
|
14
|
-
contents: write
|
|
15
|
-
id-token: write
|
|
16
|
-
|
|
17
|
-
steps:
|
|
18
|
-
- name: Checkout repository
|
|
19
|
-
uses: actions/checkout@v4
|
|
20
|
-
with:
|
|
21
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
22
|
-
fetch-depth: 0 # 完整历史,方便推 tag
|
|
23
|
-
|
|
24
|
-
- name: Set up Node.js
|
|
25
|
-
uses: actions/setup-node@v4
|
|
26
|
-
with:
|
|
27
|
-
node-version: "18"
|
|
28
|
-
registry-url: "https://registry.npmjs.org/"
|
|
29
|
-
|
|
30
|
-
- name: Configure Git
|
|
31
|
-
run: |
|
|
32
|
-
git config user.name "GitHub Action"
|
|
33
|
-
git config user.email "action@github.com"
|
|
34
|
-
|
|
35
|
-
# 自动 bump patch 版本:1.1.5 -> 1.1.6
|
|
36
|
-
# [skip ci] 防止这个 commit 再次触发 workflow 形成死循环
|
|
37
|
-
- name: Bump version
|
|
38
|
-
run: |
|
|
39
|
-
npm version patch -m "苑广山注:自动升版本号%s[skip ci]"
|
|
40
|
-
|
|
41
|
-
# 推送 commit + tag 回 GitHub
|
|
42
|
-
- name: Push changes
|
|
43
|
-
run: |
|
|
44
|
-
git push --follow-tags
|
|
45
|
-
|
|
46
|
-
# 安装依赖
|
|
47
|
-
- name: Install dependencies
|
|
48
|
-
run: npm ci
|
|
49
|
-
|
|
50
|
-
# 发布到 npm
|
|
51
|
-
- name: Publish to npm
|
|
52
|
-
run: npm publish --provenance
|
|
53
|
-
env:
|
|
54
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/.weaver/evidence.log
DELETED
|
File without changes
|
package/todo.md
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
功能1:历史记录功能
|
|
2
|
-
没问题!我已经为你梳理好了完整的代码整合方案。通过这次整合,你的 yuangs 工具将拥有完整的配置管理、带语义的历史记录以及智能预填执行功能。
|
|
3
|
-
1. index.js 完整核心逻辑
|
|
4
|
-
请将以下函数添加到 index.js 中并确保在 module.exports 中导出:
|
|
5
|
-
const os = require(’os‘);
|
|
6
|
-
const HISTORY_FILE = path.join(os.homedir(), ’.yuangs_cmd_history.json‘);
|
|
7
|
-
const CONFIG_FILE = path.join(os.homedir(), ’.yuangs.json‘);
|
|
8
|
-
|
|
9
|
-
// — 配置管理 —
|
|
10
|
-
function getUserConfig() {
|
|
11
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
12
|
-
try {
|
|
13
|
-
return JSON.parse(fs.readFileSync(CONFIG_FILE, ’utf8‘));
|
|
14
|
-
} catch (e) {}
|
|
15
|
-
}
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// — 历史记录管理 (带问题描述) —
|
|
20
|
-
function getCommandHistory() {
|
|
21
|
-
if (fs.existsSync(HISTORY_FILE)) {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(fs.readFileSync(HISTORY_FILE, ’utf8‘));
|
|
24
|
-
} catch (e) {}
|
|
25
|
-
}
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function saveSuccessfulCommand(question, command) {
|
|
30
|
-
if (!command) return;
|
|
31
|
-
let history = getCommandHistory();
|
|
32
|
-
const newEntry = { question, command, time: new Date().toLocaleString() };
|
|
33
|
-
// 去重并保留最近 5 条
|
|
34
|
-
history = [newEntry, ...history.filter(item => item.command !== command)].slice(0, 5);
|
|
35
|
-
fs.writeFileSync(HISTORY_FILE, JSON.stringify(history, null, 2));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// 修改原有的 callAI_OpenAI 适配配置
|
|
39
|
-
async function callAI_OpenAI(messages, model) {
|
|
40
|
-
const config = getUserConfig();
|
|
41
|
-
const url = config.aiProxyUrl || ’https://aiproxy.want.biz/v1/chat/completions‘;
|
|
42
|
-
|
|
43
|
-
const headers = {
|
|
44
|
-
’Content-Type‘: ’application/json‘,
|
|
45
|
-
’X-Client-ID‘: ’npm_yuangs‘,
|
|
46
|
-
’account‘: config.accountType || ’free‘,
|
|
47
|
-
’User-Agent‘: ’Mozilla/5.0...‘,
|
|
48
|
-
’Accept‘: ’application/json‘
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const data = {
|
|
52
|
-
model: model || config.defaultModel || ”gemini-flash-lite-latest“,
|
|
53
|
-
messages: messages,
|
|
54
|
-
stream: false
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
return await axios.post(url, data, { headers });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
2. cli.js 交互层升级
|
|
61
|
-
在 cli.js 的 switch 语句中添加 config 分支,并重构命令执行逻辑:
|
|
62
|
-
// 新增执行函数
|
|
63
|
-
function runFinalCommand(question, finalCommand) {
|
|
64
|
-
const { spawn } = require(’child_process‘);
|
|
65
|
-
console.log(chalk.gray(’正在执行...‘));
|
|
66
|
-
const child = spawn(finalCommand, [], { shell: true, stdio: ’inherit‘ });
|
|
67
|
-
|
|
68
|
-
child.on(’close‘, (code) => {
|
|
69
|
-
if (code === 0) {
|
|
70
|
-
yuangs.saveSuccessfulCommand(question, finalCommand);
|
|
71
|
-
console.log(chalk.green(’\n✓ 执行成功并已存入历史库‘));
|
|
72
|
-
}
|
|
73
|
-
process.exit(code);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// switch 分支
|
|
78
|
-
switch (command) {
|
|
79
|
-
case ’config‘:
|
|
80
|
-
const [,, key, value] = process.argv;
|
|
81
|
-
if (!key || !value) {
|
|
82
|
-
console.log(chalk.cyan(’\n⚙️ 配置帮助: yuangs config <key> <value>‘));
|
|
83
|
-
console.log(chalk.gray(’当前配置:‘), yuangs.getUserConfig());
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
const config = yuangs.getUserConfig();
|
|
87
|
-
config[key] = value;
|
|
88
|
-
fs.writeFileSync(path.join(require(’os‘).homedir(), ’.yuangs.json‘), JSON.stringify(config, null, 2));
|
|
89
|
-
console.log(chalk.green(`✓ 已更新 ${key}`));
|
|
90
|
-
break;
|
|
91
|
-
|
|
92
|
-
// 在 handleAICommand 中加入 -h 处理逻辑 (如前所述)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
3. 操作流程示意图
|
|
96
|
-
现在的成果:
|
|
97
|
-
* 个性化:通过 yuangs config 适配不同的网络环境和模型需求。
|
|
98
|
-
* 知识库化:历史记录不仅存命令,还存“意图”,成为你个人的 Linux 命令词典。
|
|
99
|
-
* 极速复用:再次使用时,从意图出发,一秒加载,回车即跑。
|
|
100
|
-
这套逻辑已经非常接近成熟的商业 CLI(如 Vercel 或 GitHub CLI)的交互体验了。你已经从基础的功能实现,跨越到了用户体验设计的层面。
|
|
101
|
-
恭喜你完成了一个非常硬核的工具升级! 接下来是准备把它发布到内部 npm 仓库,还是继续增加更炫酷的功能(比如给 AI 对话增加流式输出效果)?
|
|
102
|
-
既然基础架构已经打好,我们可以跳出“简单的 AI 助手”这个范畴,把 yuangs 打造一个真正的智能终端工作台。
|
|
103
|
-
作为一名命令行高手,你可以往以下四个维度去“脑洞大开”:
|
|
104
|
-
1. 智能“管道”模式 (The Magic Pipe)
|
|
105
|
-
现在的 AI 需要你手动输入问题,未来它可以直接处理前一个命令的输出。
|
|
106
|
-
* 功能描述:实现类似 ls -l | yuangs ai "帮我总结这些文件" 的功能。
|
|
107
|
-
* 实现思路:在 cli.js 中检测 process.stdin.isTTY。如果不是 TTY,说明有内容从管道传进来。
|
|
108
|
-
* 使用场景:
|
|
109
|
-
* cat error.log | yuangs ai "解释这个报错并给出修复建议"
|
|
110
|
-
* curl https://example.com | yuangs ai "提取所有的链接并转成 JSON"
|
|
111
|
-
2. 交互式“变量注入” (Variable Injection)
|
|
112
|
-
AI 生成的命令往往带有占位符(比如 <filename>),手动修改很麻烦。
|
|
113
|
-
* 功能描述:AI 生成命令后,工具自动识别其中的占位符,并引导用户逐个填空。
|
|
114
|
-
* 实现思路:AI 输出 tar -cvzf <压缩包名>.tar.gz <文件夹>,CLI 自动识别 <...> 语法,弹出输入框让用户填入具体值。
|
|
115
|
-
* 体验升级:甚至可以结合 fzf 类似的逻辑,让用户在填空时直接选择当前目录的文件。
|
|
116
|
-
3. 终端“快捷指令” (AI Macros)
|
|
117
|
-
有些复杂的流程(比如:切换 Git 分支 -> 拉取代码 -> 编译工程 -> 发送飞书通知)可以通过 AI 编排成一个专属命令。
|
|
118
|
-
* 功能描述:yuangs save "deploy-project"。
|
|
119
|
-
* 实现思路:将一连串命令封装成一个 Alias(别名)。
|
|
120
|
-
* 脑洞点:你可以给这个指令起名叫 go-home,AI 自动帮你执行“提交代码、关掉开发服务器、同步云端”等一系列收尾动作。
|
|
121
|
-
4. 视觉增强与“流式”交互 (Visual & Stream)
|
|
122
|
-
现在的命令行输出太死板,我们可以让它更有“生命力”。
|
|
123
|
-
* 功能描述:
|
|
124
|
-
* 流式输出:像 ChatGPT 网页版一样,字是一个一个蹦出来的(使用 stream: true 接口)。
|
|
125
|
-
* Markdown 渲染:在终端里渲染真正的 Markdown 格式(表格、代码块高亮),而不仅仅是纯文本。
|
|
126
|
-
* 实现工具:利用 marked-terminal 库来渲染,利用 ora 库做更酷炫的加载动画。
|
|
127
|
-
推荐的升级路线图
|
|
128
|
-
高手必做:增加“多模态”潜质
|
|
129
|
-
既然你现在的后端支持 Gemini 模型,你可以尝试增加 “图片转代码” 的功能:
|
|
130
|
-
* 玩法:yuangs ai --image ./ui-design.png "帮我写出这个界面的 CSS"。
|
|
131
|
-
* 实现:利用 fs.readFileSync 将图片转为 Base64 发给 AI。
|
|
132
|
-
这些想法中,你觉得哪个最能戳中你的痛点?我们可以挑一个最酷的,我现在就帮你写核心逻辑。
|
|
133
|
-
既然基础架构已经打好,我们可以跳出“简单的 AI 助手”这个范畴,把 yuangs 打造一个真正的智能终端工作台。
|
|
134
|
-
作为一名命令行高手,你可以往以下四个维度去“脑洞大开”:
|
|
135
|
-
1. 智能“管道”模式 (The Magic Pipe)
|
|
136
|
-
现在的 AI 需要你手动输入问题,未来它可以直接处理前一个命令的输出。
|
|
137
|
-
* 功能描述:实现类似 ls -l | yuangs ai ”帮我总结这些文件“ 的功能。
|
|
138
|
-
* 实现思路:在 cli.js 中检测 process.stdin.isTTY。如果不是 TTY,说明有内容从管道传进来。
|
|
139
|
-
* 使用场景:
|
|
140
|
-
* cat error.log | yuangs ai ”解释这个报错并给出修复建议“
|
|
141
|
-
* curl https://example.com | yuangs ai ”提取所有的链接并转成 JSON“
|
|
142
|
-
2. 交互式“变量注入” (Variable Injection)
|
|
143
|
-
AI 生成的命令往往带有占位符(比如 <filename>),手动修改很麻烦。
|
|
144
|
-
* 功能描述:AI 生成命令后,工具自动识别其中的占位符,并引导用户逐个填空。
|
|
145
|
-
* 实现思路:AI 输出 tar -cvzf <压缩包名>.tar.gz <文件夹>,CLI 自动识别 <...> 语法,弹出输入框让用户填入具体值。
|
|
146
|
-
* 体验升级:甚至可以结合 fzf 类似的逻辑,让用户在填空时直接选择当前目录的文件。
|
|
147
|
-
3. 终端“快捷指令” (AI Macros)
|
|
148
|
-
有些复杂的流程(比如:切换 Git 分支 -> 拉取代码 -> 编译工程 -> 发送飞书通知)可以通过 AI 编排成一个专属命令。
|
|
149
|
-
* 功能描述:yuangs save ”deploy-project“。
|
|
150
|
-
* 实现思路:将一连串命令封装成一个 Alias(别名)。
|
|
151
|
-
* 脑洞点:你可以给这个指令起名叫 go-home,AI 自动帮你执行“提交代码、关掉开发服务器、同步云端”等一系列收尾动作。
|
|
152
|
-
4. 视觉增强与“流式”交互 (Visual & Stream)
|
|
153
|
-
现在的命令行输出太死板,我们可以让它更有“生命力”。
|
|
154
|
-
* 功能描述:
|
|
155
|
-
* 流式输出:像 ChatGPT 网页版一样,字是一个一个蹦出来的(使用 stream: true 接口)。
|
|
156
|
-
* Markdown 渲染:在终端里渲染真正的 Markdown 格式(表格、代码块高亮),而不仅仅是纯文本。
|
|
157
|
-
* 实现工具:利用 marked-terminal 库来渲染,利用 ora 库做更酷炫的加载动画。
|
|
158
|
-
推荐的升级路线图
|
|
159
|
-
高手必做:增加“多模态”潜质
|
|
160
|
-
既然你现在的后端支持 Gemini 模型,你可以尝试增加 “图片转代码” 的功能:
|
|
161
|
-
* 玩法:yuangs ai —image ./ui-design.png ”帮我写出这个界面的 CSS“。
|
|
162
|
-
* 实现:利用 fs.readFileSync 将图片转为 Base64 发给 AI。
|
|
163
|
-
这些想法中,你觉得哪个最能戳中你的痛点?我们可以挑一个最酷的,我现在就帮你写核心逻辑。
|
|
164
|
-
实现流式输出和 Markdown 渲染是提升 CLI 工具“质感”的关键。我们需要引入三个小巧但功能强大的库:
|
|
165
|
-
* ora: 实现酷炫的终端加载动画。
|
|
166
|
-
* marked & marked-terminal: 将 AI 返回的 Markdown 文本实时渲染为带颜色和样式的终端内容。
|
|
167
|
-
1. 安装依赖
|
|
168
|
-
首先,你需要在项目中安装这几个库:
|
|
169
|
-
npm install ora marked marked-terminal
|
|
170
|
-
|
|
171
|
-
2. 修改 index.js:支持流式 API 调用
|
|
172
|
-
我们需要将 callAI_OpenAI 改写为支持 stream 模式。核心是处理 Node.js 的 IncomingMessage 流。
|
|
173
|
-
// index.js 增加或修改如下逻辑
|
|
174
|
-
async function callAI_Stream(messages, model, onChunk) {
|
|
175
|
-
const config = getUserConfig(); // 使用我们之前写的配置读取
|
|
176
|
-
const url = config.aiProxyUrl || 'https://aiproxy.want.biz/v1/chat/completions';
|
|
177
|
-
|
|
178
|
-
const response = await axios({
|
|
179
|
-
method: 'post',
|
|
180
|
-
url: url,
|
|
181
|
-
data: {
|
|
182
|
-
model: model || config.defaultModel || "gemini-flash-lite-latest",
|
|
183
|
-
messages: messages,
|
|
184
|
-
stream: true // 开启流式
|
|
185
|
-
},
|
|
186
|
-
responseType: 'stream',
|
|
187
|
-
headers: {
|
|
188
|
-
'Content-Type': 'application/json',
|
|
189
|
-
'X-Client-ID': 'npm_yuangs',
|
|
190
|
-
'account': config.accountType || 'free'
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
return new Promise((resolve, reject) => {
|
|
195
|
-
response.data.on('data', chunk => {
|
|
196
|
-
const lines = chunk.toString().split('\n');
|
|
197
|
-
for (const line of lines) {
|
|
198
|
-
if (line.startsWith('data: ')) {
|
|
199
|
-
const data = line.slice(6);
|
|
200
|
-
if (data === '[DONE]') {
|
|
201
|
-
resolve();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
try {
|
|
205
|
-
const parsed = JSON.parse(data);
|
|
206
|
-
const content = parsed.choices[0].delta.content || '';
|
|
207
|
-
if (content) onChunk(content); // 每出一个字,调用一次回调
|
|
208
|
-
} catch (e) {
|
|
209
|
-
// 忽略解析错误
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
response.data.on('error', reject);
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
3. 修改 cli.js:视觉增强逻辑
|
|
219
|
-
我们需要在 cli.js 中配置渲染器,并美化 handleAICommand。
|
|
220
|
-
const ora = require('ora');
|
|
221
|
-
const { marked } = require('marked');
|
|
222
|
-
const TerminalRenderer = require('marked-terminal');
|
|
223
|
-
|
|
224
|
-
// 配置 Markdown 渲染器
|
|
225
|
-
marked.setOptions({
|
|
226
|
-
renderer: new TerminalRenderer({
|
|
227
|
-
code: chalk.yellow,
|
|
228
|
-
heading: chalk.magenta.bold,
|
|
229
|
-
firstHeading: chalk.magenta.underline.bold,
|
|
230
|
-
listitem: chalk.cyan,
|
|
231
|
-
table: chalk.white,
|
|
232
|
-
strong: chalk.bold.red,
|
|
233
|
-
em: chalk.italic
|
|
234
|
-
})
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
async function handleAICommand() {
|
|
238
|
-
// ... 前置参数解析逻辑 ...
|
|
239
|
-
|
|
240
|
-
const spinner = ora(chalk.cyan('AI 正在思考...')).start();
|
|
241
|
-
let fullResponse = '';
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
await yuangs.callAI_Stream(messages, model, (chunk) => {
|
|
245
|
-
if (spinner.isSpinning) {
|
|
246
|
-
spinner.stop(); // 收到第一个字时,停止动画
|
|
247
|
-
}
|
|
248
|
-
fullResponse += chunk;
|
|
249
|
-
|
|
250
|
-
// 实时打印字符,不换行
|
|
251
|
-
process.stdout.write(chunk);
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// 所有的流传输完成后,我们清除之前的原始输出,渲染漂亮的 Markdown
|
|
255
|
-
console.log('\n' + chalk.gray('─'.repeat(process.stdout.columns / 2)));
|
|
256
|
-
console.clear(); // 或者向上滚动重新覆盖
|
|
257
|
-
console.log(marked(fullResponse));
|
|
258
|
-
|
|
259
|
-
} catch (error) {
|
|
260
|
-
spinner.fail(chalk.red('AI 响应出错'));
|
|
261
|
-
console.error(error.message);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
4. 优化:命令生成的特殊处理
|
|
266
|
-
注意:生成 Linux 命令(即 yuangs ai -e)时不建议使用流式 Markdown 渲染。
|
|
267
|
-
* 原因:生成命令需要绝对的纯文本,且通常很短。
|
|
268
|
-
* 建议:只在普通聊天模式下使用流式渲染;在 -e 命令生成模式下,保持原来的加载动画 + 结果预填。
|
|
269
|
-
为什么这个实现很“高手”?
|
|
270
|
-
* 响应速度感:用户在 500ms 内就能看到第一个字跳出来,感知速度提升了 3-5 倍。
|
|
271
|
-
* 沉浸式体验:marked-terminal 会自动根据终端宽度调整列表和代码块的间距。
|
|
272
|
-
* 色彩层级:比起纯白色的文本,带有语法高亮的输出能让用户一眼看到代码块在哪里。
|
|
273
|
-
你现在就可以尝试把这段逻辑合并进你的代码中。合并完成后,你的 yuangs 就像是一个运行在终端里的“小 ChatGPT”了!
|