qqbot-opencode 1.0.0

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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/bin/qqbot.js +16 -0
  4. package/dist/app.d.ts +2 -0
  5. package/dist/app.d.ts.map +1 -0
  6. package/dist/app.js +154 -0
  7. package/dist/app.js.map +1 -0
  8. package/dist/bundle.cjs +850 -0
  9. package/dist/bundle.js +826 -0
  10. package/dist/config.d.ts +8 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +179 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/handlers/index.d.ts +3 -0
  15. package/dist/handlers/index.d.ts.map +1 -0
  16. package/dist/handlers/index.js +3 -0
  17. package/dist/handlers/index.js.map +1 -0
  18. package/dist/handlers/message.d.ts +8 -0
  19. package/dist/handlers/message.d.ts.map +1 -0
  20. package/dist/handlers/message.js +57 -0
  21. package/dist/handlers/message.js.map +1 -0
  22. package/dist/handlers/session.d.ts +13 -0
  23. package/dist/handlers/session.d.ts.map +1 -0
  24. package/dist/handlers/session.js +104 -0
  25. package/dist/handlers/session.js.map +1 -0
  26. package/dist/opencode/client.d.ts +23 -0
  27. package/dist/opencode/client.d.ts.map +1 -0
  28. package/dist/opencode/client.js +141 -0
  29. package/dist/opencode/client.js.map +1 -0
  30. package/dist/opencode/index.d.ts +2 -0
  31. package/dist/opencode/index.d.ts.map +1 -0
  32. package/dist/opencode/index.js +2 -0
  33. package/dist/opencode/index.js.map +1 -0
  34. package/dist/qq/connection.d.ts +23 -0
  35. package/dist/qq/connection.d.ts.map +1 -0
  36. package/dist/qq/connection.js +188 -0
  37. package/dist/qq/connection.js.map +1 -0
  38. package/dist/qq/index.d.ts +5 -0
  39. package/dist/qq/index.d.ts.map +1 -0
  40. package/dist/qq/index.js +4 -0
  41. package/dist/qq/index.js.map +1 -0
  42. package/dist/qq/parser.d.ts +4 -0
  43. package/dist/qq/parser.d.ts.map +1 -0
  44. package/dist/qq/parser.js +99 -0
  45. package/dist/qq/parser.js.map +1 -0
  46. package/dist/qq/sender.d.ts +28 -0
  47. package/dist/qq/sender.d.ts.map +1 -0
  48. package/dist/qq/sender.js +123 -0
  49. package/dist/qq/sender.js.map +1 -0
  50. package/dist/types.d.ts +47 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +2 -0
  53. package/dist/types.js.map +1 -0
  54. package/package.json +58 -0
  55. package/src/app.ts +204 -0
  56. package/src/config.ts +200 -0
  57. package/src/handlers/index.ts +2 -0
  58. package/src/handlers/message.ts +86 -0
  59. package/src/handlers/session.ts +130 -0
  60. package/src/opencode/client.ts +204 -0
  61. package/src/opencode/index.ts +1 -0
  62. package/src/qq/connection.ts +252 -0
  63. package/src/qq/index.ts +9 -0
  64. package/src/qq/parser.ts +126 -0
  65. package/src/qq/sender.ts +215 -0
  66. package/src/types.ts +52 -0
@@ -0,0 +1,188 @@
1
+ import WebSocket from "ws";
2
+ const INTENTS = {
3
+ GUILDS: 1 << 0,
4
+ GUILD_MEMBERS: 1 << 1,
5
+ PUBLIC_GUILD_MESSAGES: 1 << 30,
6
+ DIRECT_MESSAGE: 1 << 12,
7
+ GROUP_AND_C2C: 1 << 25,
8
+ };
9
+ const FULL_INTENTS = INTENTS.PUBLIC_GUILD_MESSAGES |
10
+ INTENTS.DIRECT_MESSAGE |
11
+ INTENTS.GROUP_AND_C2C;
12
+ const API_BASE = "https://api.sgroup.qq.com";
13
+ const TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken";
14
+ let accessToken = null;
15
+ let sessionId = null;
16
+ let lastSeq = null;
17
+ let reconnectAttempts = 0;
18
+ const MAX_RECONNECT_ATTEMPTS = 10;
19
+ const RECONNECT_DELAY = 5000;
20
+ async function getAccessToken(appId, clientSecret) {
21
+ const response = await fetch(TOKEN_URL, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ },
26
+ body: JSON.stringify({ appId, clientSecret }),
27
+ });
28
+ if (!response.ok) {
29
+ const errorText = await response.text();
30
+ throw new Error(`Failed to get access token: ${response.status} - ${errorText}`);
31
+ }
32
+ const data = (await response.json());
33
+ if (!data.access_token) {
34
+ throw new Error(`Failed to get access token: ${JSON.stringify(data)}`);
35
+ }
36
+ return data.access_token;
37
+ }
38
+ async function getGatewayUrl(token) {
39
+ const response = await fetch(`${API_BASE}/gateway`, {
40
+ method: "GET",
41
+ headers: {
42
+ Authorization: `QQBot ${token}`,
43
+ },
44
+ });
45
+ if (!response.ok) {
46
+ throw new Error(`Failed to get gateway URL: ${response.status}`);
47
+ }
48
+ const data = (await response.json());
49
+ return data.url;
50
+ }
51
+ export async function startQQConnection(options) {
52
+ const { qq, onMessage, onReady, onError, onDisconnect } = options;
53
+ accessToken = await getAccessToken(qq.appId, qq.clientSecret);
54
+ return new Promise((resolve, reject) => {
55
+ let ws = null;
56
+ let heartbeatInterval = null;
57
+ let isReconnecting = false;
58
+ async function connect() {
59
+ const gatewayUrl = await getGatewayUrl(accessToken);
60
+ console.log(`[QQ] Connecting to gateway: ${gatewayUrl}`);
61
+ ws = new WebSocket(gatewayUrl);
62
+ ws.on("open", () => {
63
+ console.log("[QQ] WebSocket connected");
64
+ reconnectAttempts = 0;
65
+ });
66
+ ws.on("message", async (data) => {
67
+ try {
68
+ const rawData = data.toString();
69
+ const payload = JSON.parse(rawData);
70
+ const { op, d, s, t } = payload;
71
+ if (s) {
72
+ lastSeq = s;
73
+ }
74
+ if (op === 10) {
75
+ console.log("[QQ] Hello received");
76
+ if (sessionId && lastSeq !== null) {
77
+ console.log("[QQ] Attempting to resume session");
78
+ ws?.send(JSON.stringify({
79
+ op: 6,
80
+ d: {
81
+ token: `QQBot ${accessToken}`,
82
+ session_id: sessionId,
83
+ seq: lastSeq,
84
+ },
85
+ }));
86
+ }
87
+ else {
88
+ console.log("[QQ] Sending identify with intents:", FULL_INTENTS);
89
+ ws?.send(JSON.stringify({
90
+ op: 2,
91
+ d: {
92
+ token: `QQBot ${accessToken}`,
93
+ intents: FULL_INTENTS,
94
+ shard: [0, 1],
95
+ },
96
+ }));
97
+ }
98
+ const interval = d
99
+ .heartbeat_interval;
100
+ if (heartbeatInterval)
101
+ clearInterval(heartbeatInterval);
102
+ heartbeatInterval = setInterval(() => {
103
+ if (ws?.readyState === WebSocket.OPEN) {
104
+ ws.send(JSON.stringify({ op: 1, d: lastSeq }));
105
+ }
106
+ }, interval);
107
+ }
108
+ else if (op === 0) {
109
+ if (t === "READY") {
110
+ const readyData = d;
111
+ sessionId = readyData.session_id;
112
+ console.log("[QQ] Ready, session:", sessionId);
113
+ onReady?.();
114
+ }
115
+ else if (t === "C2C_MESSAGE_CREATE") {
116
+ const event = d;
117
+ if (event.author?.user_openid) {
118
+ onMessage(event);
119
+ }
120
+ }
121
+ }
122
+ else if (op === 7) {
123
+ console.log("[QQ] Server requested reconnect");
124
+ cleanup();
125
+ scheduleReconnect();
126
+ }
127
+ else if (op === 9) {
128
+ const canResume = d;
129
+ console.log("[QQ] Invalid session, can resume:", canResume);
130
+ if (!canResume) {
131
+ sessionId = null;
132
+ lastSeq = null;
133
+ }
134
+ cleanup();
135
+ scheduleReconnect();
136
+ }
137
+ }
138
+ catch (err) {
139
+ console.error("[QQ] Message parse error:", err);
140
+ }
141
+ });
142
+ ws.on("close", (code, reason) => {
143
+ console.log(`[QQ] WebSocket closed: ${code} ${reason.toString()}`);
144
+ cleanup();
145
+ if (!isReconnecting) {
146
+ onDisconnect?.();
147
+ scheduleReconnect();
148
+ }
149
+ });
150
+ ws.on("error", (err) => {
151
+ console.error("[QQ] WebSocket error:", err.message);
152
+ onError?.(new Error(err.message));
153
+ });
154
+ }
155
+ function cleanup() {
156
+ if (heartbeatInterval) {
157
+ clearInterval(heartbeatInterval);
158
+ heartbeatInterval = null;
159
+ }
160
+ }
161
+ function scheduleReconnect() {
162
+ if (isReconnecting)
163
+ return;
164
+ if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
165
+ console.error("[QQ] Max reconnect attempts reached");
166
+ reject(new Error("Max reconnect attempts reached"));
167
+ return;
168
+ }
169
+ isReconnecting = true;
170
+ reconnectAttempts++;
171
+ const delay = RECONNECT_DELAY * reconnectAttempts;
172
+ console.log(`[QQ] Reconnecting in ${delay}ms (attempt ${reconnectAttempts})`);
173
+ setTimeout(async () => {
174
+ isReconnecting = false;
175
+ try {
176
+ accessToken = await getAccessToken(qq.appId, qq.clientSecret);
177
+ await connect();
178
+ }
179
+ catch (err) {
180
+ console.error("[QQ] Reconnect failed:", err);
181
+ scheduleReconnect();
182
+ }
183
+ }, delay);
184
+ }
185
+ connect().catch(reject);
186
+ });
187
+ }
188
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/qq/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { startQQConnection } from "./connection.js";
2
+ export { sendC2CMessage, sendC2CImageMessage, sendC2CFileMessage, clearTokenCache, } from "./sender.js";
3
+ export { parseMessage, chunkText } from "./parser.js";
4
+ export type { QQMessageEvent, ParsedMessage } from "../types.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/qq/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { startQQConnection } from "./connection.js";
2
+ export { sendC2CMessage, sendC2CImageMessage, sendC2CFileMessage, clearTokenCache, } from "./sender.js";
3
+ export { parseMessage, chunkText } from "./parser.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/qq/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { QQMessageEvent, ParsedMessage } from "../types.js";
2
+ export declare function parseMessage(event: QQMessageEvent): ParsedMessage;
3
+ export declare function chunkText(text: string, limit: number): string[];
4
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/qq/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjE,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,aAAa,CAiBjE;AA6DD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAmC/D"}
@@ -0,0 +1,99 @@
1
+ const FACE_TAG_REGEX = /<face name="([^"]+)"[^/]*\/>/gi;
2
+ export function parseMessage(event) {
3
+ let content = event.content;
4
+ content = parseFaceTags(content);
5
+ content = content.trim();
6
+ const imageUrls = extractImageUrls(content);
7
+ content = removeImageUrls(content);
8
+ const { quoteRef, quoteId } = parseQuoteRef(event);
9
+ return {
10
+ content,
11
+ imageUrls,
12
+ quoteRef,
13
+ quoteId,
14
+ };
15
+ }
16
+ function parseFaceTags(content) {
17
+ let result = content;
18
+ let match;
19
+ FACE_TAG_REGEX.lastIndex = 0;
20
+ while ((match = FACE_TAG_REGEX.exec(content)) !== null) {
21
+ const faceName = match[1];
22
+ result = result.replace(match[0], `[表情:${faceName}]`);
23
+ }
24
+ return result;
25
+ }
26
+ function extractImageUrls(content) {
27
+ const urls = [];
28
+ let match;
29
+ const regex = /https?:\/\/[^\s"'<>]+\.(?:png|jpg|jpeg|gif|webp)(?:\?[^\s"'<>]*)?/gi;
30
+ while ((match = regex.exec(content)) !== null) {
31
+ urls.push(match[0]);
32
+ }
33
+ return urls;
34
+ }
35
+ function removeImageUrls(content) {
36
+ return content
37
+ .replace(/https?:\/\/[^\s"'<>]+\.(?:png|jpg|jpeg|gif|webp)(?:\?[^\s"'<>]*)?/gi, "")
38
+ .trim();
39
+ }
40
+ function parseQuoteRef(event) {
41
+ const ext = event.message_scene?.ext;
42
+ if (!ext) {
43
+ return {};
44
+ }
45
+ try {
46
+ const scene = JSON.parse(ext);
47
+ if (scene?.refMsgIdx) {
48
+ return {
49
+ quoteRef: String(scene.refMsgIdx),
50
+ quoteId: scene.refMsgIdx,
51
+ };
52
+ }
53
+ }
54
+ catch {
55
+ // ignore parse errors
56
+ }
57
+ return {};
58
+ }
59
+ export function chunkText(text, limit) {
60
+ if (!text || text.length === 0) {
61
+ return [];
62
+ }
63
+ if (text.length <= limit) {
64
+ return [text];
65
+ }
66
+ const chunks = [];
67
+ const lines = text.split("\n");
68
+ let currentChunk = "";
69
+ for (const line of lines) {
70
+ if (currentChunk.length + line.length + 1 <= limit) {
71
+ currentChunk += (currentChunk ? "\n" : "") + line;
72
+ }
73
+ else {
74
+ if (currentChunk) {
75
+ chunks.push(currentChunk);
76
+ }
77
+ if (line.length <= limit) {
78
+ currentChunk = line;
79
+ }
80
+ else {
81
+ const subChunks = splitLongLine(line, limit);
82
+ chunks.push(...subChunks.slice(0, -1));
83
+ currentChunk = subChunks[subChunks.length - 1] || "";
84
+ }
85
+ }
86
+ }
87
+ if (currentChunk) {
88
+ chunks.push(currentChunk);
89
+ }
90
+ return chunks;
91
+ }
92
+ function splitLongLine(line, limit) {
93
+ const chunks = [];
94
+ for (let i = 0; i < line.length; i += limit) {
95
+ chunks.push(line.slice(i, i + limit));
96
+ }
97
+ return chunks;
98
+ }
99
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/qq/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ interface SendMessageOptions {
2
+ toOpenid: string;
3
+ content: string;
4
+ messageId: string;
5
+ quoteRef?: string;
6
+ markdown?: boolean;
7
+ }
8
+ interface QQAccount {
9
+ appId: string;
10
+ clientSecret: string;
11
+ markdownSupport?: boolean;
12
+ }
13
+ export declare function sendC2CMessage(account: QQAccount, options: SendMessageOptions): Promise<void>;
14
+ export declare function sendC2CImageMessage(account: QQAccount, options: {
15
+ toOpenid: string;
16
+ imageUrl: string;
17
+ messageId: string;
18
+ }): Promise<void>;
19
+ export declare function sendC2CFileMessage(account: QQAccount, options: {
20
+ toOpenid: string;
21
+ fileData?: string;
22
+ fileUrl?: string;
23
+ fileName: string;
24
+ messageId: string;
25
+ }): Promise<void>;
26
+ export declare function clearTokenCache(): void;
27
+ export {};
28
+ //# sourceMappingURL=sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../src/qq/sender.ts"],"names":[],"mappings":"AAOA,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA6ED,wBAAsB,cAAc,CAClC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,123 @@
1
+ import crypto from "crypto";
2
+ const API_BASE = "https://api.sgroup.qq.com";
3
+ const TOKEN_URL = "https://bots.qq.com/app/getAppAccessToken";
4
+ let tokenCache = null;
5
+ async function getAccessToken(appId, clientSecret) {
6
+ if (tokenCache && Date.now() < tokenCache.expiresAt - 60000) {
7
+ return tokenCache.token;
8
+ }
9
+ const response = await fetch(TOKEN_URL, {
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ },
14
+ body: JSON.stringify({ appId, clientSecret }),
15
+ });
16
+ if (!response.ok) {
17
+ const errorText = await response.text();
18
+ throw new Error(`Failed to get access token: ${response.status} - ${errorText}`);
19
+ }
20
+ const data = (await response.json());
21
+ if (!data.access_token) {
22
+ throw new Error(`Failed to get access token: ${JSON.stringify(data)}`);
23
+ }
24
+ tokenCache = {
25
+ token: data.access_token,
26
+ expiresAt: Date.now() + (data.expires_in ?? 7200) * 1000,
27
+ };
28
+ return tokenCache.token;
29
+ }
30
+ function getNextMsgSeq(msgId) {
31
+ const hash = crypto.createHash("md5").update(msgId).digest("hex");
32
+ return (parseInt(hash.substring(0, 8), 16) % 9007199254740990) + 1;
33
+ }
34
+ async function apiRequest(accessToken, method, path, body) {
35
+ const url = `${API_BASE}${path}`;
36
+ const response = await fetch(url, {
37
+ method,
38
+ headers: {
39
+ Authorization: `QQBot ${accessToken}`,
40
+ "Content-Type": "application/json",
41
+ },
42
+ body: body ? JSON.stringify(body) : undefined,
43
+ });
44
+ if (!response.ok) {
45
+ const errorText = await response.text();
46
+ throw new Error(`API Error [${path}]: ${response.status} - ${errorText}`);
47
+ }
48
+ return response.json();
49
+ }
50
+ export async function sendC2CMessage(account, options) {
51
+ const token = await getAccessToken(account.appId, account.clientSecret);
52
+ const msgSeq = getNextMsgSeq(options.messageId);
53
+ const useMarkdown = options.markdown ?? account.markdownSupport ?? false;
54
+ let body;
55
+ if (useMarkdown) {
56
+ body = {
57
+ markdown: { content: options.content },
58
+ msg_type: 2,
59
+ msg_seq: msgSeq,
60
+ msg_id: options.messageId,
61
+ };
62
+ }
63
+ else {
64
+ body = {
65
+ content: options.content,
66
+ msg_type: 0,
67
+ msg_seq: msgSeq,
68
+ msg_id: options.messageId,
69
+ };
70
+ }
71
+ if (options.quoteRef && !useMarkdown) {
72
+ body.message_reference = { message_id: options.quoteRef };
73
+ }
74
+ await apiRequest(token, "POST", `/v2/users/${options.toOpenid}/messages`, body);
75
+ }
76
+ export async function sendC2CImageMessage(account, options) {
77
+ const token = await getAccessToken(account.appId, account.clientSecret);
78
+ const msgSeq = getNextMsgSeq(options.messageId);
79
+ let imageData = options.imageUrl;
80
+ if (!imageData.startsWith("http://") && !imageData.startsWith("https://")) {
81
+ const fs = await import("fs");
82
+ const buffer = fs.readFileSync(imageData);
83
+ const base64 = buffer.toString("base64");
84
+ const ext = imageData.split(".").pop()?.toLowerCase() || "png";
85
+ const mimeTypes = {
86
+ jpg: "image/jpeg",
87
+ jpeg: "image/jpeg",
88
+ png: "image/png",
89
+ gif: "image/gif",
90
+ webp: "image/webp",
91
+ };
92
+ const mimeType = mimeTypes[ext] || "image/png";
93
+ imageData = `data:${mimeType};base64,${base64}`;
94
+ }
95
+ const body = {
96
+ content: imageData,
97
+ msg_type: 7,
98
+ msg_seq: msgSeq,
99
+ msg_id: options.messageId,
100
+ };
101
+ await apiRequest(token, "POST", `/v2/users/${options.toOpenid}/messages`, body);
102
+ }
103
+ export async function sendC2CFileMessage(account, options) {
104
+ const token = await getAccessToken(account.appId, account.clientSecret);
105
+ const msgSeq = getNextMsgSeq(options.messageId);
106
+ const body = {
107
+ file_name: options.fileName,
108
+ msg_type: 6,
109
+ msg_seq: msgSeq,
110
+ msg_id: options.messageId,
111
+ };
112
+ if (options.fileData) {
113
+ body.file_data = options.fileData;
114
+ }
115
+ else if (options.fileUrl) {
116
+ body.file_url = options.fileUrl;
117
+ }
118
+ await apiRequest(token, "POST", `/v2/users/${options.toOpenid}/messages`, body);
119
+ }
120
+ export function clearTokenCache() {
121
+ tokenCache = null;
122
+ }
123
+ //# sourceMappingURL=sender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sender.js","sourceRoot":"","sources":["../../src/qq/sender.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ export interface QQConfig {
2
+ appId: string;
3
+ clientSecret: string;
4
+ markdownSupport?: boolean;
5
+ }
6
+ export interface OpencodeConfig {
7
+ port: number;
8
+ hostname: string;
9
+ config?: Record<string, unknown>;
10
+ }
11
+ export interface AppConfig {
12
+ workingDir: string;
13
+ }
14
+ export interface Config {
15
+ qq: QQConfig;
16
+ opencode: OpencodeConfig;
17
+ app: AppConfig;
18
+ }
19
+ export interface QQMessageEvent {
20
+ id: string;
21
+ content: string;
22
+ timestamp: number;
23
+ author: {
24
+ user_openid: string;
25
+ username?: string;
26
+ };
27
+ attachments?: Array<{
28
+ url?: string;
29
+ file_type?: number;
30
+ name?: string;
31
+ }>;
32
+ message_scene?: {
33
+ ext?: string;
34
+ };
35
+ }
36
+ export interface ParsedMessage {
37
+ content: string;
38
+ imageUrls: string[];
39
+ quoteRef?: string;
40
+ quoteId?: string;
41
+ }
42
+ export interface SessionInfo {
43
+ id: string;
44
+ title?: string;
45
+ createdAt: Date;
46
+ }
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,aAAa,CAAC,EAAE;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "qqbot-opencode",
3
+ "version": "1.0.0",
4
+ "description": "QQ Bot powered by OpenCode AI",
5
+ "keywords": [
6
+ "qq",
7
+ "bot",
8
+ "opencode",
9
+ "ai",
10
+ "chatbot",
11
+ "qqbot"
12
+ ],
13
+ "type": "module",
14
+ "main": "dist/app.js",
15
+ "bin": {
16
+ "qqbot": "./bin/qqbot.js"
17
+ },
18
+ "scripts": {
19
+ "dev": "tsx src/app.ts",
20
+ "build": "tsc",
21
+ "start": "node dist/app.js",
22
+ "lint": "eslint src --ext .ts",
23
+ "lint:fix": "eslint src --ext .ts --fix",
24
+ "format": "prettier --write \"src/**/*.ts\"",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "echo \"No tests yet\" && exit 0",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "dependencies": {
30
+ "@opencode-ai/sdk": "^1.2.27",
31
+ "js-yaml": "^4.1.0",
32
+ "prompts": "^2.4.2",
33
+ "ws": "^8.18.0"
34
+ },
35
+ "devDependencies": {
36
+ "@eslint/js": "^10.0.1",
37
+ "@types/js-yaml": "^4.0.9",
38
+ "@types/node": "^20.0.0",
39
+ "@types/prompts": "^2.4.9",
40
+ "@types/ws": "^8.5.0",
41
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
42
+ "@typescript-eslint/parser": "^8.57.1",
43
+ "eslint": "^10.1.0",
44
+ "eslint-config-prettier": "^10.1.8",
45
+ "eslint-plugin-prettier": "^5.5.5",
46
+ "prettier": "^3.8.1",
47
+ "tsx": "^4.7.0",
48
+ "typescript": "^5.9.3"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ },
53
+ "files": [
54
+ "dist/",
55
+ "bin/",
56
+ "src/"
57
+ ]
58
+ }