codeksei 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 (80) hide show
  1. package/LICENSE +661 -0
  2. package/README.en.md +215 -0
  3. package/README.md +259 -0
  4. package/bin/codeksei.js +10 -0
  5. package/bin/cyberboss.js +11 -0
  6. package/package.json +86 -0
  7. package/scripts/install-background-tasks.ps1 +135 -0
  8. package/scripts/open_shared_wechat_thread.sh +94 -0
  9. package/scripts/open_wechat_thread.sh +117 -0
  10. package/scripts/shared-common.js +791 -0
  11. package/scripts/shared-open.js +46 -0
  12. package/scripts/shared-start.js +41 -0
  13. package/scripts/shared-status.js +74 -0
  14. package/scripts/shared-supervisor.js +141 -0
  15. package/scripts/shared-task-runner.ps1 +87 -0
  16. package/scripts/shared-watchdog.js +290 -0
  17. package/scripts/show_shared_status.sh +53 -0
  18. package/scripts/start_shared_app_server.sh +65 -0
  19. package/scripts/start_shared_wechat.sh +108 -0
  20. package/scripts/timeline-screenshot.sh +15 -0
  21. package/scripts/uninstall-background-tasks.ps1 +23 -0
  22. package/src/adapters/channel/weixin/account-store.js +135 -0
  23. package/src/adapters/channel/weixin/api-v2.js +258 -0
  24. package/src/adapters/channel/weixin/api.js +180 -0
  25. package/src/adapters/channel/weixin/context-token-store.js +84 -0
  26. package/src/adapters/channel/weixin/index.js +605 -0
  27. package/src/adapters/channel/weixin/legacy.js +567 -0
  28. package/src/adapters/channel/weixin/login-common.js +63 -0
  29. package/src/adapters/channel/weixin/login-legacy.js +124 -0
  30. package/src/adapters/channel/weixin/login-v2.js +186 -0
  31. package/src/adapters/channel/weixin/media-mime.js +22 -0
  32. package/src/adapters/channel/weixin/media-receive.js +370 -0
  33. package/src/adapters/channel/weixin/media-send.js +331 -0
  34. package/src/adapters/channel/weixin/message-utils-v2.js +282 -0
  35. package/src/adapters/channel/weixin/message-utils.js +199 -0
  36. package/src/adapters/channel/weixin/protocol.js +77 -0
  37. package/src/adapters/channel/weixin/redact.js +41 -0
  38. package/src/adapters/channel/weixin/reminder-queue-store.js +101 -0
  39. package/src/adapters/channel/weixin/sync-buffer-store.js +35 -0
  40. package/src/adapters/runtime/codex/events.js +252 -0
  41. package/src/adapters/runtime/codex/index.js +502 -0
  42. package/src/adapters/runtime/codex/message-utils.js +141 -0
  43. package/src/adapters/runtime/codex/model-catalog.js +106 -0
  44. package/src/adapters/runtime/codex/protocol-leak-monitor.js +75 -0
  45. package/src/adapters/runtime/codex/rpc-client.js +443 -0
  46. package/src/adapters/runtime/codex/session-store.js +376 -0
  47. package/src/app/channel-send-file-cli.js +57 -0
  48. package/src/app/diary-write-cli.js +620 -0
  49. package/src/app/note-auto-cli.js +201 -0
  50. package/src/app/note-sync-cli.js +130 -0
  51. package/src/app/project-radar-cli.js +165 -0
  52. package/src/app/reminder-write-cli.js +210 -0
  53. package/src/app/review-cli.js +134 -0
  54. package/src/app/system-checkin-poller.js +100 -0
  55. package/src/app/system-send-cli.js +129 -0
  56. package/src/app/timeline-event-cli.js +273 -0
  57. package/src/app/timeline-screenshot-cli.js +109 -0
  58. package/src/core/app.js +1810 -0
  59. package/src/core/branding.js +167 -0
  60. package/src/core/command-registry.js +609 -0
  61. package/src/core/config.js +84 -0
  62. package/src/core/default-targets.js +163 -0
  63. package/src/core/durable-note-schema.js +325 -0
  64. package/src/core/instructions-template.js +31 -0
  65. package/src/core/note-sync.js +433 -0
  66. package/src/core/project-radar.js +402 -0
  67. package/src/core/review-semantic.js +524 -0
  68. package/src/core/review.js +1081 -0
  69. package/src/core/shared-bridge-heartbeat.js +140 -0
  70. package/src/core/stream-delivery.js +990 -0
  71. package/src/core/system-message-dispatcher.js +68 -0
  72. package/src/core/system-message-queue-store.js +128 -0
  73. package/src/core/thread-state-store.js +135 -0
  74. package/src/core/timeline-screenshot-queue-store.js +134 -0
  75. package/src/core/workspace-alias.js +163 -0
  76. package/src/core/workspace-bootstrap.js +338 -0
  77. package/src/index.js +270 -0
  78. package/src/integrations/timeline/index.js +191 -0
  79. package/templates/weixin-instructions.md +53 -0
  80. package/templates/weixin-operations.md +69 -0
@@ -0,0 +1,609 @@
1
+ const COMMAND_GROUPS = [
2
+ {
3
+ id: "lifecycle",
4
+ label: "启动与诊断",
5
+ actions: [
6
+ {
7
+ action: "app.login",
8
+ summary: "发起微信扫码登录并保存账号",
9
+ terminal: ["login"],
10
+ weixin: [],
11
+ status: "active",
12
+ },
13
+ {
14
+ action: "app.accounts",
15
+ summary: "查看本地已保存账号",
16
+ terminal: ["accounts"],
17
+ weixin: [],
18
+ status: "active",
19
+ },
20
+ {
21
+ action: "app.start",
22
+ summary: "启动当前 channel/runtime 主循环",
23
+ terminal: ["start"],
24
+ weixin: [],
25
+ status: "active",
26
+ },
27
+ {
28
+ action: "app.shared_start",
29
+ summary: "启动共享 app-server 与共享微信桥接",
30
+ terminal: ["shared start"],
31
+ weixin: [],
32
+ status: "active",
33
+ },
34
+ {
35
+ action: "app.shared_open",
36
+ summary: "接入当前微信绑定的共享线程",
37
+ terminal: ["shared open"],
38
+ weixin: [],
39
+ status: "active",
40
+ },
41
+ {
42
+ action: "app.shared_status",
43
+ summary: "查看共享 app-server 与共享桥接状态",
44
+ terminal: ["shared status"],
45
+ weixin: [],
46
+ status: "active",
47
+ },
48
+ {
49
+ action: "app.doctor",
50
+ summary: "打印当前配置、边界和线程状态",
51
+ terminal: ["doctor"],
52
+ weixin: [],
53
+ status: "active",
54
+ },
55
+ {
56
+ action: "system.send",
57
+ summary: "向内部系统队列写入一条不可见触发消息",
58
+ terminal: ["system send"],
59
+ terminalGroup: "system",
60
+ weixin: [],
61
+ status: "active",
62
+ },
63
+ {
64
+ action: "system.checkin_poller",
65
+ summary: "按随机间隔写入主动 check-in 触发",
66
+ terminal: ["system checkin-poller"],
67
+ terminalGroup: "system",
68
+ weixin: [],
69
+ status: "active",
70
+ },
71
+ ],
72
+ },
73
+ {
74
+ id: "workspace",
75
+ label: "项目与线程",
76
+ actions: [
77
+ {
78
+ action: "workspace.bind",
79
+ summary: "绑定当前聊天使用的项目目录",
80
+ terminal: [],
81
+ weixin: ["/bind"],
82
+ status: "active",
83
+ },
84
+ {
85
+ action: "workspace.status",
86
+ summary: "查看当前项目、线程、模型与上下文使用情况",
87
+ terminal: [],
88
+ weixin: ["/status"],
89
+ status: "active",
90
+ },
91
+ {
92
+ action: "thread.new",
93
+ summary: "切到新线程草稿,并在下一条消息前重建当前 workspace 上下文",
94
+ terminal: [],
95
+ weixin: ["/new"],
96
+ status: "active",
97
+ },
98
+ {
99
+ action: "thread.reread",
100
+ summary: "让当前线程重新读取最新 instructions 和当前 workspace 稳定入口",
101
+ terminal: [],
102
+ weixin: ["/reread"],
103
+ status: "active",
104
+ },
105
+ {
106
+ action: "thread.switch",
107
+ summary: "切换到指定线程,并在下一条消息前按当前 workspace 检查是否要补读稳定入口",
108
+ terminal: [],
109
+ weixin: ["/switch <threadId>"],
110
+ status: "active",
111
+ },
112
+ {
113
+ action: "thread.stop",
114
+ summary: "停止当前线程中的运行",
115
+ terminal: [],
116
+ weixin: ["/stop"],
117
+ status: "active",
118
+ },
119
+ ],
120
+ },
121
+ {
122
+ id: "approval",
123
+ label: "授权与控制",
124
+ actions: [
125
+ {
126
+ action: "approval.accept_once",
127
+ summary: "允许当前待处理的授权请求一次",
128
+ terminal: [],
129
+ weixin: ["/yes"],
130
+ status: "active",
131
+ },
132
+ {
133
+ action: "approval.accept_workspace",
134
+ summary: "在当前项目内持续允许同前缀命令",
135
+ terminal: [],
136
+ weixin: ["/always"],
137
+ status: "active",
138
+ },
139
+ {
140
+ action: "approval.reject_once",
141
+ summary: "拒绝当前待处理的授权请求",
142
+ terminal: [],
143
+ weixin: ["/no"],
144
+ status: "active",
145
+ },
146
+ ],
147
+ },
148
+ {
149
+ id: "projects",
150
+ label: "代码项目",
151
+ actions: [
152
+ {
153
+ action: "project.radar",
154
+ summary: "读取已跟踪代码项目的稳定入口与轻量 git 近况",
155
+ terminal: ["project radar"],
156
+ terminalGroup: "project",
157
+ weixin: [],
158
+ status: "active",
159
+ },
160
+ {
161
+ action: "note.sync",
162
+ summary: "把轻量 durable 摘要同步到指定 note 的指定 section",
163
+ terminal: ["note sync"],
164
+ terminalGroup: "note",
165
+ weixin: [],
166
+ status: "active",
167
+ },
168
+ {
169
+ action: "note.auto",
170
+ summary: "按 workspace durable note schema 自动选择 note 与 section 并落盘",
171
+ terminal: ["note auto"],
172
+ terminalGroup: "note",
173
+ weixin: [],
174
+ status: "active",
175
+ },
176
+ {
177
+ action: "note.maybe",
178
+ summary: "预览 durable note 路由,不实际写入",
179
+ terminal: ["note maybe"],
180
+ terminalGroup: "note",
181
+ weixin: [],
182
+ status: "active",
183
+ },
184
+ {
185
+ action: "review.nightly",
186
+ summary: "从日记真相源生成一份睡前收口",
187
+ terminal: ["review nightly"],
188
+ terminalGroup: "review",
189
+ weixin: [],
190
+ status: "active",
191
+ },
192
+ {
193
+ action: "review.weekly",
194
+ summary: "从日记真相源生成一份周复盘",
195
+ terminal: ["review weekly"],
196
+ terminalGroup: "review",
197
+ weixin: [],
198
+ status: "active",
199
+ },
200
+ {
201
+ action: "review.monthly",
202
+ summary: "从日记真相源生成一份月复盘",
203
+ terminal: ["review monthly"],
204
+ terminalGroup: "review",
205
+ weixin: [],
206
+ status: "active",
207
+ },
208
+ ],
209
+ },
210
+ {
211
+ id: "capabilities",
212
+ label: "能力集成",
213
+ actions: [
214
+ {
215
+ action: "model.inspect",
216
+ summary: "查看当前模型",
217
+ terminal: [],
218
+ weixin: ["/model"],
219
+ status: "active",
220
+ },
221
+ {
222
+ action: "model.select",
223
+ summary: "切换到指定模型",
224
+ terminal: [],
225
+ weixin: ["/model <id>"],
226
+ status: "active",
227
+ },
228
+ {
229
+ action: "channel.send_file",
230
+ summary: "将文件作为附件发送回当前聊天",
231
+ terminal: ["channel send-file"],
232
+ terminalGroup: "channel",
233
+ weixin: [],
234
+ status: "active",
235
+ },
236
+ {
237
+ action: "timeline.event",
238
+ summary: "按单个时间块写入时间轴,不必手写 JSON",
239
+ terminal: ["timeline event"],
240
+ terminalGroup: "timeline",
241
+ weixin: [],
242
+ status: "active",
243
+ },
244
+ {
245
+ action: "timeline.write",
246
+ summary: "将当前上下文写入时间轴",
247
+ terminal: ["timeline write"],
248
+ terminalGroup: "timeline",
249
+ weixin: [],
250
+ status: "active",
251
+ },
252
+ {
253
+ action: "timeline.read",
254
+ summary: "读取某一天的时间轴草稿或已发布内容",
255
+ terminal: ["timeline read"],
256
+ terminalGroup: "timeline",
257
+ weixin: [],
258
+ status: "active",
259
+ },
260
+ {
261
+ action: "timeline.categories",
262
+ summary: "查看可用分类、子类和 event node",
263
+ terminal: ["timeline categories"],
264
+ terminalGroup: "timeline",
265
+ weixin: [],
266
+ status: "active",
267
+ },
268
+ {
269
+ action: "timeline.proposals",
270
+ summary: "根据自然语言生成候选时间轴事件",
271
+ terminal: ["timeline proposals"],
272
+ terminalGroup: "timeline",
273
+ weixin: [],
274
+ status: "active",
275
+ },
276
+ {
277
+ action: "timeline.build",
278
+ summary: "构建时间轴静态页面",
279
+ terminal: ["timeline build"],
280
+ terminalGroup: "timeline",
281
+ weixin: [],
282
+ status: "active",
283
+ },
284
+ {
285
+ action: "timeline.serve",
286
+ summary: "启动时间轴静态页面服务",
287
+ terminal: ["timeline serve"],
288
+ terminalGroup: "timeline",
289
+ weixin: [],
290
+ status: "active",
291
+ },
292
+ {
293
+ action: "timeline.dev",
294
+ summary: "启动时间轴热更新开发服务",
295
+ terminal: ["timeline dev"],
296
+ terminalGroup: "timeline",
297
+ weixin: [],
298
+ status: "active",
299
+ },
300
+ {
301
+ action: "timeline.screenshot",
302
+ summary: "截图时间轴页面",
303
+ terminal: ["timeline screenshot"],
304
+ terminalGroup: "timeline",
305
+ weixin: [],
306
+ status: "active",
307
+ },
308
+ {
309
+ action: "reminder.create",
310
+ summary: "创建提醒并交给调度层处理",
311
+ terminal: ["reminder write"],
312
+ terminalGroup: "reminder",
313
+ weixin: [],
314
+ status: "active",
315
+ },
316
+ {
317
+ action: "diary.append",
318
+ summary: "追加一条日记记录",
319
+ terminal: ["diary write"],
320
+ terminalGroup: "diary",
321
+ weixin: [],
322
+ status: "active",
323
+ },
324
+ {
325
+ action: "app.help",
326
+ summary: "查看当前通道可用命令",
327
+ terminal: ["help"],
328
+ weixin: ["/help"],
329
+ status: "active",
330
+ },
331
+ ],
332
+ },
333
+ ];
334
+
335
+ function listCommandGroups() {
336
+ return COMMAND_GROUPS.map((group) => ({
337
+ ...group,
338
+ actions: group.actions.map((action) => ({ ...action })),
339
+ }));
340
+ }
341
+
342
+ function buildTerminalHelpText() {
343
+ const lines = [
344
+ "用法: npm run <script>",
345
+ "",
346
+ "当前终端命令:",
347
+ " npm run shared:start 默认修复/拉起后台共享 app-server 与共享微信桥接",
348
+ " npm run shared:open 默认接入当前微信绑定的共享线程",
349
+ " npm run shared:watchdog 主动巡检并自恢复共享链路",
350
+ " npm run background:install Windows 安装开机自启和周期巡检",
351
+ " npm run background:uninstall Windows 卸载开机自启和周期巡检",
352
+ ];
353
+
354
+ for (const group of COMMAND_GROUPS) {
355
+ const activeActions = group.actions.filter((action) => action.status === "active" && action.terminal.length);
356
+ if (!activeActions.length) {
357
+ continue;
358
+ }
359
+ lines.push(`- ${group.label}`);
360
+ for (const action of activeActions) {
361
+ lines.push(` ${formatTerminalExamples(action)} ${action.summary}`);
362
+ }
363
+ }
364
+
365
+ const plannedGroups = collectPlannedTerminalGroups();
366
+ if (plannedGroups.length) {
367
+ lines.push("");
368
+ lines.push("规划中的终端子命令:");
369
+ for (const group of plannedGroups) {
370
+ lines.push(`- ${group.name}`);
371
+ for (const action of group.actions) {
372
+ lines.push(` ${action.terminal.join(", ")} ${action.summary}`);
373
+ }
374
+ }
375
+ }
376
+
377
+ lines.push("");
378
+ lines.push("微信命令映射与后续能力动作请看 README / docs。");
379
+ return lines.join("\n");
380
+ }
381
+
382
+ function buildWeixinHelpText() {
383
+ const lines = ["当前可用命令:"];
384
+ for (const group of COMMAND_GROUPS) {
385
+ const activeActions = group.actions.filter((action) => action.status === "active" && action.weixin.length);
386
+ if (!activeActions.length) {
387
+ continue;
388
+ }
389
+ lines.push("");
390
+ lines.push(`${group.label}:`);
391
+ for (const action of activeActions) {
392
+ lines.push(`- ${action.weixin.join(", ")} ${action.summary}`);
393
+ }
394
+ }
395
+ return lines.join("\n");
396
+ }
397
+
398
+ function buildTerminalTopicHelp(topic) {
399
+ const normalizedTopic = normalizeTopic(topic);
400
+ const actions = COMMAND_GROUPS
401
+ .flatMap((group) => group.actions)
402
+ .filter((action) => normalizeTopic(action.terminalGroup) === normalizedTopic && action.terminal.length);
403
+
404
+ if (!actions.length) {
405
+ return "";
406
+ }
407
+
408
+ const hasPlannedOnly = actions.every((action) => action.status === "planned");
409
+ const lines = [
410
+ `用法: ${buildTopicUsage(normalizedTopic)}`,
411
+ "",
412
+ hasPlannedOnly
413
+ ? `当前 ${normalizedTopic} 命令仍在接入中,计划中的子命令:`
414
+ : `当前 ${normalizedTopic} 命令:`,
415
+ ];
416
+ for (const action of actions) {
417
+ lines.push(`- ${formatTerminalExamples(action)} ${action.summary}`);
418
+ }
419
+ return lines.join("\n");
420
+ }
421
+
422
+ function isPlannedTerminalTopic(topic) {
423
+ const normalizedTopic = normalizeTopic(topic);
424
+ return COMMAND_GROUPS
425
+ .flatMap((group) => group.actions)
426
+ .some((action) => normalizeTopic(action.terminalGroup) === normalizedTopic && action.terminal.length);
427
+ }
428
+
429
+ function collectPlannedTerminalGroups() {
430
+ const grouped = new Map();
431
+ for (const action of COMMAND_GROUPS.flatMap((group) => group.actions)) {
432
+ if (!action.terminal.length || !action.terminalGroup || action.status !== "planned") {
433
+ continue;
434
+ }
435
+ const key = action.terminalGroup;
436
+ if (!grouped.has(key)) {
437
+ grouped.set(key, { name: key, actions: [] });
438
+ }
439
+ grouped.get(key).actions.push(action);
440
+ }
441
+ return Array.from(grouped.values());
442
+ }
443
+
444
+ function normalizeTopic(value) {
445
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
446
+ }
447
+
448
+ module.exports = {
449
+ buildTerminalHelpText,
450
+ buildTerminalTopicHelp,
451
+ buildWeixinHelpText,
452
+ isPlannedTerminalTopic,
453
+ listCommandGroups,
454
+ };
455
+
456
+ function formatTerminalExamples(action) {
457
+ const terminal = Array.isArray(action?.terminal) ? action.terminal : [];
458
+ if (!terminal.length) {
459
+ return "";
460
+ }
461
+ return terminal.map((commandText) => toNpmRunExample(commandText)).join(", ");
462
+ }
463
+
464
+ function buildTopicUsage(topic) {
465
+ switch (topic) {
466
+ case "reminder":
467
+ return [
468
+ "npm run reminder:write -- <args>",
469
+ "",
470
+ "参数:",
471
+ " --delay 30s|10m|1h30m|2d4h",
472
+ " --at 2026-04-07T21:30+08:00 | 2026-04-07 21:30",
473
+ " --text \"提醒内容\"",
474
+ " --user <wechatUserId> 可选",
475
+ ].join("\n");
476
+ case "diary":
477
+ return [
478
+ "npm run diary:write -- <args>",
479
+ "",
480
+ "参数:",
481
+ " --text \"内容\"",
482
+ " --section todo|timeline|fragment|supplement|summary",
483
+ " --state open|done 只和 --section todo 一起用",
484
+ " --timeline-text \"...\" 只和 --section todo --state done 一起用;同一切换点会同步写入“时间线事实”",
485
+ " --title \"标题\" 默认主要给 supplement 用;其他 section 会和正文合成单行内容",
486
+ " --date YYYY-MM-DD 决定写入哪个日记文件",
487
+ " --time HH:mm 可选,覆盖条目时间",
488
+ "",
489
+ "示例:",
490
+ " npm run diary:write -- --section todo --state open --text \"把药单发给 Alex\"",
491
+ " npm run diary:write -- --section todo --state done --text \"收住 Codeksei 微信回复问题\" --timeline-text \"22:39-23:04 连续压测 Codeksei 微信回复链路;这条问题今晚可以先收尾。\"",
492
+ " npm run diary:write -- --section timeline --text \"17:30-17:58 把药单发出去了\"",
493
+ ].join("\n");
494
+ case "channel":
495
+ return [
496
+ "npm run channel:send-file -- --path /绝对路径 [--user <wechatUserId>]",
497
+ "",
498
+ "参数:",
499
+ " --path /绝对路径 要发回当前微信聊天的本地文件",
500
+ " --user <wechatUserId> 可选,覆盖默认接收用户",
501
+ ].join("\n");
502
+ case "system":
503
+ return "npm run system:send -- <args> / npm run system:checkin";
504
+ case "timeline":
505
+ return [
506
+ "npm run timeline:event -- <args> / npm run timeline:write -- <args> / npm run timeline:read -- <args> / npm run timeline:categories / npm run timeline:proposals -- <args> / npm run timeline:build / npm run timeline:serve / npm run timeline:dev / npm run timeline:screenshot -- --send",
507
+ "",
508
+ "补充:",
509
+ " 单条事件优先用 npm run timeline:event -- --date YYYY-MM-DD --start HH:mm --end HH:mm --title \"...\" ...,避免手写 JSON",
510
+ " timeline 查分类先用 npm run timeline:categories;改已有日程前先用 npm run timeline:read -- --date YYYY-MM-DD",
511
+ " timeline 截图稳定入口是 npm run timeline:screenshot -- --send,它会把任务交给当前微信桥执行",
512
+ ].join("\n");
513
+ case "project":
514
+ return [
515
+ "npm run project:radar -- [--list] [--project <slug>] [--json] [--commits 5] [--changes 20]",
516
+ "",
517
+ "补充:",
518
+ " 默认从当前 workspace 的 .codex/code-projects.json 读取已跟踪代码项目",
519
+ " 先用 --list 看 slug;讨论具体项目时再用 --project <slug> --json",
520
+ ].join("\n");
521
+ case "note":
522
+ return [
523
+ "npm run note:auto -- (--project <slug> | --scope <name>) --kind <kind> [--text \"内容\" | --stdin]",
524
+ "npm run note:maybe -- [--project <slug> | --scope <name>] [--kind <kind>] [--json]",
525
+ "npm run note:sync -- (--project <slug> | --path <path>) --section <标题> [--text \"内容\" | --stdin] [--style bullet|paragraph] [--slot <id>] [--max-items N]",
526
+ "",
527
+ "补充:",
528
+ " 默认先用 note:auto,让 schema 决定 file / section / style / slot",
529
+ " note:maybe 只看路由,适合先确认 scope 或 kind 会落到哪里",
530
+ " 默认写成 bullet;需要维护一个稳定状态块时传 --slot",
531
+ " note:sync 保留给自定义 section 或一次性低层回写",
532
+ ].join("\n");
533
+ case "review":
534
+ return [
535
+ "npm run review:nightly -- [--date YYYY-MM-DD] [--deterministic] [--model <id>]",
536
+ "npm run review:weekly -- [--week YYYY-Www] [--date YYYY-MM-DD] [--deterministic] [--model <id>]",
537
+ "npm run review:monthly -- [--month YYYY-MM] [--date YYYY-MM-DD] [--deterministic] [--model <id>]",
538
+ "",
539
+ "补充:",
540
+ " 默认走 hybrid:脚本保骨架,Codex 负责结构化语义提炼;失败时自动回退 deterministic",
541
+ " nightly 负责睡前收口;周/月复盘在有 nightly 时会优先吸收它",
542
+ " 传 --deterministic 可强制只走脚本;传 --model <id> 可覆盖语义提炼使用的模型",
543
+ " 周复盘默认按周一到周日;月复盘默认按自然月",
544
+ ].join("\n");
545
+ default:
546
+ return "npm run <script>";
547
+ }
548
+ }
549
+
550
+ function toNpmRunExample(commandText) {
551
+ const normalized = typeof commandText === "string" ? commandText.trim() : "";
552
+ switch (normalized) {
553
+ case "login":
554
+ case "accounts":
555
+ case "start":
556
+ case "shared start":
557
+ case "shared open":
558
+ case "shared status":
559
+ case "doctor":
560
+ case "help":
561
+ return `npm run ${normalized.replace(" ", ":")}`;
562
+ case "start --checkin":
563
+ return "npm run start:checkin";
564
+ case "reminder write":
565
+ return "npm run reminder:write -- <args>";
566
+ case "diary write":
567
+ return "npm run diary:write -- <args>";
568
+ case "channel send-file":
569
+ return "npm run channel:send-file -- --path /绝对路径";
570
+ case "system send":
571
+ return "npm run system:send -- <args>";
572
+ case "system checkin-poller":
573
+ return "npm run system:checkin";
574
+ case "timeline write":
575
+ return "npm run timeline:write -- <args>";
576
+ case "timeline event":
577
+ return "npm run timeline:event -- <args>";
578
+ case "timeline read":
579
+ return "npm run timeline:read -- <args>";
580
+ case "timeline categories":
581
+ return "npm run timeline:categories";
582
+ case "timeline proposals":
583
+ return "npm run timeline:proposals -- <args>";
584
+ case "timeline build":
585
+ return "npm run timeline:build";
586
+ case "timeline serve":
587
+ return "npm run timeline:serve";
588
+ case "timeline dev":
589
+ return "npm run timeline:dev";
590
+ case "timeline screenshot":
591
+ return "npm run timeline:screenshot -- --send";
592
+ case "project radar":
593
+ return "npm run project:radar -- --project <slug> --json";
594
+ case "note sync":
595
+ return "npm run note:sync -- --project <slug> --section <标题> --text \"...\"";
596
+ case "note auto":
597
+ return "npm run note:auto -- --project <slug> --kind recent --text \"...\"";
598
+ case "note maybe":
599
+ return "npm run note:maybe -- --scope assistant --kind preference";
600
+ case "review weekly":
601
+ return "npm run review:weekly";
602
+ case "review nightly":
603
+ return "npm run review:nightly";
604
+ case "review monthly":
605
+ return "npm run review:monthly";
606
+ default:
607
+ return normalized;
608
+ }
609
+ }
@@ -0,0 +1,84 @@
1
+ const os = require("os");
2
+ const path = require("path");
3
+ const {
4
+ readPrefixedBoolEnv,
5
+ readPrefixedEnv,
6
+ readPrefixedIntEnv,
7
+ readPrefixedListEnv,
8
+ resolveAppHome,
9
+ resolveStateDir,
10
+ } = require("./branding");
11
+
12
+ function readConfig() {
13
+ const argv = process.argv.slice(2);
14
+ const mode = argv[0] || "";
15
+ const stateDir = resolveStateDir({ env: process.env });
16
+ const workspaceRoot = readPrefixedEnv(process.env, "WORKSPACE_ROOT") || process.cwd();
17
+ const appHome = resolveAppHome({
18
+ env: process.env,
19
+ fallbackRoot: path.resolve(__dirname, "..", ".."),
20
+ }) || path.resolve(__dirname, "..", "..");
21
+
22
+ return {
23
+ mode,
24
+ argv,
25
+ stateDir,
26
+ codekseiHome: appHome,
27
+ cyberbossHome: appHome,
28
+ workspaceId: readPrefixedEnv(process.env, "WORKSPACE_ID") || "default",
29
+ workspaceRoot,
30
+ diaryDir: readPrefixedEnv(process.env, "DIARY_DIR") || path.join(stateDir, "diary"),
31
+ timelineStateDir: readPrefixedEnv(process.env, "TIMELINE_STATE_DIR") || stateDir,
32
+ userName: readPrefixedEnv(process.env, "USER_NAME") || "用户",
33
+ userGender: readPrefixedEnv(process.env, "USER_GENDER") || "female",
34
+ allowedUserIds: readPrefixedListEnv(process.env, "ALLOWED_USER_IDS"),
35
+ channel: readPrefixedEnv(process.env, "CHANNEL") || "weixin",
36
+ runtime: readPrefixedEnv(process.env, "RUNTIME") || "codex",
37
+ timelineCommand: readPrefixedEnv(process.env, "TIMELINE_COMMAND") || "timeline-for-agent",
38
+ accountId: readPrefixedEnv(process.env, "ACCOUNT_ID"),
39
+ weixinBaseUrl: readPrefixedEnv(process.env, "WEIXIN_BASE_URL") || "https://ilinkai.weixin.qq.com",
40
+ weixinCdnBaseUrl: readPrefixedEnv(process.env, "WEIXIN_CDN_BASE_URL") || "https://novac2c.cdn.weixin.qq.com/c2c",
41
+ weixinAdapterVariant: readPrefixedEnv(process.env, "WEIXIN_ADAPTER") || "v2",
42
+ weixinReplyMode: normalizeWeixinReplyMode(readPrefixedEnv(process.env, "WEIXIN_REPLY_MODE") || "stream"),
43
+ weixinDeliveryTrace: readPrefixedBoolEnv(process.env, "WEIXIN_DELIVERY_TRACE"),
44
+ weixinQrBotType: readPrefixedEnv(process.env, "WEIXIN_QR_BOT_TYPE") || "3",
45
+ weixinRouteTag: readPrefixedEnv(process.env, "WEIXIN_ROUTE_TAG"),
46
+ weixinProtocolClientVersion: readPrefixedEnv(process.env, "WEIXIN_PROTOCOL_CLIENT_VERSION") || "2.1.1",
47
+ accountsDir: path.join(stateDir, "accounts"),
48
+ logDir: path.join(stateDir, "logs"),
49
+ reminderQueueFile: path.join(stateDir, "reminder-queue.json"),
50
+ systemMessageQueueFile: path.join(stateDir, "system-message-queue.json"),
51
+ timelineScreenshotQueueFile: path.join(stateDir, "timeline-screenshot-queue.json"),
52
+ weixinInstructionsFile: path.join(stateDir, "weixin-instructions.md"),
53
+ weixinOperationsFile: path.resolve(__dirname, "..", "..", "templates", "weixin-operations.md"),
54
+ syncBufferDir: path.join(stateDir, "sync-buffers"),
55
+ codexEndpoint: readPrefixedEnv(process.env, "CODEX_ENDPOINT"),
56
+ codexCommand: readPrefixedEnv(process.env, "CODEX_COMMAND"),
57
+ codexAccessMode: readPrefixedEnv(process.env, "CODEX_ACCESS_MODE"),
58
+ sessionsFile: path.join(stateDir, "sessions.json"),
59
+ workspaceBootstrapConfigFile: readPrefixedEnv(process.env, "WORKSPACE_BOOTSTRAP_CONFIG")
60
+ || path.join(stateDir, "workspace-bootstrap.json"),
61
+ projectRadarConfigFile: readPrefixedEnv(process.env, "PROJECT_RADAR_CONFIG")
62
+ || path.resolve(workspaceRoot, ".codex", "code-projects.json"),
63
+ durableNoteSchemaConfigFile: readPrefixedEnv(process.env, "DURABLE_NOTE_SCHEMA_CONFIG")
64
+ || path.resolve(workspaceRoot, ".codex", "durable-note-schema.json"),
65
+ reviewSchemaConfigFile: readPrefixedEnv(process.env, "REVIEW_SCHEMA_CONFIG")
66
+ || path.resolve(workspaceRoot, ".codex", "review-schema.json"),
67
+ reviewSemanticMode: readPrefixedEnv(process.env, "REVIEW_SEMANTIC_MODE") || "hybrid",
68
+ reviewSemanticModel: readPrefixedEnv(process.env, "REVIEW_SEMANTIC_MODEL"),
69
+ reviewSemanticTimeoutMs: readPrefixedIntEnv(process.env, "REVIEW_SEMANTIC_TIMEOUT_MS") || 120000,
70
+ sharedBridgeHeartbeatFile: path.join(stateDir, "logs", "shared-wechat-heartbeat.json"),
71
+ sharedWatchdogStateFile: path.join(stateDir, "logs", "shared-watchdog-state.json"),
72
+ startWithCheckin: (mode === "start" && hasArgFlag(argv, "--checkin")) || readPrefixedBoolEnv(process.env, "ENABLE_CHECKIN"),
73
+ };
74
+ }
75
+
76
+ function normalizeWeixinReplyMode(value) {
77
+ return String(value || "").trim().toLowerCase() === "settled" ? "settled" : "stream";
78
+ }
79
+
80
+ function hasArgFlag(argv, flag) {
81
+ return Array.isArray(argv) && argv.some((item) => String(item || "").trim() === flag);
82
+ }
83
+
84
+ module.exports = { readConfig };