chaimi-keep-mcp 3.3.3-beta.11 → 3.3.3-beta.13
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/SKILL.md +9 -5
- package/bin/record.js +57 -0
- package/package.json +1 -1
- package/server.js +18 -15
- package/utils/category-mapper.js +15 -0
package/SKILL.md
CHANGED
|
@@ -128,15 +128,19 @@ chaimi-keep-mcp ⭐ 本Skill
|
|
|
128
128
|
└─ get_skill() 获取 SKILL.md 规范
|
|
129
129
|
└─ references/response-templates.md 了解回复模板
|
|
130
130
|
|
|
131
|
-
第2
|
|
132
|
-
└─ 文字记账:get_text_parse_prompt()
|
|
133
|
-
└─ 小票记账:get_parse_prompt()
|
|
131
|
+
第2步:拿凭证
|
|
132
|
+
└─ 文字记账:get_text_parse_prompt() 获取凭证和解析模板
|
|
133
|
+
└─ 小票记账:get_parse_prompt() 获取凭证和解析模板
|
|
134
|
+
|
|
135
|
+
【强制流程】必须先调用此工具,让 AI 解析用户输入
|
|
136
|
+
此工具会返回解析结果,你只需将结果原样传给 save_expense/save_income
|
|
137
|
+
⚠️ 禁止自行解析或提取任何字段,必须让 AI 处理
|
|
134
138
|
|
|
135
139
|
第3步:AI解析
|
|
136
|
-
└─ 按模板解析用户输入,生成结构化数据 +
|
|
140
|
+
└─ 按模板解析用户输入,生成结构化数据 + _flowmate
|
|
137
141
|
|
|
138
142
|
第4步:执行记账
|
|
139
|
-
└─ 调用工具(save_expense/income/receipt,带上
|
|
143
|
+
└─ 调用工具(save_expense/income/receipt,带上 _flowmate)
|
|
140
144
|
└─ 根据 _templateLocation 使用模板渲染美学回复
|
|
141
145
|
```
|
|
142
146
|
|
package/bin/record.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 柴米AI记账 - 直接记账 CLI
|
|
4
|
+
* 一步完成:解析文本 → 分类 → 调用云函数存储
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { callMcpHub } = require('../utils/api');
|
|
8
|
+
const { getToken } = require('../utils/auth');
|
|
9
|
+
const { parseText } = require('../utils/parser');
|
|
10
|
+
|
|
11
|
+
async function record(text, options = {}) {
|
|
12
|
+
try {
|
|
13
|
+
// 1. 解析文本
|
|
14
|
+
const parsed = await parseText(text);
|
|
15
|
+
|
|
16
|
+
// 2. 确定类型(收入/支出)
|
|
17
|
+
const type = options.type || parsed.type || 'expense';
|
|
18
|
+
|
|
19
|
+
// 3. 获取 token
|
|
20
|
+
const token = await getToken();
|
|
21
|
+
|
|
22
|
+
// 4. 调用云函数存储
|
|
23
|
+
const result = await callMcpHub(type === 'income' ? 'addIncome' : 'addExpense', {
|
|
24
|
+
...parsed,
|
|
25
|
+
type,
|
|
26
|
+
rawInput: text
|
|
27
|
+
}, token);
|
|
28
|
+
|
|
29
|
+
if (result.success) {
|
|
30
|
+
console.log('✅ 记账成功!');
|
|
31
|
+
console.log(`金额:¥${parsed.amount}`);
|
|
32
|
+
console.log(`分类:${parsed.category}`);
|
|
33
|
+
console.log(`商品:${parsed.name}`);
|
|
34
|
+
} else {
|
|
35
|
+
console.error('❌ 记账失败:', result.error);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('❌ 错误:', error.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 解析命令行参数
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
const text = args[0];
|
|
47
|
+
const typeFlag = args.find(arg => arg.startsWith('--type='));
|
|
48
|
+
const type = typeFlag ? typeFlag.split('=')[1] : null;
|
|
49
|
+
|
|
50
|
+
if (!text) {
|
|
51
|
+
console.log('用法: chaimi-keep record "<记账文本>" [--type=income|expense]');
|
|
52
|
+
console.log('示例: chaimi-keep record "中午吃饭花了35元"');
|
|
53
|
+
console.log('示例: chaimi-keep record "工资收入5000" --type=income');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
record(text, { type });
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -259,7 +259,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
259
259
|
},
|
|
260
260
|
{
|
|
261
261
|
name: 'save_expense',
|
|
262
|
-
description: '【文本记账-支出】用户提及支出/消费时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt
|
|
262
|
+
description: '【文本记账-支出】用户提及支出/消费时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_expense _flowmate="SOLINWANG..." name="午餐" amount=35 category="餐饮" rawInput="午餐35元"。注意:上传图片请用save_receipt',
|
|
263
263
|
inputSchema: {
|
|
264
264
|
type: 'object',
|
|
265
265
|
properties: {
|
|
@@ -275,13 +275,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
275
275
|
agentType: { type: 'string', description: '【必填】Agent类型,如:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
276
276
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商,如:anthropic、openai、doubao、aliyun' },
|
|
277
277
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容,用于记录用户原始请求' },
|
|
278
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_text_parse_prompt获取的myflowmate值' },
|
|
278
279
|
},
|
|
279
|
-
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput'],
|
|
280
|
+
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
280
281
|
},
|
|
281
282
|
},
|
|
282
283
|
{
|
|
283
284
|
name: 'save_receipt',
|
|
284
|
-
description: '【图片记账-小票】用户上传小票/发票/收据图片时用此工具。前置:必须先调用get_skill获取规范,再调用get_parse_prompt
|
|
285
|
+
description: '【图片记账-小票】用户上传小票/发票/收据图片时用此工具。前置:必须先调用get_skill获取规范,再调用get_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_receipt _flowmate="SOLINWANG..." store="超市" totalAmount=156.5 items="[...]"。注意:文字描述请用save_expense/save_income',
|
|
285
286
|
inputSchema: {
|
|
286
287
|
type: 'object',
|
|
287
288
|
properties: {
|
|
@@ -322,8 +323,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
322
323
|
agentType: { type: 'string', description: '【必填】Agent类型:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
323
324
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商:anthropic、openai、doubao、aliyun' },
|
|
324
325
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容' },
|
|
326
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_parse_prompt获取的myflowmate值' },
|
|
325
327
|
},
|
|
326
|
-
required: ['store', 'items', 'storeCategory', 'storeSubCategory', 'agentType', 'apiProvider', 'rawInput'],
|
|
328
|
+
required: ['store', 'items', 'storeCategory', 'storeSubCategory', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
327
329
|
},
|
|
328
330
|
},
|
|
329
331
|
{
|
|
@@ -409,7 +411,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
409
411
|
},
|
|
410
412
|
{
|
|
411
413
|
name: 'save_income',
|
|
412
|
-
description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt
|
|
414
|
+
description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_income _flowmate="SOLINWANG..." name="红包" amount=100 category="礼金" rawInput="收红包100元"',
|
|
413
415
|
inputSchema: {
|
|
414
416
|
type: 'object',
|
|
415
417
|
properties: {
|
|
@@ -422,13 +424,14 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
422
424
|
agentType: { type: 'string', description: '【必填】Agent类型,如:claude-desktop、cursor、openclaw、workbuddy、trae' },
|
|
423
425
|
apiProvider: { type: 'string', description: '【必填】AI服务提供商,如:anthropic、openai、doubao、aliyun' },
|
|
424
426
|
rawInput: { type: 'string', description: '【必填】用户的原始输入内容,用于记录用户原始请求' },
|
|
427
|
+
_flowmate: { type: 'string', description: '【必填】流程凭证,从get_text_parse_prompt获取的myflowmate值' },
|
|
425
428
|
},
|
|
426
|
-
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput'],
|
|
429
|
+
required: ['name', 'amount', 'category', 'agentType', 'apiProvider', 'rawInput', '_flowmate'],
|
|
427
430
|
},
|
|
428
431
|
},
|
|
429
432
|
{
|
|
430
433
|
name: 'get_text_parse_prompt',
|
|
431
|
-
description: '【不调用100%失败】获取文字记账解析的Prompt
|
|
434
|
+
description: '【不调用100%失败】获取文字记账解析的Prompt模板和流程凭证。⚠️ 文字/语音记账必须先调用此工具获取凭证,AI解析时必须返回_flowmate字段,否则save_expense/save_income会报MISSING_TOKEN错误!',
|
|
432
435
|
inputSchema: {
|
|
433
436
|
type: 'object',
|
|
434
437
|
properties: {
|
|
@@ -439,7 +442,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
439
442
|
},
|
|
440
443
|
{
|
|
441
444
|
name: 'get_parse_prompt',
|
|
442
|
-
description: '【不调用100%失败】获取小票图片解析的Prompt
|
|
445
|
+
description: '【不调用100%失败】获取小票图片解析的Prompt模板和流程凭证。⚠️ 小票记账必须先调用此工具获取凭证,AI解析时必须返回_flowmate字段,否则save_receipt会报MISSING_TOKEN错误!',
|
|
443
446
|
inputSchema: {
|
|
444
447
|
type: 'object',
|
|
445
448
|
properties: {
|
|
@@ -1625,8 +1628,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1625
1628
|
systemPrompt: promptResult.data.systemPrompt,
|
|
1626
1629
|
userPromptTemplate: promptResult.data.userPromptTemplate,
|
|
1627
1630
|
examples: promptResult.data.examples,
|
|
1628
|
-
|
|
1629
|
-
instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含
|
|
1631
|
+
myflowmate: promptResult.data.myflowmate,
|
|
1632
|
+
instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含 _flowmate 字段!'
|
|
1630
1633
|
}
|
|
1631
1634
|
};
|
|
1632
1635
|
// 【新增】返回模板位置信息(Server只返回原始数据,Agent使用模板渲染)
|
|
@@ -1653,7 +1656,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1653
1656
|
prompt: promptResult.data.prompt,
|
|
1654
1657
|
currentDate: promptResult.data.currentDate,
|
|
1655
1658
|
currentTime: promptResult.data.currentTime,
|
|
1656
|
-
|
|
1659
|
+
myflowmate: promptResult.data.myflowmate,
|
|
1657
1660
|
instructions: promptResult.data.instructions
|
|
1658
1661
|
}
|
|
1659
1662
|
};
|
|
@@ -2121,7 +2124,7 @@ function convertParams(toolName, args) {
|
|
|
2121
2124
|
apiProvider: sanitizeString(args.apiProvider, 50) || '',
|
|
2122
2125
|
mcpVersion: MCP_VERSION,
|
|
2123
2126
|
source: 'mcp_txt_expense',
|
|
2124
|
-
|
|
2127
|
+
_flowmate: args._flowmate,
|
|
2125
2128
|
};
|
|
2126
2129
|
}
|
|
2127
2130
|
|
|
@@ -2178,11 +2181,11 @@ function convertParams(toolName, args) {
|
|
|
2178
2181
|
source: 'mcp_receipt',
|
|
2179
2182
|
storeCategory: sanitizeString(args.storeCategory, 50) || '其他',
|
|
2180
2183
|
storeSubCategory: sanitizeString(args.storeSubCategory, 50) || '其他',
|
|
2181
|
-
|
|
2184
|
+
_flowmate: args._flowmate,
|
|
2182
2185
|
};
|
|
2183
2186
|
}
|
|
2184
2187
|
|
|
2185
|
-
case '
|
|
2188
|
+
case 'save_receipt': {
|
|
2186
2189
|
// 【新增】支持 period 参数
|
|
2187
2190
|
const periodDates = args.period ? parsePeriod(args.period) : {};
|
|
2188
2191
|
return {
|
|
@@ -2220,7 +2223,7 @@ function convertParams(toolName, args) {
|
|
|
2220
2223
|
apiProvider: sanitizeString(args.apiProvider, 50) || '',
|
|
2221
2224
|
mcpVersion: MCP_VERSION,
|
|
2222
2225
|
source: 'mcp_txt_income',
|
|
2223
|
-
|
|
2226
|
+
_flowmate: args._flowmate,
|
|
2224
2227
|
};
|
|
2225
2228
|
|
|
2226
2229
|
default:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 分类标准化映射器
|
|
3
|
+
* 将 Agent 提取的关键词映射到标准分类
|
|
4
|
+
* 确保分类一致性,便于后续统计
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 标准分类列表
|
|
8
|
+
const STANDARD_CATEGORIES = [
|
|
9
|
+
'餐饮', '购物', '交通', '蔬菜', '水果', '零食', '运动', '通讯', '服饰', '美容',
|
|
10
|
+
'住房', '孩子', '长辈', '社交', '旅行', '烟酒', '数码', '汽车', '医疗', '办公',
|
|
11
|
+
'学习', '宠物', '礼金', '亲友', '日用', '休闲娱乐', '维修', '居家', '饮品', '鲜花',
|
|
12
|
+
'追星', '首饰', '借出', '保险', '网络虚拟', '生活缴费', '转账', '书籍', '捐赠', '彩票', '快递', '其他'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
// 关键词到
|