@voko/lite 0.3.1

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.
Files changed (62) hide show
  1. package/package.json +32 -0
  2. package/scripts/build-native.js +72 -0
  3. package/src/bankHeadOffices.js +20543 -0
  4. package/src/channels/email.js +35 -0
  5. package/src/channels/feishu.js +31 -0
  6. package/src/channels/qq-email.js +30 -0
  7. package/src/channels/registry.js +279 -0
  8. package/src/channels/telegram.js +28 -0
  9. package/src/channels/voko-email.js +7 -0
  10. package/src/channels/wechat.js +35 -0
  11. package/src/cli.js +120 -0
  12. package/src/context.js +164 -0
  13. package/src/core/access-control-api.js +150 -0
  14. package/src/core/access-control.js +56 -0
  15. package/src/core/agent-registration.js +319 -0
  16. package/src/core/api-signature.js +33 -0
  17. package/src/core/audit.js +133 -0
  18. package/src/core/database.js +1409 -0
  19. package/src/core/did-auth.js +54 -0
  20. package/src/core/hermes-paths.js +57 -0
  21. package/src/core/invitation.js +49 -0
  22. package/src/core/lite-bus.js +16 -0
  23. package/src/core/llm-client.js +1032 -0
  24. package/src/core/messenger.js +456 -0
  25. package/src/core/notifier.js +99 -0
  26. package/src/core/offline-sync.js +150 -0
  27. package/src/core/payment.js +285 -0
  28. package/src/core/publish-agent.js +166 -0
  29. package/src/core/register-capabilities.js +119 -0
  30. package/src/core/search-capabilities.js +136 -0
  31. package/src/core/send-message.js +85 -0
  32. package/src/core/set-agent-status.js +65 -0
  33. package/src/core/update-agent-profile.js +102 -0
  34. package/src/core/worker-manager.js +332 -0
  35. package/src/endpoints.json +21 -0
  36. package/src/index.js +712 -0
  37. package/src/mcp/CLAUDE_TEST.md +82 -0
  38. package/src/mcp/FULL_TEST.md +139 -0
  39. package/src/mcp/TEST.md +124 -0
  40. package/src/mcp/TEST_STEPS.md +75 -0
  41. package/src/mcp/server.js +612 -0
  42. package/src/mcp/tools.js +1367 -0
  43. package/src/mcp/transport/http.js +95 -0
  44. package/src/mcp/transport/stdio.js +20 -0
  45. package/src/preload.js +27 -0
  46. package/src/server/agent-email-api.js +120 -0
  47. package/src/server/agent-manager.js +580 -0
  48. package/src/server/email-handler.js +329 -0
  49. package/src/server/feishu-handler.js +249 -0
  50. package/src/server/hermes-api-client.js +166 -0
  51. package/src/server/hermes-discovery.js +80 -0
  52. package/src/server/hermes-handler.js +287 -0
  53. package/src/server/openclaw-handler-cli.js +131 -0
  54. package/src/server/openclaw-websocket-handler.js +1290 -0
  55. package/src/server/oss.js +186 -0
  56. package/src/server/owner-intervention-notifier.js +320 -0
  57. package/src/server/release-page.html +204 -0
  58. package/src/server/telegram-handler.js +208 -0
  59. package/src/server/voko-email-handler.js +68 -0
  60. package/src/server/wechat-handler.js +439 -0
  61. package/src/workers/agent-worker.js +378 -0
  62. package/src/workers/message-content.js +51 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * VOKO 外部 API 签名工具
3
+ *
4
+ * 生成调用 /api/external/v1/* 接口所需的 X-Timestamp / X-Signature。
5
+ * 供主进程 IPC、MCP 工具等共享。
6
+ */
7
+
8
+ const crypto = require('crypto');
9
+ const ENDPOINTS = require('../endpoints.json');
10
+
11
+ const VOKO_API_URL = ENDPOINTS.api.baseUrl;
12
+ // VOKO 平台 API 密钥(可通过环境变量覆盖)
13
+ const VOKO_API_KEY = process.env.VOKO_API_KEY || 'ak_71a5f67cbbddaded1667435c';
14
+ const VOKO_API_SECRET = process.env.VOKO_API_SECRET || 'd37d6624e733ceb9dec1f347437058fd077259a4a14eb20f134faf04401e6f78';
15
+
16
+ function generateApiSignature(path, body) {
17
+ const timestamp = Math.floor(Date.now() / 1000).toString();
18
+ const rawBody = typeof body === 'string' ? body : JSON.stringify(body || {});
19
+ const toSign = VOKO_API_KEY + path + timestamp + rawBody;
20
+ const signature = crypto
21
+ .createHmac('sha256', VOKO_API_SECRET)
22
+ .update(toSign, 'utf8')
23
+ .digest('hex')
24
+ .toLowerCase();
25
+ return { timestamp, signature };
26
+ }
27
+
28
+ module.exports = {
29
+ VOKO_API_URL,
30
+ VOKO_API_KEY,
31
+ VOKO_API_SECRET,
32
+ generateApiSignature,
33
+ };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * audit.js — 消息审核规则引擎
3
+ *
4
+ * 从数据库加载 audit_rules,对消息进行正则/子串匹配,
5
+ * 按优先级(hard_deny > soft_deny > allow)返回审核结果。
6
+ * 纯 Node.js,无 Electron 依赖。
7
+ *
8
+ * @module
9
+ */
10
+
11
+ /**
12
+ * 检查消息是否命中审核规则
13
+ *
14
+ * @param {string} message - 消息内容
15
+ * @param {string} direction - 'inbound' 或 'outbound'
16
+ * @param {object} db - better-sqlite3 实例
17
+ * @returns {{ action: string|null, matchedRule: object|null, matchedKeyword: string|null }}
18
+ */
19
+ function checkAuditRules(message, direction, db) {
20
+ if (!message || typeof message !== 'string' || !message.trim()) return { action: null, matchedRule: null, matchedKeyword: null };
21
+
22
+ const rules = db.prepare(`SELECT * FROM audit_rules WHERE direction = ?`).all(direction);
23
+ if (!rules.length) return { action: null, matchedRule: null, matchedKeyword: null };
24
+
25
+ // 优先级:hard_deny > soft_deny > allow
26
+ const priority = { hard_deny: 3, soft_deny: 2, allow: 1 };
27
+ let bestAction = null;
28
+ let bestRule = null;
29
+
30
+ for (const rule of rules) {
31
+ let matched = false;
32
+ // 约定:keyword 以 / 开头和结尾的视为正则表达式
33
+ if (rule.keyword.startsWith('/') && rule.keyword.endsWith('/') && rule.keyword.length > 2) {
34
+ try {
35
+ const pattern = rule.keyword.slice(1, -1);
36
+ const re = new RegExp(pattern);
37
+ matched = re.test(message);
38
+ } catch (e) {
39
+ matched = message.includes(rule.keyword);
40
+ }
41
+ } else {
42
+ matched = message.includes(rule.keyword);
43
+ }
44
+
45
+ if (matched) {
46
+ const p = priority[rule.action] || 0;
47
+ const bestP = priority[bestAction] || 0;
48
+ if (p > bestP) {
49
+ bestAction = rule.action;
50
+ bestRule = rule;
51
+ }
52
+ }
53
+ }
54
+
55
+ return {
56
+ action: bestAction,
57
+ matchedRule: bestRule,
58
+ matchedKeyword: bestRule ? bestRule.keyword : null
59
+ };
60
+ }
61
+
62
+ /**
63
+ * 替换提示语中的变量
64
+ *
65
+ * @param {string} prompt - 含变量的提示语
66
+ * @param {object} vars - { keyword, visitorId, agentId }
67
+ * @param {object} db - better-sqlite3 实例
68
+ * @returns {string}
69
+ */
70
+ function substitutePromptVariables(prompt, vars, db) {
71
+ if (!prompt) return prompt;
72
+ let result = prompt;
73
+
74
+ let ownerEmail = '';
75
+ if (vars.agentId) {
76
+ const row = db.prepare(`SELECT owner_email FROM agents WHERE agent_id = ?`).get(vars.agentId);
77
+ if (row?.owner_email) ownerEmail = row.owner_email;
78
+ }
79
+
80
+ result = result.replace(/\{keyword\}/g, vars.keyword || '');
81
+ result = result.replace(/\{visitor_id\}/g, vars.visitorId || '');
82
+ result = result.replace(/\{owner_Email\}/g, ownerEmail);
83
+ result = result.replace(/\{agent_name\}/g, vars.agentId || '');
84
+
85
+ return result;
86
+ }
87
+
88
+ /**
89
+ * 手动发送审核介入 — 创建出站审核的干预记录并通知主人
90
+ *
91
+ * @param {object} data - { agentId, channelId, content }
92
+ * @param {object} auditResult - { action, matchedKeyword }
93
+ * @param {object} db - better-sqlite3 实例
94
+ * @param {object} databaseAPI - 数据库 API
95
+ * @param {Function} [enqueueIntervention] - (record) => {} 可选,入队主人通知
96
+ */
97
+ function triggerManualSendAuditIntervention(data, auditResult, db, databaseAPI, enqueueIntervention) {
98
+ try {
99
+ const now = Date.now();
100
+ const backendRow = db.prepare(`SELECT backend_type FROM agents WHERE agent_id = ?`).get(data.agentId);
101
+ const prefix = backendRow?.backend_type === 'hermes' ? 'hermes' : 'agent';
102
+ const oiId = `audit_send_${now}_${Math.random().toString(36).substr(2, 6)}`;
103
+ const isHardDeny = auditResult.action === 'hard_deny';
104
+ const problem = isHardDeny
105
+ ? `手动发送被拦截: "${data.content}"\n命中敏感词: "${auditResult.matchedKeyword}"\n系统已拦截,未发送给访客。`
106
+ : `手动发送命中软规则: "${data.content}"\n命中敏感词: "${auditResult.matchedKeyword}"\n已放行发送,请关注。`;
107
+
108
+ databaseAPI.saveOwnerIntervention({
109
+ id: oiId, visitorId: data.channelId,
110
+ sessionKey: `${prefix}:${data.agentId}:${data.channelId}`,
111
+ problem,
112
+ agentSuggestion: '出站关键词拦截提醒,无需回复',
113
+ askTime: now, expireTime: null, status: 'pending',
114
+ ownerReply: null, replyTime: null, parentMessageId: null,
115
+ channelType: 'voko', resolvedAt: null, createdAt: now, updatedAt: now,
116
+ agentId: data.agentId
117
+ });
118
+ db.prepare('UPDATE owner_interventions SET skip_reply = 1 WHERE id = ?').run(oiId);
119
+ if (enqueueIntervention) {
120
+ enqueueIntervention({
121
+ id: oiId, visitorId: data.channelId, agentId: data.agentId,
122
+ sessionKey: `${prefix}:${data.agentId}:${data.channelId}`,
123
+ problem,
124
+ agentSuggestion: '出站关键词拦截提醒,无需回复',
125
+ askTime: now, skipReply: 1,
126
+ });
127
+ }
128
+ } catch (e) {
129
+ console.error('[审核-出站] 触发人工介入失败:', e.message);
130
+ }
131
+ }
132
+
133
+ module.exports = { checkAuditRules, substitutePromptVariables, triggerManualSendAuditIntervention };