chaimi-keep-mcp 3.3.3-beta.10 → 3.3.3-beta.12

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/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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaimi-keep-mcp",
3
- "version": "3.3.3-beta.10",
3
+ "version": "3.3.3-beta.12",
4
4
  "description": "柴米AI记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
5
5
  "main": "server.js",
6
6
  "bin": {
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获取Token和解析模板。用法:mcporter call 柴米AI记账.save_expense _requestToken="RT..." name="午餐" amount=35 category="餐饮" rawInput="午餐35元"。注意:上传图片请用save_receipt',
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获取Token和解析模板。用法:mcporter call 柴米AI记账.save_receipt _requestToken="RT..." store="超市" totalAmount=156.5 items="[...]"。注意:文字描述请用save_expense/save_income',
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获取Token和解析模板。用法:mcporter call 柴米AI记账.save_income _requestToken="RT..." name="红包" amount=100 category="礼金" rawInput="收红包100元"',
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模板和requestToken。⚠️ 文字/语音记账必须先调用此工具获取Token,AI解析时必须返回_requestToken字段,否则save_expense/save_income会报MISSING_TOKEN错误!',
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模板和requestToken。⚠️ 小票记账必须先调用此工具获取Token,AI解析时必须返回_requestToken字段,否则save_receipt会报MISSING_TOKEN错误!',
445
+ description: '【不调用100%失败】获取小票图片解析的Prompt模板和流程凭证。⚠️ 小票记账必须先调用此工具获取凭证,AI解析时必须返回_flowmate字段,否则save_receipt会报MISSING_TOKEN错误!',
443
446
  inputSchema: {
444
447
  type: 'object',
445
448
  properties: {
@@ -1047,6 +1050,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1047
1050
  }
1048
1051
  }
1049
1052
 
1053
+ // 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
1054
+ processedArgs.agentType = agentType || '';
1055
+ processedArgs.apiProvider = apiProvider || '';
1056
+
1050
1057
  const mcpParams = convertParams('save_expense', processedArgs);
1051
1058
  result = await callMcpHubWithLogging('addExpense', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
1052
1059
 
@@ -1326,6 +1333,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1326
1333
  };
1327
1334
  }
1328
1335
 
1336
+ // 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
1337
+ processedArgs.agentType = agentType || '';
1338
+ processedArgs.apiProvider = apiProvider || '';
1339
+
1329
1340
  const mcpParams = convertParams('save_receipt', processedArgs);
1330
1341
  result = await callMcpHubWithLogging('addReceipt', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
1331
1342
 
@@ -1573,6 +1584,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1573
1584
  }
1574
1585
  }
1575
1586
 
1587
+ // 添加 agentType 和 apiProvider 到 processedArgs,确保 convertParams 能获取到
1588
+ processedArgs.agentType = agentType || '';
1589
+ processedArgs.apiProvider = apiProvider || '';
1590
+
1576
1591
  const mcpParams = convertParams('save_income', processedArgs);
1577
1592
  result = await callMcpHubWithLogging('addIncome', mcpParams, token, traceId, startTime, osInfo, agentType, apiProvider);
1578
1593
 
@@ -1613,8 +1628,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1613
1628
  systemPrompt: promptResult.data.systemPrompt,
1614
1629
  userPromptTemplate: promptResult.data.userPromptTemplate,
1615
1630
  examples: promptResult.data.examples,
1616
- requestToken: promptResult.data.requestToken,
1617
- instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含 _requestToken 字段!'
1631
+ myflowmate: promptResult.data.myflowmate,
1632
+ instructions: '请将 systemPrompt 作为 system message,把小票图片作为 user message,调用你的大模型进行解析。解析完成后,调用 save_receipt 工具保存结果。⚠️ 注意:AI解析结果必须包含 _flowmate 字段!'
1618
1633
  }
1619
1634
  };
1620
1635
  // 【新增】返回模板位置信息(Server只返回原始数据,Agent使用模板渲染)
@@ -1641,7 +1656,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1641
1656
  prompt: promptResult.data.prompt,
1642
1657
  currentDate: promptResult.data.currentDate,
1643
1658
  currentTime: promptResult.data.currentTime,
1644
- requestToken: promptResult.data.requestToken,
1659
+ myflowmate: promptResult.data.myflowmate,
1645
1660
  instructions: promptResult.data.instructions
1646
1661
  }
1647
1662
  };
@@ -2109,7 +2124,7 @@ function convertParams(toolName, args) {
2109
2124
  apiProvider: sanitizeString(args.apiProvider, 50) || '',
2110
2125
  mcpVersion: MCP_VERSION,
2111
2126
  source: 'mcp_txt_expense',
2112
- _requestToken: args._requestToken,
2127
+ _flowmate: args._flowmate,
2113
2128
  };
2114
2129
  }
2115
2130
 
@@ -2166,11 +2181,11 @@ function convertParams(toolName, args) {
2166
2181
  source: 'mcp_receipt',
2167
2182
  storeCategory: sanitizeString(args.storeCategory, 50) || '其他',
2168
2183
  storeSubCategory: sanitizeString(args.storeSubCategory, 50) || '其他',
2169
- _requestToken: args._requestToken,
2184
+ _flowmate: args._flowmate,
2170
2185
  };
2171
2186
  }
2172
2187
 
2173
- case 'get_expenses': {
2188
+ case 'save_receipt': {
2174
2189
  // 【新增】支持 period 参数
2175
2190
  const periodDates = args.period ? parsePeriod(args.period) : {};
2176
2191
  return {
@@ -2208,7 +2223,7 @@ function convertParams(toolName, args) {
2208
2223
  apiProvider: sanitizeString(args.apiProvider, 50) || '',
2209
2224
  mcpVersion: MCP_VERSION,
2210
2225
  source: 'mcp_txt_income',
2211
- _requestToken: args._requestToken,
2226
+ _flowmate: args._flowmate,
2212
2227
  };
2213
2228
 
2214
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
+ // 关键词到