xabot-cli 1.4.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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -0
  3. package/README.zh-CN.md +126 -0
  4. package/dist/bridge/index.d.ts +93 -0
  5. package/dist/bridge/index.d.ts.map +1 -0
  6. package/dist/bridge/index.js +811 -0
  7. package/dist/bridge/index.js.map +1 -0
  8. package/dist/bridge/input-parser.d.ts +16 -0
  9. package/dist/bridge/input-parser.d.ts.map +1 -0
  10. package/dist/bridge/input-parser.js +20 -0
  11. package/dist/bridge/input-parser.js.map +1 -0
  12. package/dist/cli/chat.d.ts +38 -0
  13. package/dist/cli/chat.d.ts.map +1 -0
  14. package/dist/cli/chat.js +147 -0
  15. package/dist/cli/chat.js.map +1 -0
  16. package/dist/cli/feishu.d.ts +3 -0
  17. package/dist/cli/feishu.d.ts.map +1 -0
  18. package/dist/cli/feishu.js +79 -0
  19. package/dist/cli/feishu.js.map +1 -0
  20. package/dist/cli/health.d.ts +15 -0
  21. package/dist/cli/health.d.ts.map +1 -0
  22. package/dist/cli/health.js +26 -0
  23. package/dist/cli/health.js.map +1 -0
  24. package/dist/cli/index.d.ts +13 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +43 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/cli/run.d.ts +20 -0
  29. package/dist/cli/run.d.ts.map +1 -0
  30. package/dist/cli/run.js +43 -0
  31. package/dist/cli/run.js.map +1 -0
  32. package/dist/cli/wechat.d.ts +3 -0
  33. package/dist/cli/wechat.d.ts.map +1 -0
  34. package/dist/cli/wechat.js +86 -0
  35. package/dist/cli/wechat.js.map +1 -0
  36. package/dist/core/client.d.ts +31 -0
  37. package/dist/core/client.d.ts.map +1 -0
  38. package/dist/core/client.js +2 -0
  39. package/dist/core/client.js.map +1 -0
  40. package/dist/core/error.d.ts +11 -0
  41. package/dist/core/error.d.ts.map +1 -0
  42. package/dist/core/error.js +21 -0
  43. package/dist/core/error.js.map +1 -0
  44. package/dist/core/fs-utils.d.ts +17 -0
  45. package/dist/core/fs-utils.d.ts.map +1 -0
  46. package/dist/core/fs-utils.js +84 -0
  47. package/dist/core/fs-utils.js.map +1 -0
  48. package/dist/core/logger.d.ts +10 -0
  49. package/dist/core/logger.d.ts.map +1 -0
  50. package/dist/core/logger.js +44 -0
  51. package/dist/core/logger.js.map +1 -0
  52. package/dist/core/pairing.d.ts +10 -0
  53. package/dist/core/pairing.d.ts.map +1 -0
  54. package/dist/core/pairing.js +22 -0
  55. package/dist/core/pairing.js.map +1 -0
  56. package/dist/core/types.d.ts +50 -0
  57. package/dist/core/types.d.ts.map +1 -0
  58. package/dist/core/types.js +11 -0
  59. package/dist/core/types.js.map +1 -0
  60. package/dist/index.d.ts +13 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +9 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/platforms/feishu/client.d.ts +49 -0
  65. package/dist/platforms/feishu/client.d.ts.map +1 -0
  66. package/dist/platforms/feishu/client.js +296 -0
  67. package/dist/platforms/feishu/client.js.map +1 -0
  68. package/dist/platforms/feishu/message.d.ts +49 -0
  69. package/dist/platforms/feishu/message.d.ts.map +1 -0
  70. package/dist/platforms/feishu/message.js +131 -0
  71. package/dist/platforms/feishu/message.js.map +1 -0
  72. package/dist/platforms/feishu/upload.d.ts +11 -0
  73. package/dist/platforms/feishu/upload.d.ts.map +1 -0
  74. package/dist/platforms/feishu/upload.js +60 -0
  75. package/dist/platforms/feishu/upload.js.map +1 -0
  76. package/dist/platforms/wechat/client.d.ts +53 -0
  77. package/dist/platforms/wechat/client.d.ts.map +1 -0
  78. package/dist/platforms/wechat/client.js +301 -0
  79. package/dist/platforms/wechat/client.js.map +1 -0
  80. package/dist/platforms/wechat/crypto.d.ts +23 -0
  81. package/dist/platforms/wechat/crypto.d.ts.map +1 -0
  82. package/dist/platforms/wechat/crypto.js +46 -0
  83. package/dist/platforms/wechat/crypto.js.map +1 -0
  84. package/dist/platforms/wechat/login.d.ts +19 -0
  85. package/dist/platforms/wechat/login.d.ts.map +1 -0
  86. package/dist/platforms/wechat/login.js +71 -0
  87. package/dist/platforms/wechat/login.js.map +1 -0
  88. package/dist/platforms/wechat/message.d.ts +102 -0
  89. package/dist/platforms/wechat/message.d.ts.map +1 -0
  90. package/dist/platforms/wechat/message.js +212 -0
  91. package/dist/platforms/wechat/message.js.map +1 -0
  92. package/dist/platforms/wechat/upload.d.ts +10 -0
  93. package/dist/platforms/wechat/upload.d.ts.map +1 -0
  94. package/dist/platforms/wechat/upload.js +86 -0
  95. package/dist/platforms/wechat/upload.js.map +1 -0
  96. package/dist/xacpp/establish-handler.d.ts +58 -0
  97. package/dist/xacpp/establish-handler.d.ts.map +1 -0
  98. package/dist/xacpp/establish-handler.js +152 -0
  99. package/dist/xacpp/establish-handler.js.map +1 -0
  100. package/dist/xacpp/index.d.ts +3 -0
  101. package/dist/xacpp/index.d.ts.map +1 -0
  102. package/dist/xacpp/index.js +3 -0
  103. package/dist/xacpp/index.js.map +1 -0
  104. package/dist/xacpp/initiator-session-handler.d.ts +30 -0
  105. package/dist/xacpp/initiator-session-handler.d.ts.map +1 -0
  106. package/dist/xacpp/initiator-session-handler.js +233 -0
  107. package/dist/xacpp/initiator-session-handler.js.map +1 -0
  108. package/dist/xacpp/session-handler.d.ts +17 -0
  109. package/dist/xacpp/session-handler.d.ts.map +1 -0
  110. package/dist/xacpp/session-handler.js +27 -0
  111. package/dist/xacpp/session-handler.js.map +1 -0
  112. package/dist/xacpp/stdin-router.d.ts +23 -0
  113. package/dist/xacpp/stdin-router.d.ts.map +1 -0
  114. package/dist/xacpp/stdin-router.js +46 -0
  115. package/dist/xacpp/stdin-router.js.map +1 -0
  116. package/package.json +44 -0
@@ -0,0 +1,212 @@
1
+ import { messageId, channelId, userId, } from '../../core/types.js';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { createLogger } from '../../core/logger.js';
4
+ import { downloadToBuffer, saveTemp } from '../../core/fs-utils.js';
5
+ import { decryptBuffer } from './crypto.js';
6
+ const log = createLogger('WechatMessage');
7
+ // --------------------------------------------------------------------------
8
+ // Standard MessageContent → Weixin send request
9
+ // --------------------------------------------------------------------------
10
+ function contentToText(content) {
11
+ switch (content.type) {
12
+ case 'text':
13
+ return content.text;
14
+ case 'image': {
15
+ const src = content.source;
16
+ if (src.localUri || src.remoteUrl)
17
+ return '[image]';
18
+ return '[image 无法发送]';
19
+ }
20
+ case 'audio': {
21
+ const src = content.source;
22
+ if (src.localUri || src.remoteUrl)
23
+ return '[audio]';
24
+ return '[audio 无法发送]';
25
+ }
26
+ case 'video': {
27
+ const src = content.source;
28
+ if (src.localUri || src.remoteUrl)
29
+ return '[video]';
30
+ return '[video 无法发送]';
31
+ }
32
+ case 'file': {
33
+ const src = content.source;
34
+ const name = (content.type === 'file' ? content.name : undefined)
35
+ || src.remoteUrl.split('/').pop()
36
+ || src.localUri.split('/').pop()
37
+ || 'unknown';
38
+ if (src.localUri || src.remoteUrl)
39
+ return `[file: ${name}]`;
40
+ return '[file 无法发送]';
41
+ }
42
+ }
43
+ }
44
+ export function fromMessageContent(toUserId, content, contextToken) {
45
+ return {
46
+ msg: {
47
+ from_user_id: '',
48
+ to_user_id: toUserId,
49
+ client_id: randomUUID(),
50
+ message_type: 2,
51
+ message_state: 2,
52
+ context_token: contextToken,
53
+ item_list: [{ type: 1, text_item: { text: contentToText(content) } }],
54
+ },
55
+ base_info: { channel_version: '1' },
56
+ };
57
+ }
58
+ function buildMediaItem(content, uploadResult) {
59
+ const media = {
60
+ media: {
61
+ encrypt_query_param: uploadResult.encryptQueryParam,
62
+ aes_key: uploadResult.aesKey,
63
+ encrypt_type: uploadResult.encryptType,
64
+ },
65
+ };
66
+ switch (content.type) {
67
+ case 'image':
68
+ return { type: 2, image_item: { ...media, mid_size: uploadResult.encryptedSize } };
69
+ case 'video':
70
+ return { type: 5, video_item: { ...media, video_size: uploadResult.encryptedSize } };
71
+ case 'audio':
72
+ case 'file': {
73
+ const name = (content.type === 'file' ? content.name : undefined)
74
+ || content.source.remoteUrl.split('/').pop()
75
+ || content.source.localUri.split('/').pop()
76
+ || 'file';
77
+ return {
78
+ type: 4,
79
+ file_item: {
80
+ file_name: name,
81
+ md5: uploadResult.rawMd5,
82
+ len: String(uploadResult.rawSize),
83
+ ...media,
84
+ },
85
+ };
86
+ }
87
+ }
88
+ }
89
+ /** Build a WeChat send request with media upload result. */
90
+ export function fromMessageContentWithUpload(toUserId, content, contextToken, uploadResult) {
91
+ if (content.type === 'text') {
92
+ throw new Error('fromMessageContentWithUpload does not accept text content');
93
+ }
94
+ return {
95
+ msg: {
96
+ from_user_id: '',
97
+ to_user_id: toUserId,
98
+ client_id: randomUUID(),
99
+ message_type: 2,
100
+ message_state: 2,
101
+ context_token: contextToken,
102
+ item_list: [buildMediaItem(content, uploadResult)],
103
+ },
104
+ base_info: { channel_version: '1' },
105
+ };
106
+ }
107
+ // --------------------------------------------------------------------------
108
+ // Weixin message → Standard Message
109
+ // --------------------------------------------------------------------------
110
+ function parseItem(item) {
111
+ if (!item || item.type !== 1) {
112
+ return { type: 'text', text: '' };
113
+ }
114
+ return { type: 'text', text: item.text_item.text };
115
+ }
116
+ export function toStandardMessage(msg) {
117
+ const id = msg.message_id != null ? String(msg.message_id) : (msg.msg_id ?? String(Date.now()));
118
+ return {
119
+ id: messageId(id),
120
+ chatId: channelId(msg.from_user_id),
121
+ senderId: userId(msg.from_user_id),
122
+ content: parseItem(msg.item_list[0]),
123
+ direction: 'incoming',
124
+ };
125
+ }
126
+ // --------------------------------------------------------------------------
127
+ // Inbound media: download → decrypt → detect → save temp
128
+ // --------------------------------------------------------------------------
129
+ const TYPE_LABEL = {
130
+ 2: '图片',
131
+ 3: '语音',
132
+ 4: '文件',
133
+ 5: '视频',
134
+ };
135
+ export async function processInboundMedia(item) {
136
+ if (item.type === 1) {
137
+ return { type: 'text', text: '' };
138
+ }
139
+ let url;
140
+ let aesKey;
141
+ let fileNameHint;
142
+ const raw = item;
143
+ switch (item.type) {
144
+ case 2:
145
+ url = raw.image_item?.media?.full_url;
146
+ aesKey = raw.image_item?.media?.aes_key;
147
+ break;
148
+ case 3:
149
+ url = raw.voice_item?.media?.full_url;
150
+ aesKey = raw.voice_item?.media?.aes_key;
151
+ break;
152
+ case 4:
153
+ url = raw.file_item?.media?.full_url;
154
+ aesKey = raw.file_item?.media?.aes_key;
155
+ fileNameHint = raw.file_item?.file_name;
156
+ break;
157
+ case 5:
158
+ url = raw.video_item?.media?.full_url;
159
+ aesKey = raw.video_item?.media?.aes_key;
160
+ break;
161
+ default:
162
+ throw new Error(`未知媒体类型: ${item.type}`);
163
+ }
164
+ const label = TYPE_LABEL[item.type] ?? '媒体';
165
+ if (!url) {
166
+ throw new Error(`${label}接收失败:缺少下载地址`);
167
+ }
168
+ try {
169
+ const encrypted = await downloadToBuffer(url);
170
+ const decrypted = aesKey
171
+ ? decryptBuffer(encrypted, aesKey)
172
+ : encrypted;
173
+ const meta = await saveTemp(decrypted, url, fileNameHint);
174
+ if (!meta.mimeType) {
175
+ throw new Error(`${label}接收失败:无法识别文件类型`);
176
+ }
177
+ const source = {
178
+ localUri: meta.localUri,
179
+ sha256: meta.sha256,
180
+ sizeBytes: meta.sizeBytes,
181
+ mimeType: meta.mimeType,
182
+ requireOrganized: true,
183
+ remoteUrl: url,
184
+ };
185
+ if (item.type === 4) {
186
+ return fileNameHint
187
+ ? { type: 'file', name: fileNameHint, source }
188
+ : { type: 'file', source };
189
+ }
190
+ const contentType = item.type === 2 ? 'image' : item.type === 3 ? 'audio' : 'video';
191
+ return { type: contentType, source };
192
+ }
193
+ catch (err) {
194
+ const reason = err instanceof Error ? err.message : String(err);
195
+ throw new Error(`${label}接收失败:${reason}`);
196
+ }
197
+ }
198
+ // --------------------------------------------------------------------------
199
+ // Extractors
200
+ // --------------------------------------------------------------------------
201
+ export function extractContextToken(msg) {
202
+ return msg.context_token;
203
+ }
204
+ export function extractText(msg) {
205
+ for (const item of msg.item_list) {
206
+ if (item.type === 1) {
207
+ return item.text_item.text;
208
+ }
209
+ }
210
+ return '';
211
+ }
212
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/platforms/wechat/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface WechatUploadResult {
2
+ encryptQueryParam: string;
3
+ aesKey: string;
4
+ encryptType: number;
5
+ encryptedSize: number;
6
+ rawMd5: string;
7
+ rawSize: number;
8
+ }
9
+ export declare function uploadMedia(baseUrl: string, token: string, xWechatUin: string, filePath: string, mediaType: string, toUserId: string): Promise<WechatUploadResult>;
10
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/platforms/wechat/upload.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAkBD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC,CAkF7B"}
@@ -0,0 +1,86 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
4
+ import { createLogger } from '../../core/logger.js';
5
+ const log = createLogger('WechatUpload');
6
+ import { aesEcbEncrypt, aesEcbDecrypt, generateAesKey, encodeAesKeyForMedia, encodeAesKeyForFile, } from './crypto.js';
7
+ function makeHeaders(token, xWechatUin) {
8
+ return {
9
+ 'Content-Type': 'application/json',
10
+ AuthorizationType: 'ilink_bot_token',
11
+ Authorization: `Bearer ${token}`,
12
+ 'X-WECHAT-UIN': xWechatUin,
13
+ };
14
+ }
15
+ const MEDIA_TYPE_NUM = {
16
+ image: 1,
17
+ video: 2,
18
+ file: 3,
19
+ audio: 4,
20
+ };
21
+ export async function uploadMedia(baseUrl, token, xWechatUin, filePath, mediaType, toUserId) {
22
+ const data = await readFile(filePath);
23
+ const md5 = createHash('md5').update(data).digest('hex');
24
+ const key = generateAesKey();
25
+ const aesKeyEncoded = encodeAesKeyForMedia(key);
26
+ const aesKeyHex = key.toString('hex');
27
+ const encryptedSize = Math.ceil((data.length + 1) / 16) * 16;
28
+ const filekey = randomBytes(16).toString('hex');
29
+ const mediaTypeNum = MEDIA_TYPE_NUM[mediaType] ?? 3;
30
+ // Step 1: get upload URL
31
+ const uploadUrlRes = await fetch(`${baseUrl}/ilink/bot/getuploadurl`, {
32
+ method: 'POST',
33
+ headers: makeHeaders(token, xWechatUin),
34
+ body: JSON.stringify({
35
+ filekey,
36
+ media_type: mediaTypeNum,
37
+ to_user_id: toUserId,
38
+ rawsize: data.length,
39
+ rawfilemd5: md5,
40
+ filesize: encryptedSize,
41
+ no_need_thumb: true,
42
+ aeskey: aesKeyHex,
43
+ base_info: { channel_version: '2.0.0' },
44
+ }),
45
+ signal: AbortSignal.timeout(30_000),
46
+ });
47
+ if (!uploadUrlRes.ok) {
48
+ throw new Error(`WeChat getuploadurl failed: HTTP ${uploadUrlRes.status}`);
49
+ }
50
+ const uploadUrlData = (await uploadUrlRes.json());
51
+ log.debug('getuploadurl OK: type=%s size=%d', mediaType, data.length);
52
+ if (uploadUrlData.ret !== undefined && uploadUrlData.ret !== 0) {
53
+ throw new Error(`WeChat getuploadurl failed: ret=${uploadUrlData.ret}, errcode=${uploadUrlData.errcode}`);
54
+ }
55
+ const uploadParam = uploadUrlData.upload_param;
56
+ if (!uploadParam) {
57
+ throw new Error('WeChat getuploadurl returned no upload_param');
58
+ }
59
+ // Step 2: encrypt and upload
60
+ const encrypted = aesEcbEncrypt(data, key);
61
+ const cdnBaseUrl = 'https://novac2c.cdn.weixin.qq.com/c2c';
62
+ const uploadUrl = `${cdnBaseUrl}/upload?encrypted_query_param=${encodeURIComponent(uploadParam)}&filekey=${filekey}`;
63
+ const uploadRes = await fetch(uploadUrl, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/octet-stream' },
66
+ body: encrypted,
67
+ signal: AbortSignal.timeout(60_000),
68
+ });
69
+ if (!uploadRes.ok) {
70
+ throw new Error(`WeChat upload failed: HTTP ${uploadRes.status}`);
71
+ }
72
+ const encryptQueryParam = uploadRes.headers.get('x-encrypted-param') ?? '';
73
+ if (!encryptQueryParam) {
74
+ throw new Error('WeChat upload failed: missing x-encrypted-param header');
75
+ }
76
+ log.debug('upload complete: encryptQueryParam=%s...', encryptQueryParam.slice(0, 16));
77
+ return {
78
+ encryptQueryParam,
79
+ aesKey: aesKeyEncoded,
80
+ encryptType: 1,
81
+ encryptedSize,
82
+ rawMd5: md5,
83
+ rawSize: data.length,
84
+ };
85
+ }
86
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../../src/platforms/wechat/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { XabotSessionHandler } from './session-handler.js';
2
+ import type { XacppTransport, EstablishHandler, XacppSessionHandler, EstablishDecision } from 'xacpp';
3
+ import type { Bridge } from '../bridge/index.js';
4
+ /**
5
+ * Handles the Establish handshake for xabot acting as the Responder.
6
+ *
7
+ * Flow when !credentials (challenge path):
8
+ * 1. Initiator generates a challenge and shows it to the user.
9
+ * 2. User manually sends the challenge to the bot via Feishu.
10
+ * 3. The cloud message handler calls {@link submitChallenge} with the challenge text and chatId.
11
+ * 4. When Initiator calls `Establish(null)`, the Responder waits for the challenge to arrive
12
+ * (via {@link submitChallenge}), then returns `{ type: 'challenge_required', challenge }`.
13
+ * 5. Initiator compares the challenge and sends `establish_confirm`.
14
+ * 6. Responder creates a session with `credentials = chatId` (the chatId from the cloud message
15
+ * that contained the challenge).
16
+ */
17
+ export declare class XabotEstablishHandler implements EstablishHandler {
18
+ private onSession;
19
+ private bridge;
20
+ private _lastHandler;
21
+ /** Resolver for the Promise returned by onEstablish() when waiting for a challenge. */
22
+ private challengeResolver;
23
+ /** Cached challenge result when submitChallenge() is called before onEstablish() asks for it. */
24
+ private pendingChallengeResult;
25
+ /** The chatId from the cloud message that delivered the challenge. Used as credentials on confirm. */
26
+ private pendingChatId;
27
+ /** WeChat login function — called when no credentials and no challenge available. */
28
+ private loginFn;
29
+ /** Callback to create/connect a cloud client after login or with existing credentials. */
30
+ private ensureCloudFn;
31
+ /** Resolved token from login or credentials parsing. */
32
+ private resolvedBotToken;
33
+ /** Resolved baseUrl from login or credentials parsing. */
34
+ private resolvedBaseUrl;
35
+ onEstablished(callback: (transport: XacppTransport, sessionId: string, credentials: string) => void): void;
36
+ setBridge(bridge: Bridge): void;
37
+ get lastHandler(): XabotSessionHandler | null;
38
+ setLoginFn(fn: () => Promise<{
39
+ token: string;
40
+ baseUrl: string;
41
+ }>): void;
42
+ setEnsureCloudFn(fn: (token: string, baseUrl: string) => Promise<void>): void;
43
+ clearPending(): void;
44
+ /**
45
+ * Called by the cloud message handler when a user sends a challenge string to the bot
46
+ * via Feishu. If onEstablish() is already waiting, this unblocks it immediately;
47
+ * otherwise the result is cached for the next onEstablish() call.
48
+ */
49
+ submitChallenge(challenge: string, chatId: string): void;
50
+ onEstablish(transport: XacppTransport, credentials?: string): Promise<EstablishDecision>;
51
+ onEstablishConfirm(transport: XacppTransport): Promise<{
52
+ sessionId: string;
53
+ handler: XacppSessionHandler;
54
+ credentials: string;
55
+ }>;
56
+ private createSession;
57
+ }
58
+ //# sourceMappingURL=establish-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"establish-handler.d.ts","sourceRoot":"","sources":["../../src/xacpp/establish-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AACtG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,YAAW,gBAAgB;IAC5D,OAAO,CAAC,SAAS,CAA8F;IAC/G,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAoC;IAExD,uFAAuF;IACvF,OAAO,CAAC,iBAAiB,CAA0E;IAEnG,iGAAiG;IACjG,OAAO,CAAC,sBAAsB,CAAsD;IAEpF,sGAAsG;IACtG,OAAO,CAAC,aAAa,CAAuB;IAE5C,qFAAqF;IACrF,OAAO,CAAC,OAAO,CAAoE;IAEnF,0FAA0F;IAC1F,OAAO,CAAC,aAAa,CAAoE;IAEzF,wDAAwD;IACxD,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,0DAA0D;IAC1D,OAAO,CAAC,eAAe,CAAuB;IAE9C,aAAa,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI1G,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,IAAI,WAAW,IAAI,mBAAmB,GAAG,IAAI,CAE5C;IAED,UAAU,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAIvE,gBAAgB,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI7E,YAAY,IAAI,IAAI;IAQpB;;;;OAIG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAWlD,WAAW,CACf,SAAS,EAAE,cAAc,EACzB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,iBAAiB,CAAC;IA6CvB,kBAAkB,CACtB,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,mBAAmB,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IA4BpF,OAAO,CAAC,aAAa;CAiBtB"}
@@ -0,0 +1,152 @@
1
+ import { XabotSessionHandler } from './session-handler.js';
2
+ /**
3
+ * Handles the Establish handshake for xabot acting as the Responder.
4
+ *
5
+ * Flow when !credentials (challenge path):
6
+ * 1. Initiator generates a challenge and shows it to the user.
7
+ * 2. User manually sends the challenge to the bot via Feishu.
8
+ * 3. The cloud message handler calls {@link submitChallenge} with the challenge text and chatId.
9
+ * 4. When Initiator calls `Establish(null)`, the Responder waits for the challenge to arrive
10
+ * (via {@link submitChallenge}), then returns `{ type: 'challenge_required', challenge }`.
11
+ * 5. Initiator compares the challenge and sends `establish_confirm`.
12
+ * 6. Responder creates a session with `credentials = chatId` (the chatId from the cloud message
13
+ * that contained the challenge).
14
+ */
15
+ export class XabotEstablishHandler {
16
+ onSession = null;
17
+ bridge = null;
18
+ _lastHandler = null;
19
+ /** Resolver for the Promise returned by onEstablish() when waiting for a challenge. */
20
+ challengeResolver = null;
21
+ /** Cached challenge result when submitChallenge() is called before onEstablish() asks for it. */
22
+ pendingChallengeResult = null;
23
+ /** The chatId from the cloud message that delivered the challenge. Used as credentials on confirm. */
24
+ pendingChatId = null;
25
+ /** WeChat login function — called when no credentials and no challenge available. */
26
+ loginFn = null;
27
+ /** Callback to create/connect a cloud client after login or with existing credentials. */
28
+ ensureCloudFn = null;
29
+ /** Resolved token from login or credentials parsing. */
30
+ resolvedBotToken = null;
31
+ /** Resolved baseUrl from login or credentials parsing. */
32
+ resolvedBaseUrl = null;
33
+ onEstablished(callback) {
34
+ this.onSession = callback;
35
+ }
36
+ setBridge(bridge) {
37
+ this.bridge = bridge;
38
+ }
39
+ get lastHandler() {
40
+ return this._lastHandler;
41
+ }
42
+ setLoginFn(fn) {
43
+ this.loginFn = fn;
44
+ }
45
+ setEnsureCloudFn(fn) {
46
+ this.ensureCloudFn = fn;
47
+ }
48
+ clearPending() {
49
+ this.pendingChallengeResult = null;
50
+ this.pendingChatId = null;
51
+ this.resolvedBotToken = null;
52
+ this.resolvedBaseUrl = null;
53
+ this.challengeResolver = null;
54
+ }
55
+ /**
56
+ * Called by the cloud message handler when a user sends a challenge string to the bot
57
+ * via Feishu. If onEstablish() is already waiting, this unblocks it immediately;
58
+ * otherwise the result is cached for the next onEstablish() call.
59
+ */
60
+ submitChallenge(challenge, chatId) {
61
+ const result = { challenge, chatId };
62
+ if (this.challengeResolver) {
63
+ const resolve = this.challengeResolver;
64
+ this.challengeResolver = null;
65
+ resolve(result);
66
+ }
67
+ else {
68
+ this.pendingChallengeResult = result;
69
+ }
70
+ }
71
+ async onEstablish(transport, credentials) {
72
+ if (credentials) {
73
+ // Attempt to parse as WeChat JSON credentials
74
+ try {
75
+ const parsed = JSON.parse(credentials);
76
+ if (typeof parsed === 'object' && parsed !== null && 'botToken' in parsed) {
77
+ const { botToken, baseUrl } = parsed;
78
+ if (this.ensureCloudFn) {
79
+ await this.ensureCloudFn(botToken, baseUrl ?? '');
80
+ }
81
+ this.resolvedBotToken = botToken;
82
+ this.resolvedBaseUrl = baseUrl ?? null;
83
+ return this.createSession(transport, credentials);
84
+ }
85
+ }
86
+ catch {
87
+ // Not JSON — treat as Feishu chatId string
88
+ }
89
+ // Feishu path: credentials is a plain chatId string
90
+ return this.createSession(transport, credentials);
91
+ }
92
+ // No credentials — try WeChat login first
93
+ if (this.loginFn && this.ensureCloudFn) {
94
+ const { token, baseUrl } = await this.loginFn();
95
+ await this.ensureCloudFn(token, baseUrl);
96
+ this.resolvedBotToken = token;
97
+ this.resolvedBaseUrl = baseUrl;
98
+ // Fall through to challenge path (same as Feishu)
99
+ }
100
+ // Challenge path: wait for submitChallenge() to deliver the challenge + chatId.
101
+ let result;
102
+ if (this.pendingChallengeResult) {
103
+ result = this.pendingChallengeResult;
104
+ this.pendingChallengeResult = null;
105
+ }
106
+ else {
107
+ result = await new Promise((resolve) => {
108
+ this.challengeResolver = resolve;
109
+ });
110
+ }
111
+ this.pendingChatId = result.chatId;
112
+ return { type: 'challenge_required', challenge: result.challenge };
113
+ }
114
+ async onEstablishConfirm(transport) {
115
+ if (this.pendingChatId === null) {
116
+ throw new Error('no pending challenge to confirm');
117
+ }
118
+ const chatId = this.pendingChatId;
119
+ let credentials;
120
+ if (this.resolvedBotToken !== null) {
121
+ // WeChat: assemble JSON credentials
122
+ credentials = JSON.stringify({
123
+ botToken: this.resolvedBotToken,
124
+ baseUrl: this.resolvedBaseUrl ?? '',
125
+ chatId,
126
+ });
127
+ }
128
+ else {
129
+ // Feishu: plain chatId
130
+ credentials = chatId;
131
+ }
132
+ this.pendingChatId = null;
133
+ this.pendingChallengeResult = null;
134
+ this.resolvedBotToken = null;
135
+ this.resolvedBaseUrl = null;
136
+ const decision = this.createSession(transport, credentials);
137
+ return { sessionId: decision.sessionId, handler: decision.handler, credentials };
138
+ }
139
+ createSession(transport, credentials) {
140
+ const sessionId = crypto.randomUUID();
141
+ const handler = new XabotSessionHandler(sessionId);
142
+ this._lastHandler = handler;
143
+ if (this.bridge) {
144
+ handler.setBridge(this.bridge);
145
+ }
146
+ if (this.onSession) {
147
+ this.onSession(transport, sessionId, credentials);
148
+ }
149
+ return { type: 'established', sessionId, handler, credentials };
150
+ }
151
+ }
152
+ //# sourceMappingURL=establish-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"establish-handler.js","sourceRoot":"","sources":["../../src/xacpp/establish-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { XabotEstablishHandler } from './establish-handler.js';
2
+ export { XabotSessionHandler } from './session-handler.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/xacpp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { XabotEstablishHandler } from './establish-handler.js';
2
+ export { XabotSessionHandler } from './session-handler.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/xacpp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { XacppCommand, XacppActivityEvent, XacppResponse, XacppSessionHandler } from 'xacpp';
2
+ import type { XacppSession } from 'xacpp';
3
+ import { StdinRouter } from './stdin-router.js';
4
+ /**
5
+ * Initiator-side XacppSessionHandler for the `chat` CLI subcommand.
6
+ *
7
+ * Data flow:
8
+ * - **onCommand**: receives `new_activity` / `invoke_activity` / `last_activity` from the Responder.
9
+ * Prints incoming messages to the terminal. For `last_activity`, prompts the user via stdin.
10
+ * - **onEvent**: returns acknowledge (the Initiator does not receive events from the Responder;
11
+ * it sends events via `sendReply()` to push agent replies back).
12
+ * - **sendReply**: sends a `message` command to the Responder, which routes it through
13
+ * Bridge → cloud.send() → Feishu/WeChat.
14
+ */
15
+ export declare class InitiatorSessionHandler implements XacppSessionHandler {
16
+ private readonly router;
17
+ private activityId;
18
+ private cmdResolve;
19
+ constructor(router: StdinRouter);
20
+ onCommand(command: XacppCommand): Promise<XacppResponse>;
21
+ onEvent(_event: XacppActivityEvent): Promise<XacppResponse>;
22
+ private sendEvent;
23
+ /**
24
+ * Send a reply from the terminal user to the Responder,
25
+ * routing text/media through Bridge → cloud.send(),
26
+ * or simulating an Agent completion via /complete.
27
+ */
28
+ sendReply(session: XacppSession, text: string): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=initiator-session-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initiator-session-handler.d.ts","sourceRoot":"","sources":["../../src/xacpp/initiator-session-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,mBAAmB,EAAe,MAAM,OAAO,CAAC;AAC/G,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA2DhD;;;;;;;;;;GAUG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,UAAU,CAA0C;gBAEhD,MAAM,EAAE,WAAW;IAQzB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAgExD,OAAO,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;YAKnD,SAAS;IAKvB;;;;OAIG;IACG,SAAS,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAyFpE"}