clawcenter 0.1.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 (122) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +180 -0
  3. package/bin/clawcenter.js +2 -0
  4. package/dist/center/commands/system-commands.d.ts +15 -0
  5. package/dist/center/commands/system-commands.d.ts.map +1 -0
  6. package/dist/center/commands/system-commands.js +363 -0
  7. package/dist/center/commands/system-commands.js.map +1 -0
  8. package/dist/center/dispatcher.d.ts +32 -0
  9. package/dist/center/dispatcher.d.ts.map +1 -0
  10. package/dist/center/dispatcher.js +264 -0
  11. package/dist/center/dispatcher.js.map +1 -0
  12. package/dist/center/hub.d.ts +16 -0
  13. package/dist/center/hub.d.ts.map +1 -0
  14. package/dist/center/hub.js +214 -0
  15. package/dist/center/hub.js.map +1 -0
  16. package/dist/center/router/engine.d.ts +35 -0
  17. package/dist/center/router/engine.d.ts.map +1 -0
  18. package/dist/center/router/engine.js +106 -0
  19. package/dist/center/router/engine.js.map +1 -0
  20. package/dist/center/router/hashtag.d.ts +15 -0
  21. package/dist/center/router/hashtag.d.ts.map +1 -0
  22. package/dist/center/router/hashtag.js +21 -0
  23. package/dist/center/router/hashtag.js.map +1 -0
  24. package/dist/center/wechat/api.d.ts +131 -0
  25. package/dist/center/wechat/api.d.ts.map +1 -0
  26. package/dist/center/wechat/api.js +205 -0
  27. package/dist/center/wechat/api.js.map +1 -0
  28. package/dist/center/wechat/cdn.d.ts +13 -0
  29. package/dist/center/wechat/cdn.d.ts.map +1 -0
  30. package/dist/center/wechat/cdn.js +100 -0
  31. package/dist/center/wechat/cdn.js.map +1 -0
  32. package/dist/center/wechat/connector.d.ts +51 -0
  33. package/dist/center/wechat/connector.d.ts.map +1 -0
  34. package/dist/center/wechat/connector.js +253 -0
  35. package/dist/center/wechat/connector.js.map +1 -0
  36. package/dist/center/wechat/login.d.ts +13 -0
  37. package/dist/center/wechat/login.d.ts.map +1 -0
  38. package/dist/center/wechat/login.js +81 -0
  39. package/dist/center/wechat/login.js.map +1 -0
  40. package/dist/core/agents/adapter.d.ts +43 -0
  41. package/dist/core/agents/adapter.d.ts.map +1 -0
  42. package/dist/core/agents/adapter.js +2 -0
  43. package/dist/core/agents/adapter.js.map +1 -0
  44. package/dist/core/agents/claude-code.d.ts +19 -0
  45. package/dist/core/agents/claude-code.d.ts.map +1 -0
  46. package/dist/core/agents/claude-code.js +138 -0
  47. package/dist/core/agents/claude-code.js.map +1 -0
  48. package/dist/core/agents/claude-sdk.d.ts +17 -0
  49. package/dist/core/agents/claude-sdk.d.ts.map +1 -0
  50. package/dist/core/agents/claude-sdk.js +85 -0
  51. package/dist/core/agents/claude-sdk.js.map +1 -0
  52. package/dist/core/agents/codebuddy.d.ts +19 -0
  53. package/dist/core/agents/codebuddy.d.ts.map +1 -0
  54. package/dist/core/agents/codebuddy.js +352 -0
  55. package/dist/core/agents/codebuddy.js.map +1 -0
  56. package/dist/core/agents/codex.d.ts +18 -0
  57. package/dist/core/agents/codex.d.ts.map +1 -0
  58. package/dist/core/agents/codex.js +300 -0
  59. package/dist/core/agents/codex.js.map +1 -0
  60. package/dist/core/agents/cursor-agent.d.ts +19 -0
  61. package/dist/core/agents/cursor-agent.d.ts.map +1 -0
  62. package/dist/core/agents/cursor-agent.js +253 -0
  63. package/dist/core/agents/cursor-agent.js.map +1 -0
  64. package/dist/core/agents/http-agent.d.ts +17 -0
  65. package/dist/core/agents/http-agent.d.ts.map +1 -0
  66. package/dist/core/agents/http-agent.js +91 -0
  67. package/dist/core/agents/http-agent.js.map +1 -0
  68. package/dist/core/agents/manager.d.ts +45 -0
  69. package/dist/core/agents/manager.d.ts.map +1 -0
  70. package/dist/core/agents/manager.js +245 -0
  71. package/dist/core/agents/manager.js.map +1 -0
  72. package/dist/core/agents/openclaw.d.ts +19 -0
  73. package/dist/core/agents/openclaw.d.ts.map +1 -0
  74. package/dist/core/agents/openclaw.js +173 -0
  75. package/dist/core/agents/openclaw.js.map +1 -0
  76. package/dist/core/agents/opencode.d.ts +19 -0
  77. package/dist/core/agents/opencode.d.ts.map +1 -0
  78. package/dist/core/agents/opencode.js +175 -0
  79. package/dist/core/agents/opencode.js.map +1 -0
  80. package/dist/core/agents/worker-agent.d.ts +24 -0
  81. package/dist/core/agents/worker-agent.d.ts.map +1 -0
  82. package/dist/core/agents/worker-agent.js +40 -0
  83. package/dist/core/agents/worker-agent.js.map +1 -0
  84. package/dist/core/api/routes.d.ts +6 -0
  85. package/dist/core/api/routes.d.ts.map +1 -0
  86. package/dist/core/api/routes.js +238 -0
  87. package/dist/core/api/routes.js.map +1 -0
  88. package/dist/core/db/schema.d.ts +3 -0
  89. package/dist/core/db/schema.d.ts.map +1 -0
  90. package/dist/core/db/schema.js +97 -0
  91. package/dist/core/db/schema.js.map +1 -0
  92. package/dist/core/db/store.d.ts +167 -0
  93. package/dist/core/db/store.d.ts.map +1 -0
  94. package/dist/core/db/store.js +469 -0
  95. package/dist/core/db/store.js.map +1 -0
  96. package/dist/index.d.ts +2 -0
  97. package/dist/index.d.ts.map +1 -0
  98. package/dist/index.js +70 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/logger.d.ts +6 -0
  101. package/dist/logger.d.ts.map +1 -0
  102. package/dist/logger.js +22 -0
  103. package/dist/logger.js.map +1 -0
  104. package/dist/server.d.ts +28 -0
  105. package/dist/server.d.ts.map +1 -0
  106. package/dist/server.js +158 -0
  107. package/dist/server.js.map +1 -0
  108. package/dist/tui/App.d.ts +78 -0
  109. package/dist/tui/App.d.ts.map +1 -0
  110. package/dist/tui/App.js +106 -0
  111. package/dist/tui/App.js.map +1 -0
  112. package/dist/tui/index.d.ts +7 -0
  113. package/dist/tui/index.d.ts.map +1 -0
  114. package/dist/tui/index.js +12 -0
  115. package/dist/tui/index.js.map +1 -0
  116. package/dist/worker/client.d.ts +28 -0
  117. package/dist/worker/client.d.ts.map +1 -0
  118. package/dist/worker/client.js +142 -0
  119. package/dist/worker/client.js.map +1 -0
  120. package/package.json +74 -0
  121. package/web/dist/assets/index-Bvq27OV5.js +60 -0
  122. package/web/dist/index.html +63 -0
@@ -0,0 +1,106 @@
1
+ import { parseHashtag } from "./hashtag.js";
2
+ import { isSystemCommand } from "../commands/system-commands.js";
3
+ import { debug } from "../../logger.js";
4
+ export class Router {
5
+ deps;
6
+ store;
7
+ agentManager;
8
+ constructor(deps) {
9
+ this.deps = deps;
10
+ this.store = deps.store;
11
+ this.agentManager = deps.agentManager;
12
+ }
13
+ /**
14
+ * Route an inbound message to the appropriate agent.
15
+ * Returns null if the message was handled as a system command.
16
+ */
17
+ async route(msg) {
18
+ const { wechatAccountId, fromUserId, text } = msg;
19
+ // 1. System command?
20
+ if (isSystemCommand(text)) {
21
+ return null; // Handled separately by the dispatcher
22
+ }
23
+ // 2. Parse #hashtag
24
+ const hashtagResult = parseHashtag(text);
25
+ let agentId = hashtagResult?.agentId ?? null;
26
+ let body = hashtagResult?.body ?? text;
27
+ let routedVia = "hashtag";
28
+ // 3. Reply-based routing (if no hashtag)
29
+ if (!agentId && (msg.refMessageId || msg.refMessageText)) {
30
+ debug("Router", `Reply-based routing: refMessageId=${msg.refMessageId ?? "none"}, refText=${msg.refMessageText?.slice(0, 60) ?? "none"}`);
31
+ let refMsg = null;
32
+ // Try exact ID match first
33
+ if (msg.refMessageId) {
34
+ refMsg = this.store.findMessageByWechatMsgId(msg.refMessageId)
35
+ ?? this.store.findMessageByClientId(msg.refMessageId);
36
+ debug("Router", ` ID lookup: ${refMsg ? `found agent=${refMsg.agent_id}` : "not found"}`);
37
+ }
38
+ // Fallback: match by content prefix (for outbound messages whose server ID we don't have)
39
+ if (!refMsg && msg.refMessageText) {
40
+ refMsg = this.store.findOutboundMessageByContent(msg.wechatAccountId, msg.fromUserId, msg.refMessageText.slice(0, 100));
41
+ debug("Router", ` Content fallback: ${refMsg ? `found agent=${refMsg.agent_id}` : "not found"}`);
42
+ }
43
+ if (refMsg) {
44
+ agentId = refMsg.agent_id;
45
+ body = text;
46
+ routedVia = "reply";
47
+ }
48
+ }
49
+ // 4. Sticky routing
50
+ if (!agentId) {
51
+ agentId = this.store.getStickyRoute(wechatAccountId, fromUserId);
52
+ routedVia = "sticky";
53
+ }
54
+ // 5. Default agent
55
+ if (!agentId) {
56
+ agentId = this.store.getDefaultAgent(wechatAccountId, fromUserId);
57
+ routedVia = "default";
58
+ }
59
+ // 6. No agent found at all
60
+ if (!agentId) {
61
+ return null;
62
+ }
63
+ // 7. Permission check
64
+ const allowed = this.store.isAgentAllowed(wechatAccountId, fromUserId, agentId);
65
+ if (!allowed) {
66
+ const allowedAgents = this.store.getAllowedAgents(wechatAccountId, fromUserId);
67
+ throw new PermissionError(agentId, allowedAgents);
68
+ }
69
+ // 8. Check agent exists and is running
70
+ const agentData = this.store.getAgent(agentId);
71
+ if (!agentData) {
72
+ throw new Error(`Agent "${agentId}" not found`);
73
+ }
74
+ const adapter = this.agentManager.getAdapter(agentId);
75
+ if (!adapter || adapter.status !== "running") {
76
+ throw new Error(`Agent "${agentId}" is not running`);
77
+ }
78
+ // 9. Get/create session
79
+ const session = this.store.getOrCreateSession(wechatAccountId, fromUserId, agentId);
80
+ // 10. Update sticky route
81
+ this.store.setStickyRoute(wechatAccountId, fromUserId, agentId);
82
+ return {
83
+ agentId,
84
+ displayName: agentData.display_name,
85
+ body,
86
+ sessionId: session.id,
87
+ agentSessionId: session.agent_session ?? undefined,
88
+ routedVia,
89
+ };
90
+ }
91
+ formatReply(displayName, text) {
92
+ const prefix = this.deps.replyPrefixFormat.replace("{displayName}", displayName);
93
+ return `${prefix} ${text}`;
94
+ }
95
+ }
96
+ export class PermissionError extends Error {
97
+ agentId;
98
+ allowedAgents;
99
+ constructor(agentId, allowedAgents) {
100
+ super(`No permission to access agent "${agentId}"`);
101
+ this.agentId = agentId;
102
+ this.allowedAgents = allowedAgents;
103
+ this.name = "PermissionError";
104
+ }
105
+ }
106
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/center/router/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Parse a #hashtag at the beginning of a message.
3
+ * Supports Unicode (Chinese, etc.) agent names.
4
+ *
5
+ * Examples:
6
+ * "#claude hello world" → { agentId: "claude", body: "hello world" }
7
+ * "#助手 你好" → { agentId: "助手", body: "你好" }
8
+ * "hello world" → null (no hashtag)
9
+ */
10
+ export interface HashtagResult {
11
+ agentId: string;
12
+ body: string;
13
+ }
14
+ export declare function parseHashtag(text: string): HashtagResult | null;
15
+ //# sourceMappingURL=hashtag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashtag.d.ts","sourceRoot":"","sources":["../../../src/center/router/hashtag.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAS/D"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Parse a #hashtag at the beginning of a message.
3
+ * Supports Unicode (Chinese, etc.) agent names.
4
+ *
5
+ * Examples:
6
+ * "#claude hello world" → { agentId: "claude", body: "hello world" }
7
+ * "#助手 你好" → { agentId: "助手", body: "你好" }
8
+ * "hello world" → null (no hashtag)
9
+ */
10
+ const HASHTAG_RE = /^#([\p{L}\p{N}_-]+)\s*/u;
11
+ export function parseHashtag(text) {
12
+ const trimmed = text.trim();
13
+ const match = trimmed.match(HASHTAG_RE);
14
+ if (!match)
15
+ return null;
16
+ return {
17
+ agentId: match[1],
18
+ body: trimmed.slice(match[0].length),
19
+ };
20
+ }
21
+ //# sourceMappingURL=hashtag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashtag.js","sourceRoot":"","sources":["../../../src/center/router/hashtag.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,UAAU,GAAG,yBAAyB,CAAC;AAO7C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACjB,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;KACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,131 @@
1
+ export interface WeixinApiOptions {
2
+ baseUrl: string;
3
+ token?: string | null;
4
+ }
5
+ export declare const MessageItemType: {
6
+ readonly TEXT: 1;
7
+ readonly IMAGE: 2;
8
+ readonly VOICE: 3;
9
+ readonly FILE: 4;
10
+ readonly VIDEO: 5;
11
+ };
12
+ export interface CDNMedia {
13
+ encrypt_query_param?: string;
14
+ aes_key?: string;
15
+ file_size?: number;
16
+ }
17
+ export interface MessageItem {
18
+ type: number;
19
+ text_item?: {
20
+ text: string;
21
+ };
22
+ image_item?: {
23
+ media?: CDNMedia;
24
+ };
25
+ voice_item?: {
26
+ media?: CDNMedia;
27
+ text?: string;
28
+ };
29
+ file_item?: {
30
+ media?: CDNMedia;
31
+ file_name?: string;
32
+ };
33
+ video_item?: {
34
+ media?: CDNMedia;
35
+ };
36
+ ref_msg?: {
37
+ message_id?: string;
38
+ message_item?: MessageItem;
39
+ };
40
+ }
41
+ export interface WeixinMessage {
42
+ message_id?: string;
43
+ from_user_id?: string;
44
+ to_user_id?: string;
45
+ message_type?: number;
46
+ message_state?: number;
47
+ context_token?: string;
48
+ session_id?: string;
49
+ seq?: number;
50
+ create_time_ms?: number;
51
+ item_list?: MessageItem[];
52
+ }
53
+ export interface GetUpdatesResponse {
54
+ ret?: number;
55
+ errcode?: number;
56
+ errmsg?: string;
57
+ msgs?: WeixinMessage[];
58
+ get_updates_buf?: string;
59
+ longpolling_timeout_ms?: number;
60
+ }
61
+ export interface GetConfigResponse {
62
+ ret?: number;
63
+ errcode?: number;
64
+ typing_ticket?: string;
65
+ }
66
+ export declare function getUpdates(opts: {
67
+ baseUrl: string;
68
+ token?: string | null;
69
+ get_updates_buf: string;
70
+ timeoutMs?: number;
71
+ }): Promise<GetUpdatesResponse>;
72
+ export declare function sendMessage(opts: {
73
+ baseUrl: string;
74
+ token?: string | null;
75
+ to: string;
76
+ text: string;
77
+ contextToken?: string;
78
+ }): Promise<{
79
+ clientId: string;
80
+ serverMsgId?: string;
81
+ }>;
82
+ export declare function sendImageMessage(opts: {
83
+ baseUrl: string;
84
+ token?: string | null;
85
+ to: string;
86
+ text?: string;
87
+ contextToken?: string;
88
+ imageAesKey: string;
89
+ encryptQueryParam: string;
90
+ fileSize: number;
91
+ }): Promise<{
92
+ clientId: string;
93
+ serverMsgId?: string;
94
+ }>;
95
+ export declare function getUploadUrl(opts: {
96
+ baseUrl: string;
97
+ token?: string | null;
98
+ }): Promise<{
99
+ upload_url?: string;
100
+ upload_param?: string;
101
+ }>;
102
+ export declare function getConfig(opts: {
103
+ baseUrl: string;
104
+ token?: string | null;
105
+ userId?: string;
106
+ contextToken?: string;
107
+ }): Promise<GetConfigResponse>;
108
+ export declare function sendTyping(opts: {
109
+ baseUrl: string;
110
+ token?: string | null;
111
+ userId: string;
112
+ typingTicket: string;
113
+ status: number;
114
+ }): Promise<void>;
115
+ export declare function getBotQrcode(baseUrl: string, botType?: string): Promise<{
116
+ qrcode?: string;
117
+ qrcode_img_content?: string;
118
+ ret?: number;
119
+ errmsg?: string;
120
+ }>;
121
+ export declare function getQrcodeStatus(baseUrl: string, qrcode: string): Promise<{
122
+ status?: string;
123
+ bot_token?: string;
124
+ baseurl?: string;
125
+ ilink_bot_id?: string;
126
+ ilink_user_id?: string;
127
+ }>;
128
+ export declare function extractTextFromMessage(msg: WeixinMessage): string;
129
+ export declare function getRefMessageId(msg: WeixinMessage): string | null;
130
+ export declare function getRefMessageText(msg: WeixinMessage): string | null;
131
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/center/wechat/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,205 @@
1
+ import crypto from "node:crypto";
2
+ import { debug } from "../../logger.js";
3
+ const CHANNEL_VERSION = "1.0.2";
4
+ function randomWechatUin() {
5
+ const uint32 = crypto.randomBytes(4).readUInt32BE(0);
6
+ return Buffer.from(String(uint32), "utf-8").toString("base64");
7
+ }
8
+ async function apiRequest(baseUrl, path, options = {}) {
9
+ const url = `${baseUrl.replace(/\/$/, "")}/${path}`;
10
+ const method = options.method ?? (options.body ? "POST" : "GET");
11
+ debug("WX-API", `→ ${method} ${url}`);
12
+ const payload = options.body
13
+ ? { ...options.body, base_info: { channel_version: CHANNEL_VERSION } }
14
+ : undefined;
15
+ const bodyStr = payload ? JSON.stringify(payload) : undefined;
16
+ const headers = {
17
+ "Content-Type": "application/json",
18
+ AuthorizationType: "ilink_bot_token",
19
+ "X-WECHAT-UIN": randomWechatUin(),
20
+ };
21
+ if (bodyStr) {
22
+ headers["Content-Length"] = String(Buffer.byteLength(bodyStr, "utf-8"));
23
+ }
24
+ if (options.token) {
25
+ headers.Authorization = `Bearer ${options.token}`;
26
+ }
27
+ const controller = new AbortController();
28
+ const timeout = options.timeoutMs ?? 30_000;
29
+ const timer = setTimeout(() => controller.abort(), timeout);
30
+ try {
31
+ const response = await fetch(url, {
32
+ method,
33
+ headers,
34
+ body: bodyStr,
35
+ signal: controller.signal,
36
+ });
37
+ const text = await response.text();
38
+ debug("WX-API", `← ${response.status} ${url} (${text.length} bytes)`);
39
+ try {
40
+ const parsed = JSON.parse(text);
41
+ if (parsed.ret !== undefined && parsed.ret !== 0) {
42
+ debug("WX-API", ` ret=${parsed.ret} errmsg=${parsed.errmsg ?? "?"}`);
43
+ }
44
+ return parsed;
45
+ }
46
+ catch {
47
+ debug("WX-API", ` Non-JSON response: ${text.slice(0, 300)}`);
48
+ return { ret: -1, errmsg: `Non-JSON response: ${text.slice(0, 200)}` };
49
+ }
50
+ }
51
+ catch (err) {
52
+ debug("WX-API", `✗ ${method} ${url} Error: ${err.message}`);
53
+ throw err;
54
+ }
55
+ finally {
56
+ clearTimeout(timer);
57
+ }
58
+ }
59
+ // ─── Message types ───
60
+ export const MessageItemType = {
61
+ TEXT: 1,
62
+ IMAGE: 2,
63
+ VOICE: 3,
64
+ FILE: 4,
65
+ VIDEO: 5,
66
+ };
67
+ // ─── API functions ───
68
+ export async function getUpdates(opts) {
69
+ return apiRequest(opts.baseUrl, "ilink/bot/getupdates", {
70
+ body: { get_updates_buf: opts.get_updates_buf },
71
+ token: opts.token,
72
+ timeoutMs: opts.timeoutMs ?? 38_000,
73
+ });
74
+ }
75
+ export async function sendMessage(opts) {
76
+ const clientId = `cc-${crypto.randomUUID()}`;
77
+ const resp = await apiRequest(opts.baseUrl, "ilink/bot/sendmessage", {
78
+ body: {
79
+ msg: {
80
+ from_user_id: "",
81
+ to_user_id: opts.to,
82
+ client_id: clientId,
83
+ message_type: 2,
84
+ message_state: 2,
85
+ context_token: opts.contextToken,
86
+ item_list: [{ type: MessageItemType.TEXT, text_item: { text: opts.text } }],
87
+ },
88
+ },
89
+ token: opts.token,
90
+ });
91
+ const serverMsgId = (resp.message_id ?? resp.msg_id ?? resp.msgId);
92
+ debug("WX-API", `sendMessage response keys=${Object.keys(resp).join(",")}, serverMsgId=${serverMsgId ?? "none"}`);
93
+ return { clientId, serverMsgId };
94
+ }
95
+ export async function sendImageMessage(opts) {
96
+ const clientId = `cc-${crypto.randomUUID()}`;
97
+ const items = [];
98
+ if (opts.text) {
99
+ items.push({ type: MessageItemType.TEXT, text_item: { text: opts.text } });
100
+ }
101
+ items.push({
102
+ type: MessageItemType.IMAGE,
103
+ image_item: {
104
+ media: {
105
+ aes_key: opts.imageAesKey,
106
+ encrypt_query_param: opts.encryptQueryParam,
107
+ file_size: opts.fileSize,
108
+ },
109
+ },
110
+ });
111
+ const resp = await apiRequest(opts.baseUrl, "ilink/bot/sendmessage", {
112
+ body: {
113
+ msg: {
114
+ from_user_id: "",
115
+ to_user_id: opts.to,
116
+ client_id: clientId,
117
+ message_type: 2,
118
+ message_state: 2,
119
+ context_token: opts.contextToken,
120
+ item_list: items,
121
+ },
122
+ },
123
+ token: opts.token,
124
+ });
125
+ const serverMsgId = (resp.message_id ?? resp.msg_id ?? resp.msgId);
126
+ return { clientId, serverMsgId };
127
+ }
128
+ export async function getUploadUrl(opts) {
129
+ return apiRequest(opts.baseUrl, "ilink/bot/getuploadurl", {
130
+ body: {},
131
+ token: opts.token,
132
+ });
133
+ }
134
+ export async function getConfig(opts) {
135
+ const body = {};
136
+ if (opts.userId)
137
+ body.ilink_user_id = opts.userId;
138
+ if (opts.contextToken)
139
+ body.context_token = opts.contextToken;
140
+ return apiRequest(opts.baseUrl, "ilink/bot/getconfig", {
141
+ body,
142
+ token: opts.token,
143
+ });
144
+ }
145
+ export async function sendTyping(opts) {
146
+ await apiRequest(opts.baseUrl, "ilink/bot/sendtyping", {
147
+ body: {
148
+ ilink_user_id: opts.userId,
149
+ typing_ticket: opts.typingTicket,
150
+ status: opts.status,
151
+ },
152
+ token: opts.token,
153
+ });
154
+ }
155
+ export async function getBotQrcode(baseUrl, botType = "3") {
156
+ return apiRequest(baseUrl, `ilink/bot/get_bot_qrcode?bot_type=${botType}`, {});
157
+ }
158
+ export async function getQrcodeStatus(baseUrl, qrcode) {
159
+ try {
160
+ return await apiRequest(baseUrl, `ilink/bot/get_qrcode_status?qrcode=${encodeURIComponent(qrcode)}`, { timeoutMs: 40_000 });
161
+ }
162
+ catch (err) {
163
+ if (err.name === "AbortError" || err.message?.includes("aborted")) {
164
+ debug("WX-API", "getQrcodeStatus long-poll timeout, returning wait");
165
+ return { status: "wait" };
166
+ }
167
+ throw err;
168
+ }
169
+ }
170
+ export function extractTextFromMessage(msg) {
171
+ for (const item of msg.item_list ?? []) {
172
+ if (item.type === MessageItemType.TEXT && item.text_item?.text) {
173
+ return item.text_item.text;
174
+ }
175
+ if (item.type === MessageItemType.VOICE && item.voice_item?.text) {
176
+ return `[语音] ${item.voice_item.text}`;
177
+ }
178
+ if (item.type === MessageItemType.IMAGE)
179
+ return "[图片]";
180
+ if (item.type === MessageItemType.FILE)
181
+ return `[文件] ${item.file_item?.file_name ?? ""}`;
182
+ if (item.type === MessageItemType.VIDEO)
183
+ return "[视频]";
184
+ }
185
+ return "";
186
+ }
187
+ export function getRefMessageId(msg) {
188
+ for (const item of msg.item_list ?? []) {
189
+ if (item.ref_msg?.message_id) {
190
+ return item.ref_msg.message_id;
191
+ }
192
+ }
193
+ return null;
194
+ }
195
+ export function getRefMessageText(msg) {
196
+ for (const item of msg.item_list ?? []) {
197
+ if (item.ref_msg?.message_item) {
198
+ const refItem = item.ref_msg.message_item;
199
+ if (refItem.text_item?.text)
200
+ return refItem.text_item.text;
201
+ }
202
+ }
203
+ return null;
204
+ }
205
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/center/wechat/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { CDNMedia } from "./api.js";
2
+ export declare function downloadAndDecryptMedia(media: CDNMedia, cdnBaseUrl?: string, savePath?: string): Promise<Buffer>;
3
+ export declare function encryptAndUploadMedia(filePath: string, opts: {
4
+ baseUrl: string;
5
+ token?: string | null;
6
+ cdnBaseUrl?: string;
7
+ }): Promise<{
8
+ aesKey: string;
9
+ encryptQueryParam: string;
10
+ fileSize: number;
11
+ }>;
12
+ export declare function downloadRemoteToTemp(url: string, tempDir?: string): Promise<string>;
13
+ //# sourceMappingURL=cdn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../../../src/center/wechat/cdn.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAoBzC,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,QAAQ,EACf,UAAU,GAAE,MAAyB,EACrC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAID,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgC1E;AAID,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAgC,GACxC,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
@@ -0,0 +1,100 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { getUploadUrl } from "./api.js";
5
+ const DEFAULT_CDN_BASE = "https://novac2c.cdn.weixin.qq.com/c2c";
6
+ // ─── AES-128-ECB encryption/decryption ───
7
+ function aesEcbEncrypt(data, key) {
8
+ const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
9
+ cipher.setAutoPadding(true);
10
+ return Buffer.concat([cipher.update(data), cipher.final()]);
11
+ }
12
+ function aesEcbDecrypt(data, key) {
13
+ const decipher = crypto.createDecipheriv("aes-128-ecb", key, null);
14
+ decipher.setAutoPadding(true);
15
+ return Buffer.concat([decipher.update(data), decipher.final()]);
16
+ }
17
+ // ─── CDN Download (decrypt) ───
18
+ export async function downloadAndDecryptMedia(media, cdnBaseUrl = DEFAULT_CDN_BASE, savePath) {
19
+ if (!media.encrypt_query_param || !media.aes_key) {
20
+ throw new Error("Media missing encrypt_query_param or aes_key");
21
+ }
22
+ const url = `${cdnBaseUrl}?${media.encrypt_query_param}`;
23
+ const response = await fetch(url);
24
+ if (!response.ok) {
25
+ throw new Error(`CDN download failed: ${response.status}`);
26
+ }
27
+ const encrypted = Buffer.from(await response.arrayBuffer());
28
+ const key = Buffer.from(media.aes_key, "hex");
29
+ const decrypted = aesEcbDecrypt(encrypted, key);
30
+ if (savePath) {
31
+ const dir = path.dirname(savePath);
32
+ if (!fs.existsSync(dir))
33
+ fs.mkdirSync(dir, { recursive: true });
34
+ fs.writeFileSync(savePath, decrypted);
35
+ }
36
+ return decrypted;
37
+ }
38
+ // ─── CDN Upload (encrypt) ───
39
+ export async function encryptAndUploadMedia(filePath, opts) {
40
+ const data = fs.readFileSync(filePath);
41
+ const aesKey = crypto.randomBytes(16);
42
+ const encrypted = aesEcbEncrypt(data, aesKey);
43
+ // Get upload URL from API
44
+ const uploadInfo = await getUploadUrl({ baseUrl: opts.baseUrl, token: opts.token });
45
+ if (!uploadInfo.upload_url) {
46
+ throw new Error("Failed to get upload URL");
47
+ }
48
+ // Upload encrypted data
49
+ const response = await fetch(uploadInfo.upload_url, {
50
+ method: "POST",
51
+ headers: { "Content-Type": "application/octet-stream" },
52
+ body: encrypted,
53
+ });
54
+ if (!response.ok) {
55
+ throw new Error(`CDN upload failed: ${response.status}`);
56
+ }
57
+ const result = await response.json();
58
+ if (!result.encrypt_query_param) {
59
+ throw new Error("Upload response missing encrypt_query_param");
60
+ }
61
+ return {
62
+ aesKey: aesKey.toString("hex"),
63
+ encryptQueryParam: result.encrypt_query_param,
64
+ fileSize: data.length,
65
+ };
66
+ }
67
+ // ─── Download remote URL to temp file ───
68
+ export async function downloadRemoteToTemp(url, tempDir = "/tmp/clawcenter/media") {
69
+ if (!fs.existsSync(tempDir))
70
+ fs.mkdirSync(tempDir, { recursive: true });
71
+ const response = await fetch(url);
72
+ if (!response.ok) {
73
+ throw new Error(`Remote download failed: ${response.status} ${url}`);
74
+ }
75
+ const contentType = response.headers.get("content-type") ?? "";
76
+ const ext = mimeToExt(contentType);
77
+ const filename = `${crypto.randomUUID()}${ext}`;
78
+ const filepath = path.join(tempDir, filename);
79
+ const buffer = Buffer.from(await response.arrayBuffer());
80
+ fs.writeFileSync(filepath, buffer);
81
+ return filepath;
82
+ }
83
+ function mimeToExt(mime) {
84
+ const map = {
85
+ "image/jpeg": ".jpg",
86
+ "image/png": ".png",
87
+ "image/gif": ".gif",
88
+ "image/webp": ".webp",
89
+ "video/mp4": ".mp4",
90
+ "audio/mpeg": ".mp3",
91
+ "audio/wav": ".wav",
92
+ "application/pdf": ".pdf",
93
+ };
94
+ for (const [key, ext] of Object.entries(map)) {
95
+ if (mime.includes(key))
96
+ return ext;
97
+ }
98
+ return ".bin";
99
+ }
100
+ //# sourceMappingURL=cdn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdn.js","sourceRoot":"","sources":["../../../src/center/wechat/cdn.ts"],"names":[],"mappings":"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"}