chaimi-keep-mcp 3.3.3-beta.7 → 3.3.3-beta.9
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 +4 -0
- package/SKILL.md +33 -12
- package/bin/get-auth-code.js +4 -2
- package/oauth.js +11 -3
- package/package.json +1 -1
- package/references/authentication.md +6 -6
- package/server.js +10 -7
- package/utils/config.js +229 -0
- package/utils/machine-id.js +10 -3
package/README.md
CHANGED
|
@@ -89,6 +89,10 @@ export MCP_PROMPT_URL="你的Prompt服务地址"
|
|
|
89
89
|
|
|
90
90
|
## Changelog
|
|
91
91
|
|
|
92
|
+
### v3.3.3-beta.8 (2026-04-30)
|
|
93
|
+
- **变更** 配置存储路径迁移 - 从 `~/.mcporter/` 迁移到 `~/.chaimi-keep/`,避免与其他 MCP 工具冲突
|
|
94
|
+
- **优化** 安全权限 - 新增目录权限控制(0700),敏感文件权限控制(0600)
|
|
95
|
+
|
|
92
96
|
### v3.3.3-beta.7 (2026-04-29)
|
|
93
97
|
- **优化** 回复模板 - 新增"请确认信息"提示,时间移到核心数据区,添加类型变量
|
|
94
98
|
- **优化** 空值处理 - 商家为空时不显示,timeNote 仅异常时显示
|
package/SKILL.md
CHANGED
|
@@ -154,6 +154,12 @@ chaimi-keep-mcp ⭐ 本Skill
|
|
|
154
154
|
- ✅ 返回 `_templateHint` 提示使用哪个模板
|
|
155
155
|
- ✅ 返回 `_templateVariables` 提供模板变量数据
|
|
156
156
|
|
|
157
|
+
**回复简洁原则(重要)**:
|
|
158
|
+
- ❌ **不要输出记账过程** - 不要告诉用户"第1步确认信息、第2步解析时间..."等流程细节
|
|
159
|
+
- ❌ **不要刷屏** - 记账是高频操作,简洁回复是对用户的尊重
|
|
160
|
+
- ✅ **只输出最终结果** - 直接使用模板渲染记账成功信息
|
|
161
|
+
- ✅ **除非用户要求** - 仅当用户主动询问"你是怎么记账的"时才说明流程
|
|
162
|
+
|
|
157
163
|
**空值处理原则**:
|
|
158
164
|
- 模板变量中,如果某个维度的值为空(null/undefined/空字符串),Agent 应跳过该行不显示
|
|
159
165
|
- 必填字段(金额、类型、商品、分类)必须显示
|
|
@@ -180,14 +186,16 @@ references/
|
|
|
180
186
|
| `get_receipt_list` | `references/response-templates.md` | 2.5 查询结果模板 | 小票列表查询 |
|
|
181
187
|
| `get_statistics` | `references/response-templates.md` | 2.6 统计结果模板 | 消费统计分析 |
|
|
182
188
|
|
|
183
|
-
### 7.4
|
|
189
|
+
### 7.4 回复模板使用流程(Agent 内部操作,不要告诉用户)
|
|
190
|
+
|
|
191
|
+
> ⚠️ **注意**:这是 Agent 内部的处理流程,**不要输出给用户看**,只输出第 5 步的渲染结果。
|
|
184
192
|
|
|
185
193
|
```
|
|
186
194
|
1. 调用工具 → 返回原始数据 + _templateLocation + _templateHint + _templateVariables
|
|
187
195
|
2. 读取 _templateLocation 指定的模板文件
|
|
188
196
|
3. 根据 _templateHint 选择对应模板章节
|
|
189
197
|
4. 使用 _templateVariables 填充模板变量
|
|
190
|
-
5.
|
|
198
|
+
5. 渲染最终回复给用户(只展示这一步的结果)
|
|
191
199
|
```
|
|
192
200
|
|
|
193
201
|
### 7.5 5层视觉结构
|
|
@@ -214,24 +222,37 @@ references/
|
|
|
214
222
|
|
|
215
223
|
### 7.6 标准成功模板
|
|
216
224
|
|
|
225
|
+
> 📄 **完整模板定义** → 见 `references/response-templates.md` 第 2.1 节
|
|
226
|
+
>
|
|
227
|
+
> **模板要点:**
|
|
228
|
+
> - 第1层:成功标识 `✅ 「{agentName}」已帮您记账成功`
|
|
229
|
+
> - 第2层:分隔线 `═══════════════`
|
|
230
|
+
> - 第3层:核心数据(金额、类型、时间 + 🔴🔴确认提示)
|
|
231
|
+
> - 第4层:分隔线
|
|
232
|
+
> - 第5层:详细信息(商品、分类、商家)
|
|
233
|
+
> - 第6层:消费洞察(可选)
|
|
234
|
+
> - 第7层:底部祝福 + 品牌信息
|
|
235
|
+
|
|
236
|
+
**渲染示例:**
|
|
217
237
|
```markdown
|
|
218
|
-
✅
|
|
238
|
+
✅ 「你的小可爱」已帮您记账成功
|
|
219
239
|
═══════════════
|
|
220
|
-
|
|
221
|
-
|
|
240
|
+
🔴🔴 请确认以下信息是否正确
|
|
241
|
+
💰 金额:¥35.00
|
|
242
|
+
📊 类型:支出
|
|
243
|
+
🕐 时间:2026-04-24 12:30
|
|
222
244
|
═══════════════
|
|
223
245
|
|
|
224
|
-
📦
|
|
225
|
-
🏷️
|
|
226
|
-
🏪
|
|
227
|
-
🕐 时间:{日期时间}
|
|
246
|
+
📦 商品:午餐
|
|
247
|
+
🏷️ 分类:餐饮
|
|
248
|
+
🏪 商家:麦当劳
|
|
228
249
|
|
|
229
|
-
💡
|
|
250
|
+
💡 消费洞察:本月餐饮支出占比30%,建议控制
|
|
230
251
|
|
|
231
252
|
───────────────
|
|
232
|
-
🎉
|
|
253
|
+
🎉 美食为梦想充电,继续向前冲!🍚
|
|
233
254
|
柴米AI记账
|
|
234
|
-
chaimi-keep-mcp
|
|
255
|
+
chaimi-keep-mcp v3.2.0
|
|
235
256
|
───────────────
|
|
236
257
|
```
|
|
237
258
|
|
package/bin/get-auth-code.js
CHANGED
|
@@ -20,8 +20,9 @@ const MCP_OAUTH_URL = process.env.MCP_OAUTH_URL || 'https://cloud1-2gfe5jhjef06b
|
|
|
20
20
|
|
|
21
21
|
// 检查是否已有有效 Token
|
|
22
22
|
async function checkExistingToken() {
|
|
23
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
23
24
|
const tokenStorage = new FileTokenStorage(
|
|
24
|
-
path.join(os.homedir(), '.
|
|
25
|
+
path.join(os.homedir(), '.chaimi-keep', 'oauth-token.json')
|
|
25
26
|
);
|
|
26
27
|
|
|
27
28
|
try {
|
|
@@ -37,8 +38,9 @@ async function checkExistingToken() {
|
|
|
37
38
|
|
|
38
39
|
// 获取新的授权码
|
|
39
40
|
async function getAuthCode() {
|
|
41
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
40
42
|
const tokenStorage = new FileTokenStorage(
|
|
41
|
-
path.join(os.homedir(), '.
|
|
43
|
+
path.join(os.homedir(), '.chaimi-keep', 'oauth-token.json')
|
|
42
44
|
);
|
|
43
45
|
|
|
44
46
|
const oauthManager = new OAuthManager({
|
package/oauth.js
CHANGED
|
@@ -311,10 +311,14 @@ class OAuthManager {
|
|
|
311
311
|
try {
|
|
312
312
|
const fs = require('fs').promises;
|
|
313
313
|
const path = require('path');
|
|
314
|
-
const
|
|
314
|
+
const os = require('os');
|
|
315
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
316
|
+
const stateFile = path.join(os.homedir(), '.chaimi-keep', 'auth-state.json');
|
|
315
317
|
|
|
316
318
|
const dir = path.dirname(stateFile);
|
|
317
319
|
await fs.mkdir(dir, { recursive: true });
|
|
320
|
+
// 设置目录权限 0700
|
|
321
|
+
await fs.chmod(dir, 0o700).catch(() => {});
|
|
318
322
|
|
|
319
323
|
await fs.writeFile(
|
|
320
324
|
stateFile,
|
|
@@ -329,7 +333,9 @@ class OAuthManager {
|
|
|
329
333
|
try {
|
|
330
334
|
const fs = require('fs').promises;
|
|
331
335
|
const path = require('path');
|
|
332
|
-
const
|
|
336
|
+
const os = require('os');
|
|
337
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
338
|
+
const stateFile = path.join(os.homedir(), '.chaimi-keep', 'auth-state.json');
|
|
333
339
|
|
|
334
340
|
const data = await fs.readFile(stateFile, 'utf8');
|
|
335
341
|
return JSON.parse(data);
|
|
@@ -345,7 +351,9 @@ class OAuthManager {
|
|
|
345
351
|
try {
|
|
346
352
|
const fs = require('fs').promises;
|
|
347
353
|
const path = require('path');
|
|
348
|
-
const
|
|
354
|
+
const os = require('os');
|
|
355
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
356
|
+
const stateFile = path.join(os.homedir(), '.chaimi-keep', 'auth-state.json');
|
|
349
357
|
await fs.unlink(stateFile);
|
|
350
358
|
} catch (err) {
|
|
351
359
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "chaimi-keep-authentication"
|
|
3
3
|
description: 柴米AI记账授权流程详解
|
|
4
|
-
version: "1.0.
|
|
5
|
-
updated: "2026-04-
|
|
4
|
+
version: "1.0.1"
|
|
5
|
+
updated: "2026-04-30"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 柴米AI记账授权流程
|
|
@@ -134,12 +134,12 @@ mcporter auth 柴米AI记账 --reset
|
|
|
134
134
|
|
|
135
135
|
**macOS/Linux:**
|
|
136
136
|
```bash
|
|
137
|
-
rm ~/.
|
|
137
|
+
rm ~/.chaimi-keep/oauth-token.json
|
|
138
138
|
```
|
|
139
139
|
|
|
140
140
|
**Windows:**
|
|
141
141
|
```cmd
|
|
142
|
-
del %USERPROFILE%\.
|
|
142
|
+
del %USERPROFILE%\.chaimi-keep\oauth-token.json
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
然后完全退出并重新启动 Claude/Cursor
|
|
@@ -157,7 +157,7 @@ del %USERPROFILE%\.mcporter\oauth-token.json
|
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
159
|
# 查看 Token 文件是否存在
|
|
160
|
-
cat ~/.
|
|
160
|
+
cat ~/.chaimi-keep/oauth-token.json
|
|
161
161
|
|
|
162
162
|
# 或尝试调用工具测试
|
|
163
163
|
mcporter call 柴米AI记账.get_skill
|
|
@@ -165,7 +165,7 @@ mcporter call 柴米AI记账.get_skill
|
|
|
165
165
|
|
|
166
166
|
**Token 文件位置:**
|
|
167
167
|
```
|
|
168
|
-
~/.
|
|
168
|
+
~/.chaimi-keep/oauth-token.json
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
### 3.2 Token刷新
|
package/server.js
CHANGED
|
@@ -39,6 +39,9 @@ const MCP_VERSION = getVersion();
|
|
|
39
39
|
// 导入 OAuth 模块
|
|
40
40
|
const { OAuthManager, FileTokenStorage } = require('./oauth.js');
|
|
41
41
|
|
|
42
|
+
// 导入配置管理工具
|
|
43
|
+
const { configManager } = require('./utils/config.js');
|
|
44
|
+
|
|
42
45
|
// 导入校验工具
|
|
43
46
|
const { validateDate } = require('./utils/validators.js');
|
|
44
47
|
|
|
@@ -167,9 +170,9 @@ let oauthManager = null;
|
|
|
167
170
|
|
|
168
171
|
// 初始化 OAuth 管理器
|
|
169
172
|
async function initOAuthManager() {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
);
|
|
173
|
+
// 使用新的配置路径 ~/.chaimi-keep/
|
|
174
|
+
const tokenPath = configManager.getPath('oauth-token.json');
|
|
175
|
+
const tokenStorage = new FileTokenStorage(tokenPath);
|
|
173
176
|
|
|
174
177
|
oauthManager = new OAuthManager({
|
|
175
178
|
mcpOAuthUrl: MCP_OAUTH_URL,
|
|
@@ -1000,11 +1003,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1000
1003
|
}
|
|
1001
1004
|
|
|
1002
1005
|
// 【新增】处理 time_description(文本记账新时间格式)
|
|
1003
|
-
let timeNote =
|
|
1006
|
+
let timeNote = null;
|
|
1004
1007
|
if (processedArgs.time_description) {
|
|
1005
1008
|
const parsedDate = parseTimeDescription(processedArgs.time_description, Date.now());
|
|
1006
1009
|
processedArgs.date = parsedDate;
|
|
1007
|
-
|
|
1010
|
+
// 正常解析时不显示 timeNote,只有兜底或异常时才显示
|
|
1008
1011
|
console.log(`[save_expense] 时间描述解析: ${processedArgs.time_description} → ${parsedDate} (${new Date(parsedDate).toLocaleString('zh-CN')})`);
|
|
1009
1012
|
}
|
|
1010
1013
|
|
|
@@ -1520,11 +1523,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1520
1523
|
}
|
|
1521
1524
|
|
|
1522
1525
|
// 【新增】处理 time_description(收入记账新时间格式)
|
|
1523
|
-
let timeNote =
|
|
1526
|
+
let timeNote = null;
|
|
1524
1527
|
if (processedArgs.time_description) {
|
|
1525
1528
|
const parsedDate = parseTimeDescription(processedArgs.time_description, Date.now());
|
|
1526
1529
|
processedArgs.date = parsedDate;
|
|
1527
|
-
|
|
1530
|
+
// 正常解析时不显示 timeNote,只有兜底或异常时才显示
|
|
1528
1531
|
console.log(`[save_income] 时间描述解析: ${processedArgs.time_description} → ${parsedDate} (${new Date(parsedDate).toLocaleString('zh-CN')})`);
|
|
1529
1532
|
}
|
|
1530
1533
|
// 【新增】兜底:如果既没传 time_description 也没传 date,使用当前时间
|
package/utils/config.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 柴米记账 MCP 配置管理工具
|
|
3
|
+
* 统一管理配置文件存储路径,支持从旧路径迁移
|
|
4
|
+
*
|
|
5
|
+
* 存储位置:~/.chaimi-keep/
|
|
6
|
+
* 旧位置:~/.mcporter/(兼容迁移)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const fs = require('fs').promises;
|
|
12
|
+
|
|
13
|
+
// 配置目录名称
|
|
14
|
+
const CONFIG_DIR_NAME = '.chaimi-keep';
|
|
15
|
+
const LEGACY_DIR_NAME = '.mcporter';
|
|
16
|
+
|
|
17
|
+
class ConfigManager {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.configDir = path.join(os.homedir(), CONFIG_DIR_NAME);
|
|
20
|
+
this.legacyDir = path.join(os.homedir(), LEGACY_DIR_NAME);
|
|
21
|
+
this.migrationChecked = false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 获取配置文件路径
|
|
26
|
+
* @param {string} filename - 文件名
|
|
27
|
+
* @returns {string} 完整路径
|
|
28
|
+
*/
|
|
29
|
+
getPath(filename) {
|
|
30
|
+
return path.join(this.configDir, filename);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 获取旧配置文件路径
|
|
35
|
+
* @param {string} filename - 文件名
|
|
36
|
+
* @returns {string} 完整路径
|
|
37
|
+
*/
|
|
38
|
+
getLegacyPath(filename) {
|
|
39
|
+
return path.join(this.legacyDir, filename);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 确保配置目录存在,并设置正确权限
|
|
44
|
+
*/
|
|
45
|
+
async ensureDir() {
|
|
46
|
+
try {
|
|
47
|
+
await fs.mkdir(this.configDir, { recursive: true });
|
|
48
|
+
// 设置目录权限 0700(仅用户可读写执行)
|
|
49
|
+
await fs.chmod(this.configDir, 0o700);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
// 如果权限设置失败,继续执行
|
|
52
|
+
if (err.code !== 'EEXIST') {
|
|
53
|
+
console.error('创建配置目录失败:', err.message);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 检查文件是否存在于新位置
|
|
60
|
+
* @param {string} filename - 文件名
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
*/
|
|
63
|
+
async exists(filename) {
|
|
64
|
+
try {
|
|
65
|
+
await fs.access(this.getPath(filename));
|
|
66
|
+
return true;
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 检查文件是否存在于旧位置
|
|
74
|
+
* @param {string} filename - 文件名
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
async existsInLegacy(filename) {
|
|
78
|
+
try {
|
|
79
|
+
await fs.access(this.getLegacyPath(filename));
|
|
80
|
+
return true;
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 从旧位置迁移文件到新位置
|
|
88
|
+
* @param {string} filename - 文件名
|
|
89
|
+
* @returns {boolean} 是否成功迁移
|
|
90
|
+
*/
|
|
91
|
+
async migrateFile(filename) {
|
|
92
|
+
const legacyPath = this.getLegacyPath(filename);
|
|
93
|
+
const newPath = this.getPath(filename);
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
// 检查旧文件是否存在
|
|
97
|
+
await fs.access(legacyPath);
|
|
98
|
+
|
|
99
|
+
// 确保新目录存在
|
|
100
|
+
await this.ensureDir();
|
|
101
|
+
|
|
102
|
+
// 读取旧文件
|
|
103
|
+
const data = await fs.readFile(legacyPath, 'utf8');
|
|
104
|
+
|
|
105
|
+
// 写入新位置,设置权限 0600
|
|
106
|
+
await fs.writeFile(newPath, data, { mode: 0o600 });
|
|
107
|
+
|
|
108
|
+
// 删除旧文件
|
|
109
|
+
await fs.unlink(legacyPath);
|
|
110
|
+
|
|
111
|
+
console.error(`✅ 已迁移 ${filename} 到新位置`);
|
|
112
|
+
return true;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (err.code !== 'ENOENT') {
|
|
115
|
+
console.error(`迁移 ${filename} 失败:`, err.message);
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 读取配置文件(自动处理迁移)
|
|
123
|
+
* @param {string} filename - 文件名
|
|
124
|
+
* @returns {any} 文件内容(JSON 解析后)或 null
|
|
125
|
+
*/
|
|
126
|
+
async read(filename) {
|
|
127
|
+
// 确保目录存在
|
|
128
|
+
await this.ensureDir();
|
|
129
|
+
|
|
130
|
+
// 优先从新位置读取
|
|
131
|
+
const newPath = this.getPath(filename);
|
|
132
|
+
try {
|
|
133
|
+
const data = await fs.readFile(newPath, 'utf8');
|
|
134
|
+
return JSON.parse(data);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
if (err.code !== 'ENOENT') {
|
|
137
|
+
console.error(`读取 ${filename} 失败:`, err.message);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 新位置不存在,尝试从旧位置迁移
|
|
142
|
+
const migrated = await this.migrateFile(filename);
|
|
143
|
+
if (migrated) {
|
|
144
|
+
try {
|
|
145
|
+
const data = await fs.readFile(newPath, 'utf8');
|
|
146
|
+
return JSON.parse(data);
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error(`读取迁移后的 ${filename} 失败:`, err.message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 写入配置文件
|
|
157
|
+
* @param {string} filename - 文件名
|
|
158
|
+
* @param {any} data - 数据(会被 JSON 序列化)
|
|
159
|
+
* @param {boolean} isSensitive - 是否为敏感文件(设置 0600 权限)
|
|
160
|
+
*/
|
|
161
|
+
async write(filename, data, isSensitive = true) {
|
|
162
|
+
await this.ensureDir();
|
|
163
|
+
const filePath = this.getPath(filename);
|
|
164
|
+
|
|
165
|
+
const options = isSensitive ? { mode: 0o600 } : {};
|
|
166
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), options);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 删除配置文件
|
|
171
|
+
* @param {string} filename - 文件名
|
|
172
|
+
*/
|
|
173
|
+
async delete(filename) {
|
|
174
|
+
const filePath = this.getPath(filename);
|
|
175
|
+
try {
|
|
176
|
+
await fs.unlink(filePath);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
if (err.code !== 'ENOENT') {
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 删除旧位置的文件(清理用)
|
|
186
|
+
* @param {string} filename - 文件名
|
|
187
|
+
*/
|
|
188
|
+
async deleteLegacy(filename) {
|
|
189
|
+
const legacyPath = this.getLegacyPath(filename);
|
|
190
|
+
try {
|
|
191
|
+
await fs.unlink(legacyPath);
|
|
192
|
+
} catch (err) {
|
|
193
|
+
// 忽略不存在的错误
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 获取所有相关文件的路径信息
|
|
199
|
+
* @returns {Object} 路径映射
|
|
200
|
+
*/
|
|
201
|
+
getPaths() {
|
|
202
|
+
const files = [
|
|
203
|
+
'oauth-token.json',
|
|
204
|
+
'auth-state.json',
|
|
205
|
+
'agent-name.json',
|
|
206
|
+
'device-code.json',
|
|
207
|
+
'machine-id'
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
const result = {};
|
|
211
|
+
for (const file of files) {
|
|
212
|
+
result[file] = {
|
|
213
|
+
new: this.getPath(file),
|
|
214
|
+
legacy: this.getLegacyPath(file)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 导出单例实例
|
|
222
|
+
const configManager = new ConfigManager();
|
|
223
|
+
|
|
224
|
+
module.exports = {
|
|
225
|
+
ConfigManager,
|
|
226
|
+
configManager,
|
|
227
|
+
CONFIG_DIR_NAME,
|
|
228
|
+
LEGACY_DIR_NAME
|
|
229
|
+
};
|
package/utils/machine-id.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 机器ID和设备指纹管理模块
|
|
3
3
|
*
|
|
4
4
|
* 功能:
|
|
5
|
-
* 1. 生成并管理机器唯一ID(存储在 ~/.
|
|
5
|
+
* 1. 生成并管理机器唯一ID(存储在 ~/.chaimi-keep/machine-id)
|
|
6
6
|
* 2. 生成设备指纹(hash(machineId + agentType))
|
|
7
7
|
*
|
|
8
8
|
* 特点:
|
|
@@ -16,9 +16,16 @@ const path = require('path');
|
|
|
16
16
|
const os = require('os');
|
|
17
17
|
const crypto = require('crypto');
|
|
18
18
|
|
|
19
|
-
// 机器ID
|
|
19
|
+
// 机器ID文件路径(新位置 ~/.chaimi-keep/)
|
|
20
20
|
const MACHINE_ID_FILE = path.join(
|
|
21
|
-
|
|
21
|
+
os.homedir(),
|
|
22
|
+
'.chaimi-keep',
|
|
23
|
+
'machine-id'
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// 旧机器ID文件路径(用于迁移)
|
|
27
|
+
const LEGACY_MACHINE_ID_FILE = path.join(
|
|
28
|
+
os.homedir(),
|
|
22
29
|
'.mcporter',
|
|
23
30
|
'machine-id'
|
|
24
31
|
);
|