opc-agent 4.1.0 → 4.1.2
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/.github/ISSUE_TEMPLATE/bug_report.md +20 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +14 -14
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -13
- package/CHANGELOG.md +48 -48
- package/CONTRIBUTING.md +36 -36
- package/README.zh-CN.md +497 -497
- package/USABILITY-ISSUES.md +73 -0
- package/dist/channels/web.js +8 -2
- package/dist/channels/wechat.js +6 -6
- package/dist/cli.js +200 -85
- package/dist/core/runtime.js +37 -15
- package/dist/deploy/index.js +56 -56
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +105 -10
- package/dist/memory/deepbrain.d.ts +1 -1
- package/dist/memory/deepbrain.js +95 -4
- package/dist/scheduler/cron-engine.js +3 -36
- package/dist/studio/server.js +30 -1
- package/dist/studio-ui/index.html +230 -10
- package/dist/ui/components.js +105 -105
- package/examples/README.md +22 -22
- package/examples/basic-agent.ts +90 -90
- package/examples/brain-integration.ts +71 -71
- package/examples/multi-channel.ts +74 -74
- package/fix-sidebar.mjs +188 -188
- package/install.ps1 +154 -154
- package/install.sh +164 -164
- package/package.json +1 -1
- package/scripts/install.ps1 +31 -31
- package/scripts/install.sh +40 -40
- package/serve-studio.js +13 -13
- package/serve-test.js +25 -25
- package/src/channels/dingtalk.ts +46 -46
- package/src/channels/email.ts +351 -351
- package/src/channels/feishu.ts +349 -349
- package/src/channels/googlechat.ts +42 -42
- package/src/channels/imessage.ts +31 -31
- package/src/channels/irc.ts +82 -82
- package/src/channels/line.ts +32 -32
- package/src/channels/matrix.ts +33 -33
- package/src/channels/mattermost.ts +57 -57
- package/src/channels/msteams.ts +32 -32
- package/src/channels/nostr.ts +32 -32
- package/src/channels/qq.ts +33 -33
- package/src/channels/signal.ts +32 -32
- package/src/channels/sms.ts +33 -33
- package/src/channels/telegram.ts +616 -616
- package/src/channels/twitch.ts +65 -65
- package/src/channels/voice-call.ts +100 -100
- package/src/channels/web.ts +8 -2
- package/src/channels/websocket.ts +399 -399
- package/src/channels/wechat.ts +329 -329
- package/src/channels/whatsapp.ts +32 -32
- package/src/cli/chat.ts +99 -99
- package/src/cli/setup.ts +314 -314
- package/src/cli.ts +195 -92
- package/src/core/agent.ts +476 -476
- package/src/core/api-server.ts +277 -277
- package/src/core/audio.ts +98 -98
- package/src/core/collaboration.ts +275 -275
- package/src/core/context-discovery.ts +85 -85
- package/src/core/context-refs.ts +140 -140
- package/src/core/gateway.ts +106 -106
- package/src/core/heartbeat.ts +51 -51
- package/src/core/hooks.ts +105 -105
- package/src/core/ide-bridge.ts +133 -133
- package/src/core/node-network.ts +86 -86
- package/src/core/profiles.ts +122 -122
- package/src/core/runtime.ts +25 -0
- package/src/core/scheduler.ts +187 -187
- package/src/core/session-manager.ts +137 -137
- package/src/core/subagent.ts +98 -98
- package/src/core/vision.ts +180 -180
- package/src/core/workflow-graph.ts +365 -365
- package/src/daemon.ts +96 -96
- package/src/deploy/index.ts +255 -255
- package/src/doctor.ts +98 -11
- package/src/eval/index.ts +211 -211
- package/src/eval/suites/basic.json +16 -16
- package/src/eval/suites/memory.json +12 -12
- package/src/eval/suites/safety.json +14 -14
- package/src/hub/brain-seed.ts +54 -54
- package/src/hub/client.ts +60 -60
- package/src/mcp/servers/calculator-mcp.ts +65 -65
- package/src/mcp/servers/crypto-mcp.ts +73 -73
- package/src/mcp/servers/database-mcp.ts +72 -72
- package/src/mcp/servers/datetime-mcp.ts +69 -69
- package/src/mcp/servers/filesystem.ts +66 -66
- package/src/mcp/servers/github-mcp.ts +58 -58
- package/src/mcp/servers/index.ts +63 -63
- package/src/mcp/servers/json-mcp.ts +102 -102
- package/src/mcp/servers/memory-mcp.ts +56 -56
- package/src/mcp/servers/regex-mcp.ts +53 -53
- package/src/mcp/servers/web-mcp.ts +49 -49
- package/src/memory/context-compressor.ts +189 -189
- package/src/memory/deepbrain.ts +99 -5
- package/src/memory/seed-loader.ts +212 -212
- package/src/memory/user-profiler.ts +215 -215
- package/src/plugins/content-filter.ts +23 -23
- package/src/plugins/logger.ts +18 -18
- package/src/plugins/rate-limiter.ts +38 -38
- package/src/protocols/a2a/client.ts +132 -132
- package/src/protocols/a2a/index.ts +8 -8
- package/src/protocols/a2a/server.ts +333 -333
- package/src/protocols/a2a/types.ts +88 -88
- package/src/protocols/a2a/utils.ts +50 -50
- package/src/protocols/agui/client.ts +83 -83
- package/src/protocols/agui/index.ts +4 -4
- package/src/protocols/agui/server.ts +218 -218
- package/src/protocols/agui/types.ts +153 -153
- package/src/protocols/index.ts +2 -2
- package/src/protocols/mcp/agent-tools.ts +134 -134
- package/src/protocols/mcp/index.ts +8 -8
- package/src/protocols/mcp/server.ts +262 -262
- package/src/protocols/mcp/types.ts +69 -69
- package/src/providers/index.ts +632 -632
- package/src/publish/index.ts +376 -376
- package/src/scheduler/cron-engine.ts +191 -191
- package/src/scheduler/index.ts +2 -2
- package/src/schema/oad.ts +217 -217
- package/src/security/approval.ts +131 -131
- package/src/security/approvals.ts +143 -143
- package/src/security/elevated.ts +105 -105
- package/src/security/guardrails.ts +248 -248
- package/src/security/index.ts +9 -9
- package/src/security/keys.ts +87 -87
- package/src/security/secrets.ts +129 -129
- package/src/skills/builtin/index.ts +408 -408
- package/src/skills/marketplace.ts +113 -113
- package/src/skills/types.ts +42 -42
- package/src/studio/server.ts +31 -1
- package/src/studio/templates-data.ts +178 -178
- package/src/studio-ui/index.html +230 -10
- package/src/telemetry/index.ts +324 -324
- package/src/tools/builtin/browser.ts +299 -299
- package/src/tools/builtin/datetime.ts +41 -41
- package/src/tools/builtin/file.ts +107 -107
- package/src/tools/builtin/home-assistant.ts +116 -116
- package/src/tools/builtin/rl-tools.ts +243 -243
- package/src/tools/builtin/shell.ts +43 -43
- package/src/tools/builtin/vision.ts +64 -64
- package/src/tools/builtin/web-search.ts +126 -126
- package/src/tools/builtin/web.ts +35 -35
- package/src/tools/document-processor.ts +213 -213
- package/src/tools/image-generator.ts +150 -150
- package/src/tools/integrations/calendar.ts +73 -73
- package/src/tools/integrations/code-exec.ts +39 -39
- package/src/tools/integrations/csv-analyzer.ts +92 -92
- package/src/tools/integrations/database.ts +44 -44
- package/src/tools/integrations/email-send.ts +76 -76
- package/src/tools/integrations/git-tool.ts +42 -42
- package/src/tools/integrations/github-tool.ts +76 -76
- package/src/tools/integrations/image-gen.ts +56 -56
- package/src/tools/integrations/index.ts +92 -92
- package/src/tools/integrations/jira.ts +83 -83
- package/src/tools/integrations/notion.ts +71 -71
- package/src/tools/integrations/npm-tool.ts +48 -48
- package/src/tools/integrations/pdf-reader.ts +58 -58
- package/src/tools/integrations/slack.ts +65 -65
- package/src/tools/integrations/summarizer.ts +49 -49
- package/src/tools/integrations/translator.ts +48 -48
- package/src/tools/integrations/trello.ts +60 -60
- package/src/tools/integrations/vector-search.ts +42 -42
- package/src/tools/integrations/web-scraper.ts +47 -47
- package/src/tools/integrations/web-search.ts +58 -58
- package/src/tools/integrations/webhook.ts +38 -38
- package/src/tools/mcp-client.ts +131 -131
- package/src/tools/web-scraper.ts +179 -179
- package/src/tools/web-search.ts +180 -180
- package/src/ui/components.ts +127 -127
- package/srv-out.txt +1 -1
- package/templates/ecommerce-assistant/README.md +45 -45
- package/templates/ecommerce-assistant/oad.yaml +47 -47
- package/templates/tech-support/README.md +43 -43
- package/templates/tech-support/oad.yaml +45 -45
- package/test-agent/Dockerfile +9 -9
- package/test-agent/README.md +50 -50
- package/test-agent/agent.yaml +23 -23
- package/test-agent/docker-compose.yml +11 -11
- package/test-agent/oad.yaml +31 -31
- package/test-agent/package-lock.json +1492 -1492
- package/test-agent/package.json +17 -17
- package/test-agent/src/index.ts +24 -24
- package/test-agent/src/skills/echo.ts +15 -15
- package/test-agent/tsconfig.json +24 -24
- package/test-full.js +43 -43
- package/test-sidebar.js +22 -22
- package/test-studio3.js +75 -75
- package/test-studio4.js +41 -41
- package/tests/a2a-protocol.test.ts +285 -285
- package/tests/agui-protocol.test.ts +246 -246
- package/tests/api-server.test.ts +148 -148
- package/tests/approvals.test.ts +89 -89
- package/tests/audio.test.ts +40 -40
- package/tests/brain-seed-extended.test.ts +490 -490
- package/tests/brain-seed.test.ts +239 -239
- package/tests/browser.test.ts +179 -179
- package/tests/channels/discord.test.ts +79 -79
- package/tests/channels/email.test.ts +148 -148
- package/tests/channels/feishu.test.ts +123 -123
- package/tests/channels/telegram.test.ts +129 -129
- package/tests/channels/websocket.test.ts +53 -53
- package/tests/channels/wechat.test.ts +170 -170
- package/tests/channels-extra.test.ts +45 -45
- package/tests/chat-cli.test.ts +160 -160
- package/tests/cli.test.ts +46 -46
- package/tests/context-compressor.test.ts +172 -172
- package/tests/context-refs.test.ts +121 -121
- package/tests/cron-engine.test.ts +101 -101
- package/tests/daemon.test.ts +135 -135
- package/tests/deepbrain-wire.test.ts +234 -234
- package/tests/deploy-and-dag.test.ts +196 -196
- package/tests/doctor.test.ts +38 -38
- package/tests/document-processor.test.ts +69 -69
- package/tests/e2e-nocode.test.ts +442 -442
- package/tests/elevated.test.ts +69 -69
- package/tests/eval.test.ts +173 -173
- package/tests/gateway.test.ts +63 -63
- package/tests/guardrails.test.ts +177 -177
- package/tests/home-assistant.test.ts +40 -40
- package/tests/hooks.test.ts +79 -79
- package/tests/ide-bridge.test.ts +38 -38
- package/tests/image-generator.test.ts +84 -84
- package/tests/init-role.test.ts +124 -124
- package/tests/integrations.test.ts +249 -249
- package/tests/mcp-client.test.ts +92 -92
- package/tests/mcp-server.test.ts +178 -178
- package/tests/mcp-servers.test.ts +260 -260
- package/tests/node-network.test.ts +74 -74
- package/tests/plugin-a2a-enhanced.test.ts +230 -230
- package/tests/profiles.test.ts +61 -61
- package/tests/publish.test.ts +231 -231
- package/tests/rl-tools.test.ts +93 -93
- package/tests/sandbox-manager.test.ts +46 -46
- package/tests/scheduler.test.ts +200 -200
- package/tests/secrets.test.ts +107 -107
- package/tests/security-enhanced.test.ts +233 -233
- package/tests/settings-api.test.ts +148 -148
- package/tests/setup.test.ts +73 -73
- package/tests/subagent.test.ts +193 -193
- package/tests/telegram-discord.test.ts +60 -60
- package/tests/telemetry.test.ts +186 -186
- package/tests/user-profiler.test.ts +169 -169
- package/tests/v090-features.test.ts +254 -254
- package/tests/vision.test.ts +61 -61
- package/tests/voice-call.test.ts +47 -47
- package/tests/voice-enhanced.test.ts +169 -169
- package/tests/voice-interaction.test.ts +38 -38
- package/tests/web-search.test.ts +155 -155
- package/tests/workflow-graph.test.ts +279 -279
- package/tutorial/customer-service-agent/README.md +612 -612
- package/tutorial/customer-service-agent/SOUL.md +26 -26
- package/tutorial/customer-service-agent/agent.yaml +63 -63
- package/tutorial/customer-service-agent/package.json +19 -19
- package/tutorial/customer-service-agent/src/index.ts +69 -69
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -27
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -22
- package/tutorial/customer-service-agent/tsconfig.json +14 -14
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { WeChatChannel } from '../../src/channels/wechat';
|
|
3
|
-
import * as crypto from 'crypto';
|
|
4
|
-
|
|
5
|
-
describe('WeChatChannel', () => {
|
|
6
|
-
// ── XML Parsing ──────────────────────────────────
|
|
7
|
-
|
|
8
|
-
describe('parseXML', () => {
|
|
9
|
-
it('should parse text message XML', () => {
|
|
10
|
-
const xml = `<xml>
|
|
11
|
-
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
12
|
-
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
13
|
-
<CreateTime>1348831860</CreateTime>
|
|
14
|
-
<MsgType><![CDATA[text]]></MsgType>
|
|
15
|
-
<Content><![CDATA[Hello World]]></Content>
|
|
16
|
-
<MsgId>1234567890123456</MsgId>
|
|
17
|
-
</xml>`;
|
|
18
|
-
|
|
19
|
-
const msg = WeChatChannel.parseXML(xml);
|
|
20
|
-
expect(msg).not.toBeNull();
|
|
21
|
-
expect(msg!.toUserName).toBe('gh_123456');
|
|
22
|
-
expect(msg!.fromUserName).toBe('oUser123');
|
|
23
|
-
expect(msg!.createTime).toBe(1348831860);
|
|
24
|
-
expect(msg!.msgType).toBe('text');
|
|
25
|
-
expect(msg!.content).toBe('Hello World');
|
|
26
|
-
expect(msg!.msgId).toBe('1234567890123456');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should parse event message XML (subscribe)', () => {
|
|
30
|
-
const xml = `<xml>
|
|
31
|
-
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
32
|
-
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
33
|
-
<CreateTime>1348831860</CreateTime>
|
|
34
|
-
<MsgType><![CDATA[event]]></MsgType>
|
|
35
|
-
<Event><![CDATA[subscribe]]></Event>
|
|
36
|
-
</xml>`;
|
|
37
|
-
|
|
38
|
-
const msg = WeChatChannel.parseXML(xml);
|
|
39
|
-
expect(msg).not.toBeNull();
|
|
40
|
-
expect(msg!.msgType).toBe('event');
|
|
41
|
-
expect(msg!.event).toBe('subscribe');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should parse image message XML', () => {
|
|
45
|
-
const xml = `<xml>
|
|
46
|
-
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
47
|
-
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
48
|
-
<CreateTime>1348831860</CreateTime>
|
|
49
|
-
<MsgType><![CDATA[image]]></MsgType>
|
|
50
|
-
<MsgId>1234567890123456</MsgId>
|
|
51
|
-
</xml>`;
|
|
52
|
-
|
|
53
|
-
const msg = WeChatChannel.parseXML(xml);
|
|
54
|
-
expect(msg).not.toBeNull();
|
|
55
|
-
expect(msg!.msgType).toBe('image');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should return null for invalid XML', () => {
|
|
59
|
-
expect(WeChatChannel.parseXML('')).toBeNull();
|
|
60
|
-
expect(WeChatChannel.parseXML('not xml')).toBeNull();
|
|
61
|
-
expect(WeChatChannel.parseXML('<xml></xml>')).toBeNull();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should handle XML with plain text (no CDATA)', () => {
|
|
65
|
-
const xml = `<xml>
|
|
66
|
-
<ToUserName>gh_123456</ToUserName>
|
|
67
|
-
<FromUserName>oUser123</FromUserName>
|
|
68
|
-
<CreateTime>1348831860</CreateTime>
|
|
69
|
-
<MsgType>text</MsgType>
|
|
70
|
-
<Content>Hello</Content>
|
|
71
|
-
</xml>`;
|
|
72
|
-
|
|
73
|
-
const msg = WeChatChannel.parseXML(xml);
|
|
74
|
-
expect(msg).not.toBeNull();
|
|
75
|
-
expect(msg!.content).toBe('Hello');
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// ── XML Response Formatting ──────────────────────
|
|
80
|
-
|
|
81
|
-
describe('formatXMLResponse', () => {
|
|
82
|
-
it('should format valid XML response', () => {
|
|
83
|
-
const xml = WeChatChannel.formatXMLResponse('oUser123', 'gh_123456', 'Hello!');
|
|
84
|
-
expect(xml).toContain('<ToUserName><![CDATA[oUser123]]></ToUserName>');
|
|
85
|
-
expect(xml).toContain('<FromUserName><![CDATA[gh_123456]]></FromUserName>');
|
|
86
|
-
expect(xml).toContain('<Content><![CDATA[Hello!]]></Content>');
|
|
87
|
-
expect(xml).toContain('<MsgType><![CDATA[text]]></MsgType>');
|
|
88
|
-
expect(xml).toContain('<CreateTime>');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle special characters in content', () => {
|
|
92
|
-
const xml = WeChatChannel.formatXMLResponse('u', 'g', 'Hello <world> & "friends"');
|
|
93
|
-
expect(xml).toContain('Hello <world> & "friends"');
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// ── Signature Verification ───────────────────────
|
|
98
|
-
|
|
99
|
-
describe('verifySignature', () => {
|
|
100
|
-
it('should verify valid signature', () => {
|
|
101
|
-
const token = 'mytoken123';
|
|
102
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token });
|
|
103
|
-
|
|
104
|
-
const timestamp = '1348831860';
|
|
105
|
-
const nonce = 'abc123';
|
|
106
|
-
const arr = [token, timestamp, nonce].sort();
|
|
107
|
-
const expectedSignature = crypto.createHash('sha1').update(arr.join('')).digest('hex');
|
|
108
|
-
|
|
109
|
-
expect(channel.verifySignature(expectedSignature, timestamp, nonce)).toBe(true);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should reject invalid signature', () => {
|
|
113
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'mytoken' });
|
|
114
|
-
expect(channel.verifySignature('invalidsig', '123', 'abc')).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('should handle empty inputs', () => {
|
|
118
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
119
|
-
expect(channel.verifySignature('', '', '')).toBe(false);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// ── Message Handling ─────────────────────────────
|
|
124
|
-
|
|
125
|
-
describe('handleMessage', () => {
|
|
126
|
-
it('should handle subscribe event', async () => {
|
|
127
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
128
|
-
const result = await channel.handleMessage({
|
|
129
|
-
toUserName: 'gh_123',
|
|
130
|
-
fromUserName: 'oUser',
|
|
131
|
-
createTime: 1000,
|
|
132
|
-
msgType: 'event',
|
|
133
|
-
event: 'subscribe',
|
|
134
|
-
});
|
|
135
|
-
expect(result).toContain('Welcome');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should handle text message with handler', async () => {
|
|
139
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
140
|
-
channel.onMessage(async (msg) => ({
|
|
141
|
-
id: 'reply',
|
|
142
|
-
role: 'assistant',
|
|
143
|
-
content: `Echo: ${msg.content}`,
|
|
144
|
-
timestamp: Date.now(),
|
|
145
|
-
}));
|
|
146
|
-
|
|
147
|
-
const result = await channel.handleMessage({
|
|
148
|
-
toUserName: 'gh_123',
|
|
149
|
-
fromUserName: 'oUser',
|
|
150
|
-
createTime: 1000,
|
|
151
|
-
msgType: 'text',
|
|
152
|
-
content: 'Hello',
|
|
153
|
-
msgId: 'msg1',
|
|
154
|
-
});
|
|
155
|
-
expect(result).toBe('Echo: Hello');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('should return empty for text message without handler', async () => {
|
|
159
|
-
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
160
|
-
const result = await channel.handleMessage({
|
|
161
|
-
toUserName: 'gh_123',
|
|
162
|
-
fromUserName: 'oUser',
|
|
163
|
-
createTime: 1000,
|
|
164
|
-
msgType: 'text',
|
|
165
|
-
content: 'Hello',
|
|
166
|
-
});
|
|
167
|
-
expect(result).toBe('');
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { WeChatChannel } from '../../src/channels/wechat';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
|
|
5
|
+
describe('WeChatChannel', () => {
|
|
6
|
+
// ── XML Parsing ──────────────────────────────────
|
|
7
|
+
|
|
8
|
+
describe('parseXML', () => {
|
|
9
|
+
it('should parse text message XML', () => {
|
|
10
|
+
const xml = `<xml>
|
|
11
|
+
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
12
|
+
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
13
|
+
<CreateTime>1348831860</CreateTime>
|
|
14
|
+
<MsgType><![CDATA[text]]></MsgType>
|
|
15
|
+
<Content><![CDATA[Hello World]]></Content>
|
|
16
|
+
<MsgId>1234567890123456</MsgId>
|
|
17
|
+
</xml>`;
|
|
18
|
+
|
|
19
|
+
const msg = WeChatChannel.parseXML(xml);
|
|
20
|
+
expect(msg).not.toBeNull();
|
|
21
|
+
expect(msg!.toUserName).toBe('gh_123456');
|
|
22
|
+
expect(msg!.fromUserName).toBe('oUser123');
|
|
23
|
+
expect(msg!.createTime).toBe(1348831860);
|
|
24
|
+
expect(msg!.msgType).toBe('text');
|
|
25
|
+
expect(msg!.content).toBe('Hello World');
|
|
26
|
+
expect(msg!.msgId).toBe('1234567890123456');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should parse event message XML (subscribe)', () => {
|
|
30
|
+
const xml = `<xml>
|
|
31
|
+
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
32
|
+
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
33
|
+
<CreateTime>1348831860</CreateTime>
|
|
34
|
+
<MsgType><![CDATA[event]]></MsgType>
|
|
35
|
+
<Event><![CDATA[subscribe]]></Event>
|
|
36
|
+
</xml>`;
|
|
37
|
+
|
|
38
|
+
const msg = WeChatChannel.parseXML(xml);
|
|
39
|
+
expect(msg).not.toBeNull();
|
|
40
|
+
expect(msg!.msgType).toBe('event');
|
|
41
|
+
expect(msg!.event).toBe('subscribe');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should parse image message XML', () => {
|
|
45
|
+
const xml = `<xml>
|
|
46
|
+
<ToUserName><![CDATA[gh_123456]]></ToUserName>
|
|
47
|
+
<FromUserName><![CDATA[oUser123]]></FromUserName>
|
|
48
|
+
<CreateTime>1348831860</CreateTime>
|
|
49
|
+
<MsgType><![CDATA[image]]></MsgType>
|
|
50
|
+
<MsgId>1234567890123456</MsgId>
|
|
51
|
+
</xml>`;
|
|
52
|
+
|
|
53
|
+
const msg = WeChatChannel.parseXML(xml);
|
|
54
|
+
expect(msg).not.toBeNull();
|
|
55
|
+
expect(msg!.msgType).toBe('image');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should return null for invalid XML', () => {
|
|
59
|
+
expect(WeChatChannel.parseXML('')).toBeNull();
|
|
60
|
+
expect(WeChatChannel.parseXML('not xml')).toBeNull();
|
|
61
|
+
expect(WeChatChannel.parseXML('<xml></xml>')).toBeNull();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle XML with plain text (no CDATA)', () => {
|
|
65
|
+
const xml = `<xml>
|
|
66
|
+
<ToUserName>gh_123456</ToUserName>
|
|
67
|
+
<FromUserName>oUser123</FromUserName>
|
|
68
|
+
<CreateTime>1348831860</CreateTime>
|
|
69
|
+
<MsgType>text</MsgType>
|
|
70
|
+
<Content>Hello</Content>
|
|
71
|
+
</xml>`;
|
|
72
|
+
|
|
73
|
+
const msg = WeChatChannel.parseXML(xml);
|
|
74
|
+
expect(msg).not.toBeNull();
|
|
75
|
+
expect(msg!.content).toBe('Hello');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// ── XML Response Formatting ──────────────────────
|
|
80
|
+
|
|
81
|
+
describe('formatXMLResponse', () => {
|
|
82
|
+
it('should format valid XML response', () => {
|
|
83
|
+
const xml = WeChatChannel.formatXMLResponse('oUser123', 'gh_123456', 'Hello!');
|
|
84
|
+
expect(xml).toContain('<ToUserName><![CDATA[oUser123]]></ToUserName>');
|
|
85
|
+
expect(xml).toContain('<FromUserName><![CDATA[gh_123456]]></FromUserName>');
|
|
86
|
+
expect(xml).toContain('<Content><![CDATA[Hello!]]></Content>');
|
|
87
|
+
expect(xml).toContain('<MsgType><![CDATA[text]]></MsgType>');
|
|
88
|
+
expect(xml).toContain('<CreateTime>');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle special characters in content', () => {
|
|
92
|
+
const xml = WeChatChannel.formatXMLResponse('u', 'g', 'Hello <world> & "friends"');
|
|
93
|
+
expect(xml).toContain('Hello <world> & "friends"');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ── Signature Verification ───────────────────────
|
|
98
|
+
|
|
99
|
+
describe('verifySignature', () => {
|
|
100
|
+
it('should verify valid signature', () => {
|
|
101
|
+
const token = 'mytoken123';
|
|
102
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token });
|
|
103
|
+
|
|
104
|
+
const timestamp = '1348831860';
|
|
105
|
+
const nonce = 'abc123';
|
|
106
|
+
const arr = [token, timestamp, nonce].sort();
|
|
107
|
+
const expectedSignature = crypto.createHash('sha1').update(arr.join('')).digest('hex');
|
|
108
|
+
|
|
109
|
+
expect(channel.verifySignature(expectedSignature, timestamp, nonce)).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should reject invalid signature', () => {
|
|
113
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'mytoken' });
|
|
114
|
+
expect(channel.verifySignature('invalidsig', '123', 'abc')).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should handle empty inputs', () => {
|
|
118
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
119
|
+
expect(channel.verifySignature('', '', '')).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ── Message Handling ─────────────────────────────
|
|
124
|
+
|
|
125
|
+
describe('handleMessage', () => {
|
|
126
|
+
it('should handle subscribe event', async () => {
|
|
127
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
128
|
+
const result = await channel.handleMessage({
|
|
129
|
+
toUserName: 'gh_123',
|
|
130
|
+
fromUserName: 'oUser',
|
|
131
|
+
createTime: 1000,
|
|
132
|
+
msgType: 'event',
|
|
133
|
+
event: 'subscribe',
|
|
134
|
+
});
|
|
135
|
+
expect(result).toContain('Welcome');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle text message with handler', async () => {
|
|
139
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
140
|
+
channel.onMessage(async (msg) => ({
|
|
141
|
+
id: 'reply',
|
|
142
|
+
role: 'assistant',
|
|
143
|
+
content: `Echo: ${msg.content}`,
|
|
144
|
+
timestamp: Date.now(),
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
const result = await channel.handleMessage({
|
|
148
|
+
toUserName: 'gh_123',
|
|
149
|
+
fromUserName: 'oUser',
|
|
150
|
+
createTime: 1000,
|
|
151
|
+
msgType: 'text',
|
|
152
|
+
content: 'Hello',
|
|
153
|
+
msgId: 'msg1',
|
|
154
|
+
});
|
|
155
|
+
expect(result).toBe('Echo: Hello');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should return empty for text message without handler', async () => {
|
|
159
|
+
const channel = new WeChatChannel({ appId: 'id', appSecret: 'secret', token: 'tok' });
|
|
160
|
+
const result = await channel.handleMessage({
|
|
161
|
+
toUserName: 'gh_123',
|
|
162
|
+
fromUserName: 'oUser',
|
|
163
|
+
createTime: 1000,
|
|
164
|
+
msgType: 'text',
|
|
165
|
+
content: 'Hello',
|
|
166
|
+
});
|
|
167
|
+
expect(result).toBe('');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { WhatsAppChannel } from '../src/channels/whatsapp';
|
|
3
|
-
import { SignalChannel } from '../src/channels/signal';
|
|
4
|
-
import { MatrixChannel } from '../src/channels/matrix';
|
|
5
|
-
import { IMessageChannel } from '../src/channels/imessage';
|
|
6
|
-
import { LINEChannel } from '../src/channels/line';
|
|
7
|
-
import { MSTeamsChannel } from '../src/channels/msteams';
|
|
8
|
-
import { QQChannel } from '../src/channels/qq';
|
|
9
|
-
import { NostrChannel } from '../src/channels/nostr';
|
|
10
|
-
import { SMSChannel } from '../src/channels/sms';
|
|
11
|
-
|
|
12
|
-
describe('Additional Channels', () => {
|
|
13
|
-
it('should create WhatsApp channel', () => {
|
|
14
|
-
const ch = new WhatsAppChannel({ phoneNumber: '+1234567890' });
|
|
15
|
-
expect(ch.type).toBe('whatsapp');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should throw on start without deps', async () => {
|
|
19
|
-
const ch = new SignalChannel();
|
|
20
|
-
await expect(ch.start()).rejects.toThrow(/Install/);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should create Matrix channel', () => {
|
|
24
|
-
const ch = new MatrixChannel({ homeserverUrl: 'https://matrix.org' });
|
|
25
|
-
expect(ch.type).toBe('matrix');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should create all channel types', () => {
|
|
29
|
-
const channels = [
|
|
30
|
-
new IMessageChannel(),
|
|
31
|
-
new LINEChannel(),
|
|
32
|
-
new MSTeamsChannel(),
|
|
33
|
-
new QQChannel(),
|
|
34
|
-
new NostrChannel(),
|
|
35
|
-
new SMSChannel(),
|
|
36
|
-
];
|
|
37
|
-
const types = channels.map(c => c.type);
|
|
38
|
-
expect(types).toEqual(['imessage', 'line', 'msteams', 'qq', 'nostr', 'sms']);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should throw on send before start', async () => {
|
|
42
|
-
const ch = new WhatsAppChannel();
|
|
43
|
-
await expect(ch.send('123', 'hello')).rejects.toThrow(/not yet connected/);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { WhatsAppChannel } from '../src/channels/whatsapp';
|
|
3
|
+
import { SignalChannel } from '../src/channels/signal';
|
|
4
|
+
import { MatrixChannel } from '../src/channels/matrix';
|
|
5
|
+
import { IMessageChannel } from '../src/channels/imessage';
|
|
6
|
+
import { LINEChannel } from '../src/channels/line';
|
|
7
|
+
import { MSTeamsChannel } from '../src/channels/msteams';
|
|
8
|
+
import { QQChannel } from '../src/channels/qq';
|
|
9
|
+
import { NostrChannel } from '../src/channels/nostr';
|
|
10
|
+
import { SMSChannel } from '../src/channels/sms';
|
|
11
|
+
|
|
12
|
+
describe('Additional Channels', () => {
|
|
13
|
+
it('should create WhatsApp channel', () => {
|
|
14
|
+
const ch = new WhatsAppChannel({ phoneNumber: '+1234567890' });
|
|
15
|
+
expect(ch.type).toBe('whatsapp');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should throw on start without deps', async () => {
|
|
19
|
+
const ch = new SignalChannel();
|
|
20
|
+
await expect(ch.start()).rejects.toThrow(/Install/);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should create Matrix channel', () => {
|
|
24
|
+
const ch = new MatrixChannel({ homeserverUrl: 'https://matrix.org' });
|
|
25
|
+
expect(ch.type).toBe('matrix');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should create all channel types', () => {
|
|
29
|
+
const channels = [
|
|
30
|
+
new IMessageChannel(),
|
|
31
|
+
new LINEChannel(),
|
|
32
|
+
new MSTeamsChannel(),
|
|
33
|
+
new QQChannel(),
|
|
34
|
+
new NostrChannel(),
|
|
35
|
+
new SMSChannel(),
|
|
36
|
+
];
|
|
37
|
+
const types = channels.map(c => c.type);
|
|
38
|
+
expect(types).toEqual(['imessage', 'line', 'msteams', 'qq', 'nostr', 'sms']);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should throw on send before start', async () => {
|
|
42
|
+
const ch = new WhatsAppChannel();
|
|
43
|
+
await expect(ch.send('123', 'hello')).rejects.toThrow(/not yet connected/);
|
|
44
|
+
});
|
|
45
|
+
});
|