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,68 +1,68 @@
1
- class SystemMessageDispatcher {
2
- constructor({ queueStore, config, accountId }) {
3
- this.queueStore = queueStore;
4
- this.config = config;
5
- this.accountId = accountId;
6
- }
7
-
8
- hasPending() {
9
- return this.queueStore.hasPendingForAccount(this.accountId);
10
- }
11
-
12
- drainPending() {
13
- return this.queueStore.drainForAccount(this.accountId);
14
- }
15
-
16
- requeue(message) {
17
- return this.queueStore.enqueue(message);
18
- }
19
-
20
- resolveWorkspaceRoot(message) {
21
- return normalizeText(message?.workspaceRoot) || normalizeText(this.config.workspaceRoot);
22
- }
23
-
24
- buildPreparedMessage(message, contextToken = "") {
25
- return {
26
- provider: "system",
27
- workspaceId: this.config.workspaceId,
28
- accountId: this.accountId,
29
- chatId: message.senderId,
30
- threadKey: `system:${message.senderId}`,
31
- senderId: message.senderId,
32
- messageId: message.id,
33
- text: buildSystemInboundText(message?.text, this.config),
34
- attachments: [],
35
- command: "message",
36
- contextToken,
37
- receivedAt: normalizeIsoTime(message?.createdAt) || new Date().toISOString(),
38
- workspaceRoot: this.resolveWorkspaceRoot(message),
39
- };
40
- }
41
- }
42
-
43
- function buildSystemInboundText(text, config = {}) {
44
- const body = normalizeText(text);
45
- const userName = normalizeText(config?.userName) || "用户";
46
- if (!body) {
47
- return `System trigger.\nThis message is not visible to ${userName}.`;
48
- }
49
- return `System trigger.\nThis message is not visible to ${userName}.\n${body}`;
50
- }
51
-
52
- function normalizeIsoTime(value) {
53
- const normalized = normalizeText(value);
54
- if (!normalized) {
55
- return "";
56
- }
57
- const parsed = Date.parse(normalized);
58
- if (!Number.isFinite(parsed)) {
59
- return "";
60
- }
61
- return new Date(parsed).toISOString();
62
- }
63
-
64
- function normalizeText(value) {
65
- return typeof value === "string" ? value.trim() : "";
66
- }
67
-
68
- module.exports = { SystemMessageDispatcher };
1
+ class SystemMessageDispatcher {
2
+ constructor({ queueStore, config, accountId }) {
3
+ this.queueStore = queueStore;
4
+ this.config = config;
5
+ this.accountId = accountId;
6
+ }
7
+
8
+ hasPending() {
9
+ return this.queueStore.hasPendingForAccount(this.accountId);
10
+ }
11
+
12
+ drainPending() {
13
+ return this.queueStore.drainForAccount(this.accountId);
14
+ }
15
+
16
+ requeue(message) {
17
+ return this.queueStore.enqueue(message);
18
+ }
19
+
20
+ resolveWorkspaceRoot(message) {
21
+ return normalizeText(message?.workspaceRoot) || normalizeText(this.config.workspaceRoot);
22
+ }
23
+
24
+ buildPreparedMessage(message, contextToken = "") {
25
+ return {
26
+ provider: "system",
27
+ workspaceId: this.config.workspaceId,
28
+ accountId: this.accountId,
29
+ chatId: message.senderId,
30
+ threadKey: `system:${message.senderId}`,
31
+ senderId: message.senderId,
32
+ messageId: message.id,
33
+ text: buildSystemInboundText(message?.text, this.config),
34
+ attachments: [],
35
+ command: "message",
36
+ contextToken,
37
+ receivedAt: normalizeIsoTime(message?.createdAt) || new Date().toISOString(),
38
+ workspaceRoot: this.resolveWorkspaceRoot(message),
39
+ };
40
+ }
41
+ }
42
+
43
+ function buildSystemInboundText(text, config = {}) {
44
+ const body = normalizeText(text);
45
+ const userName = normalizeText(config?.userName) || "用户";
46
+ if (!body) {
47
+ return `System trigger.\nThis message is not visible to ${userName}.`;
48
+ }
49
+ return `System trigger.\nThis message is not visible to ${userName}.\n${body}`;
50
+ }
51
+
52
+ function normalizeIsoTime(value) {
53
+ const normalized = normalizeText(value);
54
+ if (!normalized) {
55
+ return "";
56
+ }
57
+ const parsed = Date.parse(normalized);
58
+ if (!Number.isFinite(parsed)) {
59
+ return "";
60
+ }
61
+ return new Date(parsed).toISOString();
62
+ }
63
+
64
+ function normalizeText(value) {
65
+ return typeof value === "string" ? value.trim() : "";
66
+ }
67
+
68
+ module.exports = { SystemMessageDispatcher };
@@ -1,128 +1,128 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- class SystemMessageQueueStore {
5
- constructor({ filePath }) {
6
- this.filePath = filePath;
7
- this.state = { messages: [] };
8
- this.ensureParentDirectory();
9
- this.load();
10
- }
11
-
12
- ensureParentDirectory() {
13
- fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
14
- }
15
-
16
- load() {
17
- try {
18
- const raw = fs.readFileSync(this.filePath, "utf8");
19
- const parsed = JSON.parse(raw);
20
- const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
21
- this.state = {
22
- messages: messages
23
- .map(normalizeSystemMessage)
24
- .filter(Boolean)
25
- .sort(compareSystemMessages),
26
- };
27
- } catch {
28
- this.state = { messages: [] };
29
- }
30
- }
31
-
32
- save() {
33
- fs.writeFileSync(this.filePath, JSON.stringify(this.state, null, 2));
34
- }
35
-
36
- enqueue(message) {
37
- this.load();
38
- const normalized = normalizeSystemMessage(message);
39
- if (!normalized) {
40
- throw new Error("invalid system message");
41
- }
42
- this.state.messages.push(normalized);
43
- this.state.messages.sort(compareSystemMessages);
44
- this.save();
45
- return normalized;
46
- }
47
-
48
- drainForAccount(accountId) {
49
- this.load();
50
- const normalizedAccountId = normalizeText(accountId);
51
- const drained = [];
52
- const pending = [];
53
-
54
- for (const message of this.state.messages) {
55
- if (message.accountId === normalizedAccountId) {
56
- drained.push(message);
57
- } else {
58
- pending.push(message);
59
- }
60
- }
61
-
62
- if (drained.length) {
63
- this.state.messages = pending;
64
- this.save();
65
- }
66
-
67
- return drained;
68
- }
69
-
70
- hasPendingForAccount(accountId) {
71
- this.load();
72
- const normalizedAccountId = normalizeText(accountId);
73
- return this.state.messages.some((message) => message.accountId === normalizedAccountId);
74
- }
75
- }
76
-
77
- function normalizeSystemMessage(message) {
78
- if (!message || typeof message !== "object") {
79
- return null;
80
- }
81
-
82
- const id = normalizeText(message.id);
83
- const accountId = normalizeText(message.accountId);
84
- const senderId = normalizeText(message.senderId);
85
- const workspaceRoot = normalizeText(message.workspaceRoot);
86
- const text = normalizeText(message.text);
87
- const createdAt = normalizeIsoTime(message.createdAt);
88
-
89
- if (!id || !accountId || !senderId || !workspaceRoot || !text) {
90
- return null;
91
- }
92
-
93
- return {
94
- id,
95
- accountId,
96
- senderId,
97
- workspaceRoot,
98
- text,
99
- createdAt: createdAt || new Date().toISOString(),
100
- };
101
- }
102
-
103
- function normalizeIsoTime(value) {
104
- const normalized = normalizeText(value);
105
- if (!normalized) {
106
- return "";
107
- }
108
- const parsed = Date.parse(normalized);
109
- if (!Number.isFinite(parsed)) {
110
- return "";
111
- }
112
- return new Date(parsed).toISOString();
113
- }
114
-
115
- function compareSystemMessages(left, right) {
116
- const leftTime = Date.parse(left?.createdAt || "") || 0;
117
- const rightTime = Date.parse(right?.createdAt || "") || 0;
118
- if (leftTime !== rightTime) {
119
- return leftTime - rightTime;
120
- }
121
- return String(left?.id || "").localeCompare(String(right?.id || ""));
122
- }
123
-
124
- function normalizeText(value) {
125
- return typeof value === "string" ? value.trim() : "";
126
- }
127
-
128
- module.exports = { SystemMessageQueueStore };
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ class SystemMessageQueueStore {
5
+ constructor({ filePath }) {
6
+ this.filePath = filePath;
7
+ this.state = { messages: [] };
8
+ this.ensureParentDirectory();
9
+ this.load();
10
+ }
11
+
12
+ ensureParentDirectory() {
13
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
14
+ }
15
+
16
+ load() {
17
+ try {
18
+ const raw = fs.readFileSync(this.filePath, "utf8");
19
+ const parsed = JSON.parse(raw);
20
+ const messages = Array.isArray(parsed?.messages) ? parsed.messages : [];
21
+ this.state = {
22
+ messages: messages
23
+ .map(normalizeSystemMessage)
24
+ .filter(Boolean)
25
+ .sort(compareSystemMessages),
26
+ };
27
+ } catch {
28
+ this.state = { messages: [] };
29
+ }
30
+ }
31
+
32
+ save() {
33
+ fs.writeFileSync(this.filePath, JSON.stringify(this.state, null, 2));
34
+ }
35
+
36
+ enqueue(message) {
37
+ this.load();
38
+ const normalized = normalizeSystemMessage(message);
39
+ if (!normalized) {
40
+ throw new Error("invalid system message");
41
+ }
42
+ this.state.messages.push(normalized);
43
+ this.state.messages.sort(compareSystemMessages);
44
+ this.save();
45
+ return normalized;
46
+ }
47
+
48
+ drainForAccount(accountId) {
49
+ this.load();
50
+ const normalizedAccountId = normalizeText(accountId);
51
+ const drained = [];
52
+ const pending = [];
53
+
54
+ for (const message of this.state.messages) {
55
+ if (message.accountId === normalizedAccountId) {
56
+ drained.push(message);
57
+ } else {
58
+ pending.push(message);
59
+ }
60
+ }
61
+
62
+ if (drained.length) {
63
+ this.state.messages = pending;
64
+ this.save();
65
+ }
66
+
67
+ return drained;
68
+ }
69
+
70
+ hasPendingForAccount(accountId) {
71
+ this.load();
72
+ const normalizedAccountId = normalizeText(accountId);
73
+ return this.state.messages.some((message) => message.accountId === normalizedAccountId);
74
+ }
75
+ }
76
+
77
+ function normalizeSystemMessage(message) {
78
+ if (!message || typeof message !== "object") {
79
+ return null;
80
+ }
81
+
82
+ const id = normalizeText(message.id);
83
+ const accountId = normalizeText(message.accountId);
84
+ const senderId = normalizeText(message.senderId);
85
+ const workspaceRoot = normalizeText(message.workspaceRoot);
86
+ const text = normalizeText(message.text);
87
+ const createdAt = normalizeIsoTime(message.createdAt);
88
+
89
+ if (!id || !accountId || !senderId || !workspaceRoot || !text) {
90
+ return null;
91
+ }
92
+
93
+ return {
94
+ id,
95
+ accountId,
96
+ senderId,
97
+ workspaceRoot,
98
+ text,
99
+ createdAt: createdAt || new Date().toISOString(),
100
+ };
101
+ }
102
+
103
+ function normalizeIsoTime(value) {
104
+ const normalized = normalizeText(value);
105
+ if (!normalized) {
106
+ return "";
107
+ }
108
+ const parsed = Date.parse(normalized);
109
+ if (!Number.isFinite(parsed)) {
110
+ return "";
111
+ }
112
+ return new Date(parsed).toISOString();
113
+ }
114
+
115
+ function compareSystemMessages(left, right) {
116
+ const leftTime = Date.parse(left?.createdAt || "") || 0;
117
+ const rightTime = Date.parse(right?.createdAt || "") || 0;
118
+ if (leftTime !== rightTime) {
119
+ return leftTime - rightTime;
120
+ }
121
+ return String(left?.id || "").localeCompare(String(right?.id || ""));
122
+ }
123
+
124
+ function normalizeText(value) {
125
+ return typeof value === "string" ? value.trim() : "";
126
+ }
127
+
128
+ module.exports = { SystemMessageQueueStore };
@@ -1,86 +1,86 @@
1
- class ThreadStateStore {
2
- constructor() {
3
- this.stateByThreadId = new Map();
4
- this.latestUsage = null;
5
- }
6
-
7
- applyRuntimeEvent(event) {
8
- if (event?.type === "runtime.usage.updated") {
9
- this.latestUsage = {
10
- ...event.payload,
11
- updatedAt: new Date().toISOString(),
12
- };
13
- return;
14
- }
15
- if (!event || !event.payload || !event.payload.threadId) {
16
- return;
17
- }
18
-
19
- const threadId = event.payload.threadId;
20
- const current = this.stateByThreadId.get(threadId) || createEmptyThreadState(threadId);
21
- const next = {
22
- ...current,
23
- updatedAt: new Date().toISOString(),
24
- };
25
-
26
- switch (event.type) {
27
- case "runtime.turn.started":
28
- next.status = "running";
29
- next.turnId = event.payload.turnId || next.turnId;
30
- next.lastError = "";
31
- break;
32
- case "runtime.reply.delta":
33
- next.status = "running";
34
- next.turnId = event.payload.turnId || next.turnId;
35
- next.lastReplyText = event.payload.text || next.lastReplyText;
36
- break;
37
- case "runtime.reply.completed":
38
- next.status = "running";
39
- next.turnId = event.payload.turnId || next.turnId;
40
- next.lastReplyText = event.payload.text || next.lastReplyText;
41
- break;
42
- case "runtime.approval.requested":
43
- next.status = "waiting_approval";
44
- next.pendingApproval = {
45
- requestId: event.payload.requestId ?? null,
46
- reason: event.payload.reason || "",
47
- command: event.payload.command || "",
48
- commandTokens: Array.isArray(event.payload.commandTokens) ? event.payload.commandTokens : [],
49
- };
50
- break;
51
- case "runtime.turn.completed":
52
- next.status = "idle";
53
- next.turnId = event.payload.turnId || next.turnId;
54
- next.pendingApproval = null;
55
- break;
56
- case "runtime.turn.failed":
57
- next.status = "failed";
58
- next.turnId = event.payload.turnId || next.turnId;
59
- next.lastError = event.payload.text || "执行失败";
60
- next.pendingApproval = null;
61
- break;
62
- default:
63
- break;
64
- }
65
-
66
- this.stateByThreadId.set(threadId, next);
67
- }
68
-
69
- getThreadState(threadId) {
70
- return this.stateByThreadId.get(threadId) || null;
71
- }
72
-
1
+ class ThreadStateStore {
2
+ constructor() {
3
+ this.stateByThreadId = new Map();
4
+ this.latestUsage = null;
5
+ }
6
+
7
+ applyRuntimeEvent(event) {
8
+ if (event?.type === "runtime.usage.updated") {
9
+ this.latestUsage = {
10
+ ...event.payload,
11
+ updatedAt: new Date().toISOString(),
12
+ };
13
+ return;
14
+ }
15
+ if (!event || !event.payload || !event.payload.threadId) {
16
+ return;
17
+ }
18
+
19
+ const threadId = event.payload.threadId;
20
+ const current = this.stateByThreadId.get(threadId) || createEmptyThreadState(threadId);
21
+ const next = {
22
+ ...current,
23
+ updatedAt: new Date().toISOString(),
24
+ };
25
+
26
+ switch (event.type) {
27
+ case "runtime.turn.started":
28
+ next.status = "running";
29
+ next.turnId = event.payload.turnId || next.turnId;
30
+ next.lastError = "";
31
+ break;
32
+ case "runtime.reply.delta":
33
+ next.status = "running";
34
+ next.turnId = event.payload.turnId || next.turnId;
35
+ next.lastReplyText = event.payload.text || next.lastReplyText;
36
+ break;
37
+ case "runtime.reply.completed":
38
+ next.status = "running";
39
+ next.turnId = event.payload.turnId || next.turnId;
40
+ next.lastReplyText = event.payload.text || next.lastReplyText;
41
+ break;
42
+ case "runtime.approval.requested":
43
+ next.status = "waiting_approval";
44
+ next.pendingApproval = {
45
+ requestId: event.payload.requestId ?? null,
46
+ reason: event.payload.reason || "",
47
+ command: event.payload.command || "",
48
+ commandTokens: Array.isArray(event.payload.commandTokens) ? event.payload.commandTokens : [],
49
+ };
50
+ break;
51
+ case "runtime.turn.completed":
52
+ next.status = "idle";
53
+ next.turnId = event.payload.turnId || next.turnId;
54
+ next.pendingApproval = null;
55
+ break;
56
+ case "runtime.turn.failed":
57
+ next.status = "failed";
58
+ next.turnId = event.payload.turnId || next.turnId;
59
+ next.lastError = event.payload.text || "执行失败";
60
+ next.pendingApproval = null;
61
+ break;
62
+ default:
63
+ break;
64
+ }
65
+
66
+ this.stateByThreadId.set(threadId, next);
67
+ }
68
+
69
+ getThreadState(threadId) {
70
+ return this.stateByThreadId.get(threadId) || null;
71
+ }
72
+
73
73
  resolveApproval(threadId, status = "running") {
74
74
  const current = this.stateByThreadId.get(threadId);
75
75
  if (!current) {
76
76
  return null;
77
77
  }
78
- const next = {
79
- ...current,
80
- status,
81
- pendingApproval: null,
82
- updatedAt: new Date().toISOString(),
83
- };
78
+ const next = {
79
+ ...current,
80
+ status,
81
+ pendingApproval: null,
82
+ updatedAt: new Date().toISOString(),
83
+ };
84
84
  this.stateByThreadId.set(threadId, next);
85
85
  return next;
86
86
  }
@@ -106,25 +106,25 @@ class ThreadStateStore {
106
106
  this.stateByThreadId.set(normalizedThreadId, next);
107
107
  return next;
108
108
  }
109
-
110
- snapshot() {
111
- return Array.from(this.stateByThreadId.values()).map((entry) => ({ ...entry }));
112
- }
113
-
114
- getLatestUsage() {
115
- return this.latestUsage ? { ...this.latestUsage } : null;
116
- }
117
- }
118
-
109
+
110
+ snapshot() {
111
+ return Array.from(this.stateByThreadId.values()).map((entry) => ({ ...entry }));
112
+ }
113
+
114
+ getLatestUsage() {
115
+ return this.latestUsage ? { ...this.latestUsage } : null;
116
+ }
117
+ }
118
+
119
119
  function createEmptyThreadState(threadId) {
120
- return {
121
- threadId,
122
- turnId: "",
123
- status: "idle",
124
- lastReplyText: "",
125
- lastError: "",
126
- pendingApproval: null,
127
- updatedAt: new Date().toISOString(),
120
+ return {
121
+ threadId,
122
+ turnId: "",
123
+ status: "idle",
124
+ lastReplyText: "",
125
+ lastError: "",
126
+ pendingApproval: null,
127
+ updatedAt: new Date().toISOString(),
128
128
  };
129
129
  }
130
130