codeksei 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +661 -661
  2. package/README.en.md +109 -47
  3. package/README.md +79 -58
  4. package/bin/cyberboss.js +1 -1
  5. package/package.json +86 -86
  6. package/scripts/open_shared_wechat_thread.sh +77 -77
  7. package/scripts/open_wechat_thread.sh +108 -108
  8. package/scripts/shared-common.js +144 -144
  9. package/scripts/shared-open.js +14 -14
  10. package/scripts/shared-start.js +5 -5
  11. package/scripts/shared-status.js +27 -27
  12. package/scripts/show_shared_status.sh +45 -45
  13. package/scripts/start_shared_app_server.sh +52 -52
  14. package/scripts/start_shared_wechat.sh +94 -94
  15. package/scripts/timeline-screenshot.sh +14 -14
  16. package/src/adapters/channel/weixin/account-store.js +99 -99
  17. package/src/adapters/channel/weixin/api-v2.js +50 -50
  18. package/src/adapters/channel/weixin/api.js +169 -169
  19. package/src/adapters/channel/weixin/context-token-store.js +84 -84
  20. package/src/adapters/channel/weixin/index.js +618 -604
  21. package/src/adapters/channel/weixin/legacy.js +579 -566
  22. package/src/adapters/channel/weixin/media-mime.js +22 -22
  23. package/src/adapters/channel/weixin/media-receive.js +370 -370
  24. package/src/adapters/channel/weixin/media-send.js +102 -102
  25. package/src/adapters/channel/weixin/message-utils-v2.js +282 -282
  26. package/src/adapters/channel/weixin/message-utils.js +199 -199
  27. package/src/adapters/channel/weixin/redact.js +41 -41
  28. package/src/adapters/channel/weixin/reminder-queue-store.js +101 -101
  29. package/src/adapters/channel/weixin/sync-buffer-store.js +35 -35
  30. package/src/adapters/runtime/codex/events.js +215 -215
  31. package/src/adapters/runtime/codex/index.js +109 -104
  32. package/src/adapters/runtime/codex/message-utils.js +95 -95
  33. package/src/adapters/runtime/codex/model-catalog.js +106 -106
  34. package/src/adapters/runtime/codex/protocol-leak-monitor.js +75 -75
  35. package/src/adapters/runtime/codex/rpc-client.js +339 -339
  36. package/src/adapters/runtime/codex/session-store.js +286 -286
  37. package/src/app/channel-send-file-cli.js +57 -57
  38. package/src/app/diary-write-cli.js +236 -88
  39. package/src/app/note-sync-cli.js +2 -2
  40. package/src/app/reminder-write-cli.js +215 -210
  41. package/src/app/review-cli.js +7 -5
  42. package/src/app/system-checkin-poller.js +64 -64
  43. package/src/app/system-send-cli.js +129 -129
  44. package/src/app/timeline-event-cli.js +28 -25
  45. package/src/app/timeline-screenshot-cli.js +103 -100
  46. package/src/core/app.js +1763 -1763
  47. package/src/core/branding.js +2 -1
  48. package/src/core/command-registry.js +381 -369
  49. package/src/core/config.js +30 -14
  50. package/src/core/default-targets.js +163 -163
  51. package/src/core/durable-note-schema.js +9 -8
  52. package/src/core/instructions-template.js +17 -16
  53. package/src/core/note-sync.js +8 -7
  54. package/src/core/path-utils.js +54 -0
  55. package/src/core/project-radar.js +11 -10
  56. package/src/core/review.js +48 -50
  57. package/src/core/stream-delivery.js +1162 -983
  58. package/src/core/system-message-dispatcher.js +68 -68
  59. package/src/core/system-message-queue-store.js +128 -128
  60. package/src/core/thread-state-store.js +96 -96
  61. package/src/core/timeline-screenshot-queue-store.js +134 -134
  62. package/src/core/timezone.js +436 -0
  63. package/src/core/workspace-bootstrap.js +9 -1
  64. package/src/index.js +148 -146
  65. package/src/integrations/timeline/index.js +130 -74
  66. package/src/integrations/timeline/state-sync.js +240 -0
  67. package/templates/weixin-instructions.md +12 -38
  68. package/templates/weixin-operations.md +29 -31
@@ -1,282 +1,282 @@
1
- const MESSAGE_TYPE_USER = 1;
2
- const MESSAGE_TYPE_BOT = 2;
3
- const MESSAGE_ITEM_TEXT = 1;
4
- const MESSAGE_ITEM_IMAGE = 2;
5
- const MESSAGE_ITEM_VOICE = 3;
6
- const MESSAGE_ITEM_FILE = 4;
7
- const MESSAGE_ITEM_VIDEO = 5;
8
- const DEDUP_TTL_MS = 5 * 60_000;
9
-
10
- function createInboundFilter() {
11
- const seen = new Map();
12
-
13
- return {
14
- normalize(message, config, accountId) {
15
- if (!message || typeof message !== "object") {
16
- return null;
17
- }
18
- const messageType = Number(message.message_type);
19
- if (messageType === MESSAGE_TYPE_BOT) {
20
- return null;
21
- }
22
- if (messageType !== 0 && messageType !== MESSAGE_TYPE_USER) {
23
- return null;
24
- }
25
-
26
- const senderId = normalizeText(message.from_user_id);
27
- if (!senderId) {
28
- return null;
29
- }
30
-
31
- const createdAtMs = normalizeMessageTimestampMs(message);
32
-
33
- const dedupKey = buildDedupKey(message, senderId, createdAtMs);
34
- pruneSeen(seen);
35
- if (dedupKey && seen.has(dedupKey)) {
36
- return null;
37
- }
38
- if (dedupKey) {
39
- seen.set(dedupKey, Date.now());
40
- }
41
-
42
- const itemList = Array.isArray(message.item_list) ? message.item_list : [];
43
- const text = bodyFromItemList(itemList);
44
- const attachments = extractAttachmentItems(itemList);
45
- if (!text && !attachments.length) {
46
- return null;
47
- }
48
-
49
- return {
50
- provider: "weixin",
51
- accountId,
52
- workspaceId: config.workspaceId,
53
- senderId,
54
- chatId: senderId,
55
- messageId: normalizeMessageId(message),
56
- threadKey: normalizeText(message.session_id),
57
- text,
58
- attachments,
59
- contextToken: normalizeText(message.context_token),
60
- receivedAt: createdAtMs > 0 ? new Date(createdAtMs).toISOString() : new Date().toISOString(),
61
- };
62
- },
63
- };
64
- }
65
-
66
- function bodyFromItemList(items) {
67
- if (!Array.isArray(items) || !items.length) {
68
- return "";
69
- }
70
- for (const item of items) {
71
- const itemType = Number(item?.type);
72
- if (itemType === MESSAGE_ITEM_TEXT) {
73
- const text = normalizeText(item?.text_item?.text);
74
- if (!text) {
75
- continue;
76
- }
77
- const ref = item?.ref_msg;
78
- if (!ref || !ref.message_item || isMediaItemType(Number(ref.message_item.type))) {
79
- return text;
80
- }
81
- const parts = [];
82
- const refTitle = normalizeText(ref.title);
83
- if (refTitle) {
84
- parts.push(refTitle);
85
- }
86
- const refBody = bodyFromItemList([ref.message_item]);
87
- if (refBody) {
88
- parts.push(refBody);
89
- }
90
- if (!parts.length) {
91
- return text;
92
- }
93
- return `[引用: ${parts.join(" | ")}]\n${text}`;
94
- }
95
- if (itemType === MESSAGE_ITEM_VOICE) {
96
- const voiceText = normalizeText(item?.voice_item?.text);
97
- if (voiceText) {
98
- return voiceText;
99
- }
100
- }
101
- }
102
- return "";
103
- }
104
-
105
- function isMediaItemType(type) {
106
- return type === MESSAGE_ITEM_IMAGE || type === MESSAGE_ITEM_VOICE || type === MESSAGE_ITEM_FILE || type === MESSAGE_ITEM_VIDEO;
107
- }
108
-
109
- function extractAttachmentItems(itemList) {
110
- if (!Array.isArray(itemList) || !itemList.length) {
111
- return [];
112
- }
113
-
114
- const attachments = [];
115
- for (let index = 0; index < itemList.length; index += 1) {
116
- const normalized = normalizeAttachmentItem(itemList[index], index);
117
- if (normalized) {
118
- attachments.push(normalized);
119
- }
120
- }
121
- return attachments;
122
- }
123
-
124
- function normalizeAttachmentItem(item, index) {
125
- const itemType = Number(item?.type);
126
- const payload = resolveAttachmentPayload(itemType, item);
127
- if (!payload) {
128
- return null;
129
- }
130
-
131
- const media = payload.media && typeof payload.media === "object"
132
- ? payload.media
133
- : {};
134
-
135
- return {
136
- kind: payload.kind,
137
- itemType,
138
- index,
139
- fileName: normalizeText(
140
- payload.body?.file_name
141
- || payload.body?.filename
142
- || item?.file_name
143
- || item?.filename
144
- ),
145
- sizeBytes: parseOptionalInt(
146
- payload.body?.len
147
- || payload.body?.file_size
148
- || payload.body?.size
149
- || payload.body?.video_size
150
- || item?.len
151
- ),
152
- directUrls: collectStringValues([
153
- payload.body?.url,
154
- payload.body?.download_url,
155
- payload.body?.cdn_url,
156
- media?.url,
157
- media?.download_url,
158
- media?.cdn_url,
159
- ]),
160
- mediaRef: {
161
- encryptQueryParam: normalizeText(
162
- media?.encrypt_query_param
163
- || media?.encrypted_query_param
164
- || payload.body?.encrypt_query_param
165
- || payload.body?.encrypted_query_param
166
- || item?.encrypt_query_param
167
- || item?.encrypted_query_param
168
- ),
169
- aesKey: normalizeText(
170
- media?.aes_key
171
- || payload.body?.aes_key
172
- || item?.aes_key
173
- ),
174
- aesKeyHex: normalizeText(
175
- payload.body?.aeskey
176
- || payload.body?.aes_key_hex
177
- || item?.aeskey
178
- ),
179
- encryptType: Number(
180
- media?.encrypt_type
181
- ?? payload.body?.encrypt_type
182
- ?? item?.encrypt_type
183
- ?? 1
184
- ),
185
- fileKey: normalizeText(
186
- media?.filekey
187
- || payload.body?.filekey
188
- || item?.filekey
189
- ),
190
- },
191
- rawItem: item,
192
- };
193
- }
194
-
195
- function resolveAttachmentPayload(itemType, item) {
196
- if (itemType === MESSAGE_ITEM_IMAGE && item?.image_item && typeof item.image_item === "object") {
197
- return { kind: "image", body: item.image_item, media: item.image_item.media };
198
- }
199
- if (itemType === MESSAGE_ITEM_FILE && item?.file_item && typeof item.file_item === "object") {
200
- return { kind: "file", body: item.file_item, media: item.file_item.media };
201
- }
202
- if (itemType === MESSAGE_ITEM_VIDEO && item?.video_item && typeof item.video_item === "object") {
203
- return { kind: "video", body: item.video_item, media: item.video_item.media };
204
- }
205
- return null;
206
- }
207
-
208
- function collectStringValues(values) {
209
- const seen = new Set();
210
- const result = [];
211
- for (const value of values) {
212
- const normalized = normalizeText(value);
213
- if (!normalized || seen.has(normalized)) {
214
- continue;
215
- }
216
- seen.add(normalized);
217
- result.push(normalized);
218
- }
219
- return result;
220
- }
221
-
222
- function parseOptionalInt(value) {
223
- if (value == null || value === "") {
224
- return 0;
225
- }
226
- const parsed = Number.parseInt(String(value), 10);
227
- return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
228
- }
229
-
230
- function normalizeMessageId(message) {
231
- const raw = message?.message_id;
232
- if (typeof raw === "number" && Number.isFinite(raw)) {
233
- return String(raw);
234
- }
235
- if (typeof raw === "string") {
236
- return raw.trim();
237
- }
238
- return "";
239
- }
240
-
241
- function normalizeMessageTimestampMs(message) {
242
- const rawMs = Number(message?.create_time_ms);
243
- if (Number.isFinite(rawMs) && rawMs > 0) {
244
- return rawMs;
245
- }
246
- const rawSeconds = Number(message?.create_time);
247
- if (Number.isFinite(rawSeconds) && rawSeconds > 0) {
248
- return rawSeconds * 1000;
249
- }
250
- return 0;
251
- }
252
-
253
- function buildDedupKey(message, senderId, createdAtMs) {
254
- const seq = normalizeNumeric(message?.seq);
255
- const messageId = normalizeNumeric(message?.message_id);
256
- const clientId = normalizeText(message?.client_id);
257
- const parts = [senderId, messageId, seq, createdAtMs || 0, clientId];
258
- return parts.join("|");
259
- }
260
-
261
- function normalizeNumeric(value) {
262
- const num = Number(value);
263
- return Number.isFinite(num) ? String(num) : "0";
264
- }
265
-
266
- function pruneSeen(seen) {
267
- const now = Date.now();
268
- for (const [key, timestamp] of seen.entries()) {
269
- if (now - timestamp > DEDUP_TTL_MS) {
270
- seen.delete(key);
271
- }
272
- }
273
- }
274
-
275
- function normalizeText(value) {
276
- return typeof value === "string" ? value.trim() : "";
277
- }
278
-
279
- module.exports = {
280
- createInboundFilter,
281
- bodyFromItemList,
282
- };
1
+ const MESSAGE_TYPE_USER = 1;
2
+ const MESSAGE_TYPE_BOT = 2;
3
+ const MESSAGE_ITEM_TEXT = 1;
4
+ const MESSAGE_ITEM_IMAGE = 2;
5
+ const MESSAGE_ITEM_VOICE = 3;
6
+ const MESSAGE_ITEM_FILE = 4;
7
+ const MESSAGE_ITEM_VIDEO = 5;
8
+ const DEDUP_TTL_MS = 5 * 60_000;
9
+
10
+ function createInboundFilter() {
11
+ const seen = new Map();
12
+
13
+ return {
14
+ normalize(message, config, accountId) {
15
+ if (!message || typeof message !== "object") {
16
+ return null;
17
+ }
18
+ const messageType = Number(message.message_type);
19
+ if (messageType === MESSAGE_TYPE_BOT) {
20
+ return null;
21
+ }
22
+ if (messageType !== 0 && messageType !== MESSAGE_TYPE_USER) {
23
+ return null;
24
+ }
25
+
26
+ const senderId = normalizeText(message.from_user_id);
27
+ if (!senderId) {
28
+ return null;
29
+ }
30
+
31
+ const createdAtMs = normalizeMessageTimestampMs(message);
32
+
33
+ const dedupKey = buildDedupKey(message, senderId, createdAtMs);
34
+ pruneSeen(seen);
35
+ if (dedupKey && seen.has(dedupKey)) {
36
+ return null;
37
+ }
38
+ if (dedupKey) {
39
+ seen.set(dedupKey, Date.now());
40
+ }
41
+
42
+ const itemList = Array.isArray(message.item_list) ? message.item_list : [];
43
+ const text = bodyFromItemList(itemList);
44
+ const attachments = extractAttachmentItems(itemList);
45
+ if (!text && !attachments.length) {
46
+ return null;
47
+ }
48
+
49
+ return {
50
+ provider: "weixin",
51
+ accountId,
52
+ workspaceId: config.workspaceId,
53
+ senderId,
54
+ chatId: senderId,
55
+ messageId: normalizeMessageId(message),
56
+ threadKey: normalizeText(message.session_id),
57
+ text,
58
+ attachments,
59
+ contextToken: normalizeText(message.context_token),
60
+ receivedAt: createdAtMs > 0 ? new Date(createdAtMs).toISOString() : new Date().toISOString(),
61
+ };
62
+ },
63
+ };
64
+ }
65
+
66
+ function bodyFromItemList(items) {
67
+ if (!Array.isArray(items) || !items.length) {
68
+ return "";
69
+ }
70
+ for (const item of items) {
71
+ const itemType = Number(item?.type);
72
+ if (itemType === MESSAGE_ITEM_TEXT) {
73
+ const text = normalizeText(item?.text_item?.text);
74
+ if (!text) {
75
+ continue;
76
+ }
77
+ const ref = item?.ref_msg;
78
+ if (!ref || !ref.message_item || isMediaItemType(Number(ref.message_item.type))) {
79
+ return text;
80
+ }
81
+ const parts = [];
82
+ const refTitle = normalizeText(ref.title);
83
+ if (refTitle) {
84
+ parts.push(refTitle);
85
+ }
86
+ const refBody = bodyFromItemList([ref.message_item]);
87
+ if (refBody) {
88
+ parts.push(refBody);
89
+ }
90
+ if (!parts.length) {
91
+ return text;
92
+ }
93
+ return `[引用: ${parts.join(" | ")}]\n${text}`;
94
+ }
95
+ if (itemType === MESSAGE_ITEM_VOICE) {
96
+ const voiceText = normalizeText(item?.voice_item?.text);
97
+ if (voiceText) {
98
+ return voiceText;
99
+ }
100
+ }
101
+ }
102
+ return "";
103
+ }
104
+
105
+ function isMediaItemType(type) {
106
+ return type === MESSAGE_ITEM_IMAGE || type === MESSAGE_ITEM_VOICE || type === MESSAGE_ITEM_FILE || type === MESSAGE_ITEM_VIDEO;
107
+ }
108
+
109
+ function extractAttachmentItems(itemList) {
110
+ if (!Array.isArray(itemList) || !itemList.length) {
111
+ return [];
112
+ }
113
+
114
+ const attachments = [];
115
+ for (let index = 0; index < itemList.length; index += 1) {
116
+ const normalized = normalizeAttachmentItem(itemList[index], index);
117
+ if (normalized) {
118
+ attachments.push(normalized);
119
+ }
120
+ }
121
+ return attachments;
122
+ }
123
+
124
+ function normalizeAttachmentItem(item, index) {
125
+ const itemType = Number(item?.type);
126
+ const payload = resolveAttachmentPayload(itemType, item);
127
+ if (!payload) {
128
+ return null;
129
+ }
130
+
131
+ const media = payload.media && typeof payload.media === "object"
132
+ ? payload.media
133
+ : {};
134
+
135
+ return {
136
+ kind: payload.kind,
137
+ itemType,
138
+ index,
139
+ fileName: normalizeText(
140
+ payload.body?.file_name
141
+ || payload.body?.filename
142
+ || item?.file_name
143
+ || item?.filename
144
+ ),
145
+ sizeBytes: parseOptionalInt(
146
+ payload.body?.len
147
+ || payload.body?.file_size
148
+ || payload.body?.size
149
+ || payload.body?.video_size
150
+ || item?.len
151
+ ),
152
+ directUrls: collectStringValues([
153
+ payload.body?.url,
154
+ payload.body?.download_url,
155
+ payload.body?.cdn_url,
156
+ media?.url,
157
+ media?.download_url,
158
+ media?.cdn_url,
159
+ ]),
160
+ mediaRef: {
161
+ encryptQueryParam: normalizeText(
162
+ media?.encrypt_query_param
163
+ || media?.encrypted_query_param
164
+ || payload.body?.encrypt_query_param
165
+ || payload.body?.encrypted_query_param
166
+ || item?.encrypt_query_param
167
+ || item?.encrypted_query_param
168
+ ),
169
+ aesKey: normalizeText(
170
+ media?.aes_key
171
+ || payload.body?.aes_key
172
+ || item?.aes_key
173
+ ),
174
+ aesKeyHex: normalizeText(
175
+ payload.body?.aeskey
176
+ || payload.body?.aes_key_hex
177
+ || item?.aeskey
178
+ ),
179
+ encryptType: Number(
180
+ media?.encrypt_type
181
+ ?? payload.body?.encrypt_type
182
+ ?? item?.encrypt_type
183
+ ?? 1
184
+ ),
185
+ fileKey: normalizeText(
186
+ media?.filekey
187
+ || payload.body?.filekey
188
+ || item?.filekey
189
+ ),
190
+ },
191
+ rawItem: item,
192
+ };
193
+ }
194
+
195
+ function resolveAttachmentPayload(itemType, item) {
196
+ if (itemType === MESSAGE_ITEM_IMAGE && item?.image_item && typeof item.image_item === "object") {
197
+ return { kind: "image", body: item.image_item, media: item.image_item.media };
198
+ }
199
+ if (itemType === MESSAGE_ITEM_FILE && item?.file_item && typeof item.file_item === "object") {
200
+ return { kind: "file", body: item.file_item, media: item.file_item.media };
201
+ }
202
+ if (itemType === MESSAGE_ITEM_VIDEO && item?.video_item && typeof item.video_item === "object") {
203
+ return { kind: "video", body: item.video_item, media: item.video_item.media };
204
+ }
205
+ return null;
206
+ }
207
+
208
+ function collectStringValues(values) {
209
+ const seen = new Set();
210
+ const result = [];
211
+ for (const value of values) {
212
+ const normalized = normalizeText(value);
213
+ if (!normalized || seen.has(normalized)) {
214
+ continue;
215
+ }
216
+ seen.add(normalized);
217
+ result.push(normalized);
218
+ }
219
+ return result;
220
+ }
221
+
222
+ function parseOptionalInt(value) {
223
+ if (value == null || value === "") {
224
+ return 0;
225
+ }
226
+ const parsed = Number.parseInt(String(value), 10);
227
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
228
+ }
229
+
230
+ function normalizeMessageId(message) {
231
+ const raw = message?.message_id;
232
+ if (typeof raw === "number" && Number.isFinite(raw)) {
233
+ return String(raw);
234
+ }
235
+ if (typeof raw === "string") {
236
+ return raw.trim();
237
+ }
238
+ return "";
239
+ }
240
+
241
+ function normalizeMessageTimestampMs(message) {
242
+ const rawMs = Number(message?.create_time_ms);
243
+ if (Number.isFinite(rawMs) && rawMs > 0) {
244
+ return rawMs;
245
+ }
246
+ const rawSeconds = Number(message?.create_time);
247
+ if (Number.isFinite(rawSeconds) && rawSeconds > 0) {
248
+ return rawSeconds * 1000;
249
+ }
250
+ return 0;
251
+ }
252
+
253
+ function buildDedupKey(message, senderId, createdAtMs) {
254
+ const seq = normalizeNumeric(message?.seq);
255
+ const messageId = normalizeNumeric(message?.message_id);
256
+ const clientId = normalizeText(message?.client_id);
257
+ const parts = [senderId, messageId, seq, createdAtMs || 0, clientId];
258
+ return parts.join("|");
259
+ }
260
+
261
+ function normalizeNumeric(value) {
262
+ const num = Number(value);
263
+ return Number.isFinite(num) ? String(num) : "0";
264
+ }
265
+
266
+ function pruneSeen(seen) {
267
+ const now = Date.now();
268
+ for (const [key, timestamp] of seen.entries()) {
269
+ if (now - timestamp > DEDUP_TTL_MS) {
270
+ seen.delete(key);
271
+ }
272
+ }
273
+ }
274
+
275
+ function normalizeText(value) {
276
+ return typeof value === "string" ? value.trim() : "";
277
+ }
278
+
279
+ module.exports = {
280
+ createInboundFilter,
281
+ bodyFromItemList,
282
+ };