@jesonliu/lark-claudecode-bridge 1.3.6 → 1.3.8

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 (55) hide show
  1. package/README.md +31 -1
  2. package/assets/web/js/main.js +2 -1
  3. package/assets/web/js/pages/memory.js +543 -0
  4. package/config.example.yaml +51 -11
  5. package/dist/config.d.ts +3 -0
  6. package/dist/config.js +213 -14
  7. package/dist/config.js.map +1 -1
  8. package/dist/executor/claude-executor.d.ts +34 -4
  9. package/dist/executor/claude-executor.js +718 -282
  10. package/dist/executor/claude-executor.js.map +1 -1
  11. package/dist/executor/notify-server.d.ts +10 -0
  12. package/dist/executor/notify-server.js +11 -0
  13. package/dist/executor/notify-server.js.map +1 -1
  14. package/dist/executor/permission-gate.d.ts +38 -0
  15. package/dist/executor/permission-gate.js +53 -0
  16. package/dist/executor/permission-gate.js.map +1 -1
  17. package/dist/gateway/card-builder.d.ts +15 -3
  18. package/dist/gateway/card-builder.js +21 -10
  19. package/dist/gateway/card-builder.js.map +1 -1
  20. package/dist/gateway/feishu-gateway.d.ts +36 -2
  21. package/dist/gateway/feishu-gateway.js +105 -8
  22. package/dist/gateway/feishu-gateway.js.map +1 -1
  23. package/dist/gateway/progress-card.d.ts +4 -2
  24. package/dist/gateway/progress-card.js +52 -25
  25. package/dist/gateway/progress-card.js.map +1 -1
  26. package/dist/index.d.ts +10 -1
  27. package/dist/index.js +277 -44
  28. package/dist/index.js.map +1 -1
  29. package/dist/memory-installer.d.ts +138 -0
  30. package/dist/memory-installer.js +908 -0
  31. package/dist/memory-installer.js.map +1 -0
  32. package/dist/memory.d.ts +79 -0
  33. package/dist/memory.js +182 -0
  34. package/dist/memory.js.map +1 -0
  35. package/dist/security/audit.d.ts +43 -0
  36. package/dist/security/audit.js +46 -0
  37. package/dist/security/audit.js.map +1 -0
  38. package/dist/security/paths.d.ts +41 -0
  39. package/dist/security/paths.js +240 -0
  40. package/dist/security/paths.js.map +1 -0
  41. package/dist/security/redact.d.ts +59 -0
  42. package/dist/security/redact.js +151 -0
  43. package/dist/security/redact.js.map +1 -0
  44. package/dist/session/session-store.d.ts +15 -0
  45. package/dist/session/session-store.js +16 -0
  46. package/dist/session/session-store.js.map +1 -1
  47. package/dist/types.d.ts +82 -6
  48. package/dist/web/config-api.js +32 -0
  49. package/dist/web/config-api.js.map +1 -1
  50. package/dist/web/memory-api.d.ts +25 -0
  51. package/dist/web/memory-api.js +186 -0
  52. package/dist/web/memory-api.js.map +1 -0
  53. package/dist/web/server.js +73 -2
  54. package/dist/web/server.js.map +1 -1
  55. package/package.json +1 -1
@@ -0,0 +1,240 @@
1
+ // R1/R2 路径判定:红区(读黑名单,恒定 deny)与工作区边界(写白名单)。
2
+ // 形态说明(方案 v3 §三):
3
+ // - Read/Grep/Glob/LS/Write/Edit/NotebookEdit 是结构化路径参数,这里做的是「完备可判」的
4
+ // 路径前缀/通配校验——这是砍掉(或收紧)Bash 之后 R1/R2 能成为硬约束的前提;
5
+ // - Bash 命令串只能做「特征探测」(命令文本含红区绝对路径字面量即 deny),是文档化的
6
+ // best-effort 而非完备判定——命令替换/编码/脚本下载执行永远可能绕过,根治靠 OS 层沙箱。
7
+ // 平台语义:Windows 文件系统大小写不敏感 → 比较统一小写 + 分隔符归一为 /;其他平台保持大小写敏感。
8
+ import { homedir, platform } from 'node:os';
9
+ import { resolve, isAbsolute } from 'node:path';
10
+ /**
11
+ * 内置默认红区(R1 读黑名单,config security.redzone.read 缺省值;配置即整体替换)。
12
+ * 口径:凭证与身份的存储位置——bridge 自身配置/会话记录、lark-cli 授权 token、SSH/GPG/AWS、
13
+ * 浏览器资料、通用凭证文件形态。对 deputy 恒定生效;主机器人不消费(主人读本机文件属合法自用,
14
+ * 出站脱敏兜底)。误报取向:宁可多拦(双星加 .key 一类的密钥扩展名),分身工作区如需此类文件由主人显式调整清单。
15
+ */
16
+ export const DEFAULT_REDZONE_READ_SOURCES = [
17
+ '~/.lark-claudecode-bridge/**', // bridge config.yaml(app_secret)/ transcripts / plans;inbox 子目录被 R1 豁免(入站附件,见 GateSecurity.inboxRoot)
18
+ '~/.lark-cli/**', // lark-cli 用户授权 token(R4 私人面互锁项)
19
+ '~/.claude/**', // CLI 登录态 / OAuth / 本机 settings
20
+ '~/.codex/**',
21
+ '~/.ssh/**',
22
+ '~/.aws/**',
23
+ '~/.gnupg/**',
24
+ '~/.netrc',
25
+ '~/.git-credentials',
26
+ '~/AppData/Local/Google/**', // 浏览器资料(Cookies / Login Data)
27
+ '~/AppData/Roaming/Google/**',
28
+ '~/Library/Application Support/Google/Chrome/**',
29
+ '~/.config/google-chrome/**',
30
+ '**/credentials*',
31
+ '**/id_rsa*',
32
+ '**/secrets.*',
33
+ '**/.env',
34
+ '**/.env.*',
35
+ '**/*.pem',
36
+ '**/*.key',
37
+ '**/*.enc',
38
+ '**/*.p12',
39
+ '**/*.pfx',
40
+ '**/*.keystore',
41
+ ];
42
+ const CASE_INSENSITIVE = platform() === 'win32';
43
+ /** `~` 展开 + 绝对化 + 分隔符归一(/)+(Windows)小写。所有比较都走这一条漏斗 */
44
+ export function normalizeForCompare(p, cwd = process.cwd()) {
45
+ let abs = p.trim();
46
+ if (abs === '~')
47
+ abs = homedir();
48
+ else if (abs.startsWith('~/') || abs.startsWith('~\\'))
49
+ abs = joinHome(abs.slice(2));
50
+ if (!isAbsolute(abs))
51
+ abs = resolve(cwd, abs);
52
+ const norm = resolve(abs).replace(/\\/g, '/');
53
+ return CASE_INSENSITIVE ? norm.toLowerCase() : norm;
54
+ }
55
+ function joinHome(rest) {
56
+ // path.join 在 Windows 接受 / 混排,这里统一用 resolve 兜住 `~\x` 与 `~/x`
57
+ return resolve(homedir(), rest);
58
+ }
59
+ /**
60
+ * 编译红区 glob 模式(config security.redzone.read)。支持:
61
+ * - `~/` 前缀展开为用户主目录
62
+ * - 双星加斜杠(`**` 后跟 `/`)匹配任意层级目录(含零层);`*` 单段内通配
63
+ * - 无通配模式按「目录前缀」语义:命中该路径本身与其下全部内容
64
+ * 非法/空条目跳过(配置页自由文本,坏条目 warn 不拖垮启动)。
65
+ */
66
+ export function compilePathPatterns(sources) {
67
+ const out = [];
68
+ for (const [i, raw] of sources.entries()) {
69
+ if (typeof raw !== 'string' || !raw.trim())
70
+ continue;
71
+ try {
72
+ out.push({ id: raw, re: compileOne(raw) });
73
+ }
74
+ catch (e) {
75
+ console.warn(`[security] 红区模式 #${i + 1} 编译失败已忽略(${raw}):`, e instanceof Error ? e.message : e);
76
+ }
77
+ }
78
+ return out;
79
+ }
80
+ function compileOne(raw) {
81
+ let p = raw.trim().replace(/\\/g, '/');
82
+ // 尾部 /** :目录前缀语义(命中目录本身 + 其下全部内容),先摘掉再按无通配收尾
83
+ const dirPrefix = p.endsWith('/**') || p === '~' || !p.endsWith('*');
84
+ if (p.endsWith('/**'))
85
+ p = p.slice(0, -3);
86
+ // ~ 展开(含 ~\ 与裸 ~)
87
+ if (p === '~')
88
+ p = normalizeForCompare('~');
89
+ else if (p.startsWith('~/'))
90
+ p = normalizeForCompare(p);
91
+ else if (!p.startsWith('/') && !/^[a-zA-Z]:\//.test(p) && !p.startsWith('**/')) {
92
+ // 相对模式:按「任意层级下匹配」语义处理(如 credentials* → **/credentials*)
93
+ p = `**/${p}`;
94
+ }
95
+ let re = '';
96
+ // 是否以段内通配收尾(收尾通配 = 精确深度语义,不得追加目录前缀后缀)
97
+ let trailingWildcard = false;
98
+ for (let i = 0; i < p.length; i++) {
99
+ const ch = p[i];
100
+ if (ch === '*') {
101
+ if (p[i + 1] === '*') {
102
+ // `**/`:零或多层目录;`**` 其余形态按同义处理
103
+ if (p[i + 2] === '/') {
104
+ re += '(?:[^/]+/)*';
105
+ trailingWildcard = true;
106
+ i += 2;
107
+ }
108
+ else {
109
+ re += '.*';
110
+ trailingWildcard = true;
111
+ i++;
112
+ }
113
+ }
114
+ else {
115
+ re += '[^/]*';
116
+ trailingWildcard = true;
117
+ }
118
+ continue;
119
+ }
120
+ re += /[.+^${}()|[\]\\?]/.test(ch) ? `\\${ch}` : ch;
121
+ trailingWildcard = false;
122
+ }
123
+ // 目录前缀语义(尾部 /**、裸 ~、无任何通配):同时命中路径本身与其下全部内容;
124
+ // 以段内通配收尾的(dir/*、**/credentials*)保持精确深度,不追加
125
+ if (dirPrefix && !trailingWildcard)
126
+ re += '(?:/.*)?';
127
+ return new RegExp(`^${re}$`, CASE_INSENSITIVE ? 'i' : '');
128
+ }
129
+ /** 路径命中红区则返回命中的模式(审计/日志用),未命中返回 null */
130
+ export function matchRedzone(p, matchers, cwd = process.cwd()) {
131
+ if (!p)
132
+ return null;
133
+ const norm = normalizeForCompare(p, cwd);
134
+ for (const m of matchers) {
135
+ if (m.re.test(norm))
136
+ return m.id;
137
+ m.re.lastIndex = 0;
138
+ }
139
+ return null;
140
+ }
141
+ /** 路径是否落在任一允许根之下(分隔符边界对齐,防 /ws-a 前缀误配 /ws-ab) */
142
+ export function isUnderAnyRoot(p, roots, cwd = process.cwd()) {
143
+ if (!p)
144
+ return false;
145
+ const norm = normalizeForCompare(p, cwd);
146
+ return roots.some((r) => {
147
+ const root = normalizeForCompare(r, cwd);
148
+ return norm === root || norm.startsWith(root.endsWith('/') ? root : `${root}/`);
149
+ });
150
+ }
151
+ /** canUseTool 各文件工具的路径参数抽取(Grep/Glob/LS 的 path 可缺省 → 缺省即任务 cwd,由调用方补齐) */
152
+ const TOOL_PATH_FIELDS = {
153
+ Read: ['file_path'],
154
+ Write: ['file_path'],
155
+ Edit: ['file_path'],
156
+ NotebookEdit: ['notebook_path'],
157
+ Grep: ['path'],
158
+ Glob: ['path'],
159
+ LS: ['path'],
160
+ };
161
+ /** 抽取工具入参中的候选路径(未声明路径参数的工具返回空数组) */
162
+ export function extractToolPaths(toolName, input) {
163
+ const fields = TOOL_PATH_FIELDS[toolName];
164
+ if (!fields)
165
+ return [];
166
+ const out = [];
167
+ for (const f of fields) {
168
+ const v = input[f];
169
+ if (typeof v === 'string' && v.trim())
170
+ out.push(v.trim());
171
+ }
172
+ return out;
173
+ }
174
+ /** 写红线约束的写工具集合(Edit/Write/NotebookEdit 之外无落盘写语义) */
175
+ export const WRITE_TOOLS = new Set(['Write', 'Edit', 'NotebookEdit']);
176
+ /**
177
+ * Bash 命令串红区特征探测(best-effort,见文件头说明):
178
+ * - 把命令文本中的 `~/` 引用展开后,检查是否包含任一红区模式的「字面前缀」(模式首个通配符之前
179
+ * 的字面部分,如 `~/.ssh/**` → `<home>/.ssh/`);
180
+ * - 纯通配开头(如双星开头再接 credentials)无稳定字面前缀,跳过——此类交给出站脱敏兜底。
181
+ * inboxRoot(入站附件豁免根)传入时:命中字面前缀后须命令串中该前缀的每一处出现都指向 inbox
182
+ * 根内才豁免该模式,任一处不指向仍命中——fail-closed,不扩大既有绕过面。
183
+ * 命中返回模式串,未命中返回 null。
184
+ */
185
+ export function bashHitsRedzone(command, matchers, inboxRoot) {
186
+ if (!command)
187
+ return null;
188
+ const expanded = command.replace(/(^|[\s"'=;(])~([/\\])/g, (_m, pre, sep) => `${pre}${homedir()}${sep}`);
189
+ const norm = normalizeForCompare(expanded);
190
+ const inboxNorm = inboxRoot ? normalizeForCompare(inboxRoot) : '';
191
+ for (const m of matchers) {
192
+ const literal = literalPrefix(m.id);
193
+ if (!literal || !norm.includes(literal))
194
+ continue;
195
+ if (inboxNorm && allOccurrencesUnderInbox(norm, literal, inboxNorm))
196
+ continue; // 全部指向 inbox → 豁免该模式
197
+ return m.id;
198
+ }
199
+ return null;
200
+ }
201
+ /** Bash token 断字字符集(豁免的 fail-closed 边界):inbox 根之后紧跟这些字符视为引用结束;
202
+ * 其余字符(含 : = * ? $ 等 shell 合法文件名成分)一律视为路径成分 → 不豁免回退 deny */
203
+ const BASH_TOKEN_BREAK = new Set([' ', '\t', '\n', '\r', '"', "'", '`', ';', '&', '|', '<', '>', '(', ')', ',']);
204
+ /** literal 在 norm 中的每一处出现是否都指向 inbox 根内(含根本身):
205
+ * - 出现处须完整匹配 inboxNorm 前缀(~/.ssh/inbox 一类「第一段恰好叫 inbox」的无关模式引用不会误豁免);
206
+ * - inboxNorm 之后须为 /(子路径)、串尾(根本身)或断字符;inbox2 / inbox:x 等视为不同路径 → false。
207
+ * 已知边界(与文件头 best-effort 口径一致):`inbox/../config.yaml` 回溯、命令替换编码不在字面探测
208
+ * 能力内(R1 结构化路径侧因 normalizeForCompare 走 resolve 折叠 .. 无此问题),根治靠 OS 层沙箱 */
209
+ function allOccurrencesUnderInbox(norm, literal, inboxNorm) {
210
+ for (let i = norm.indexOf(literal); i !== -1; i = norm.indexOf(literal, i + literal.length)) {
211
+ if (!norm.startsWith(inboxNorm, i))
212
+ return false;
213
+ const c = norm[i + inboxNorm.length];
214
+ if (c !== undefined && c !== '/' && !BASH_TOKEN_BREAK.has(c))
215
+ return false;
216
+ }
217
+ return true;
218
+ }
219
+ /** 模式串首个通配符前的字面前缀(归一化;无有效字面前缀返回 '') */
220
+ function literalPrefix(pattern) {
221
+ const cut = pattern.replace(/\\/g, '/').split('*')[0].replace(/[?]+$/, '');
222
+ if (!cut || cut === '/' || cut.endsWith(':'))
223
+ return '';
224
+ return normalizeForCompare(cut.endsWith('/') ? cut : `${cut}/`);
225
+ }
226
+ // 模块级编译缓存:红区模式源串 → 编译产物(模式列表小且变更低频,键取序列化串)
227
+ const matcherCache = new Map();
228
+ /** 带缓存的红区编译:同一份模式串(JSON 键)只编译一次,decide 热路径零重复开销 */
229
+ export function cachedPathMatchers(sources) {
230
+ const key = JSON.stringify(sources);
231
+ let m = matcherCache.get(key);
232
+ if (!m) {
233
+ m = compilePathPatterns(sources);
234
+ if (matcherCache.size > 32)
235
+ matcherCache.clear(); // 防热重载频繁变更导致的无界增长
236
+ matcherCache.set(key, m);
237
+ }
238
+ return m;
239
+ }
240
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/security/paths.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,kBAAkB;AAClB,oEAAoE;AACpE,iDAAiD;AACjD,kDAAkD;AAClD,yDAAyD;AACzD,2DAA2D;AAE3D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIhD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAsB;IAC7D,8BAA8B,EAAI,sGAAsG;IACxI,gBAAgB,EAAkB,iCAAiC;IACnE,cAAc,EAAoB,gCAAgC;IAClE,aAAa;IACb,WAAW;IACX,WAAW;IACX,aAAa;IACb,UAAU;IACV,oBAAoB;IACpB,2BAA2B,EAAO,8BAA8B;IAChE,6BAA6B;IAC7B,gDAAgD;IAChD,4BAA4B;IAC5B,iBAAiB;IACjB,YAAY;IACZ,cAAc;IACd,SAAS;IACT,WAAW;IACX,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,eAAe;CAChB,CAAC;AAEF,MAAM,gBAAgB,GAAG,QAAQ,EAAE,KAAK,OAAO,CAAC;AAEhD,sDAAsD;AACtD,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IACxE,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,IAAI,GAAG,KAAK,GAAG;QAAE,GAAG,GAAG,OAAO,EAAE,CAAC;SAC5B,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9C,OAAO,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACtD,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,6DAA6D;IAC7D,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA0B;IAC5D,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACzC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;YAAE,SAAS;QACrD,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,YAAY,GAAG,IAAI,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvC,6CAA6C;IAC7C,MAAM,SAAS,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,kBAAkB;IAClB,IAAI,CAAC,KAAK,GAAG;QAAE,CAAC,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;SACvC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;SACnD,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/E,wDAAwD;QACxD,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;IAChB,CAAC;IACD,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,sCAAsC;IACtC,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACrB,8BAA8B;gBAC9B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAAC,EAAE,IAAI,aAAa,CAAC;oBAAC,gBAAgB,GAAG,IAAI,CAAC;oBAAC,CAAC,IAAI,CAAC,CAAC;gBAAC,CAAC;qBAC1E,CAAC;oBAAC,EAAE,IAAI,IAAI,CAAC;oBAAC,gBAAgB,GAAG,IAAI,CAAC;oBAAC,CAAC,EAAE,CAAC;gBAAC,CAAC;YACpD,CAAC;iBAAM,CAAC;gBACN,EAAE,IAAI,OAAO,CAAC;gBACd,gBAAgB,GAAG,IAAI,CAAC;YAC1B,CAAC;YACD,SAAS;QACX,CAAC;QACD,EAAE,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,gBAAgB,GAAG,KAAK,CAAC;IAC3B,CAAC;IACD,4CAA4C;IAC5C,4CAA4C;IAC5C,IAAI,SAAS,IAAI,CAAC,gBAAgB;QAAE,EAAE,IAAI,UAAU,CAAC;IACrD,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,QAAgC,EAAE,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IACnG,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,IAAI,GAAG,mBAAmB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,EAAE,CAAC;QACjC,CAAC,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,cAAc,CAAC,CAAS,EAAE,KAAwB,EAAE,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IAC7F,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,MAAM,IAAI,GAAG,mBAAmB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;QACtB,MAAM,IAAI,GAAG,mBAAmB,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACzC,OAAO,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,gBAAgB,GAAsC;IAC1D,IAAI,EAAE,CAAC,WAAW,CAAC;IACnB,KAAK,EAAE,CAAC,WAAW,CAAC;IACpB,IAAI,EAAE,CAAC,WAAW,CAAC;IACnB,YAAY,EAAE,CAAC,eAAe,CAAC;IAC/B,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,IAAI,EAAE,CAAC,MAAM,CAAC;IACd,EAAE,EAAE,CAAC,MAAM,CAAC;CACb,CAAC;AAEF,oCAAoC;AACpC,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,KAA8B;IAC/E,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IACvB,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;AAE3F;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,QAAgC,EAChC,SAAkB;IAElB,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,EAAE,CAAC,EAAE,EAAE,GAAW,EAAE,GAAW,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IACzH,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QAClD,IAAI,SAAS,IAAI,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC;YAAE,SAAS,CAAC,qBAAqB;QACpG,OAAO,CAAC,CAAC,EAAE,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;6DAC6D;AAC7D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEjH;;;;0EAI0E;AAC1E,SAAS,wBAAwB,CAAC,IAAY,EAAE,OAAe,EAAE,SAAiB;IAChF,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5F,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;QACjD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC7E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uCAAuC;AACvC,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACxD,OAAO,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAClE,CAAC;AAED,2CAA2C;AAC3C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;AAEtD,mDAAmD;AACnD,MAAM,UAAU,kBAAkB,CAAC,OAA0B;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,YAAY,CAAC,IAAI,GAAG,EAAE;YAAE,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,kBAAkB;QACpE,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,59 @@
1
+ /** 单条脱敏规则(预编译) */
2
+ export interface RedactRule {
3
+ id: string;
4
+ re: RegExp;
5
+ }
6
+ /** 脱敏结果:脱敏后文本 + 命中规则 id 列表 + 是否命中金丝雀 */
7
+ export interface RedactResult {
8
+ text: string;
9
+ hits: string[];
10
+ canary: boolean;
11
+ }
12
+ /** 内置规则源(调试用可读形态;运行期统一 gi/less 编译) */
13
+ export declare const DEFAULT_REDACT_RULE_SOURCES: ReadonlyArray<{
14
+ id: string;
15
+ source: string;
16
+ flags: string;
17
+ }>;
18
+ /** 默认金丝雀标记:命中即视为「防线被穿透」的证据 */
19
+ export declare const DEFAULT_CANARY_PATTERNS: readonly string[];
20
+ /** 命中后的统一掩码(完整丢弃,不保留前后缀——前缀本身也可能是敏感信息的一部分) */
21
+ export declare const REDACT_MASK = "******";
22
+ /**
23
+ * 编译用户自定义规则(config security.redact_patterns):
24
+ * 非法正则跳过并 warn(配置页能保存的自由文本,不能让一条坏正则拖垮出站链路)。
25
+ */
26
+ export declare function compileCustomRules(sources?: string[]): RedactRule[];
27
+ /**
28
+ * 对单段文本执行脱敏。规则依次扫描,命中区间统一替换为 REDACT_MASK(完整丢弃);
29
+ * 逐规则计时,超预算放弃该规则剩余扫描(防用户正则灾难性回溯挂死出站链路)。
30
+ */
31
+ export declare function redactText(text: string, rules?: readonly RedactRule[], canaryPatterns?: readonly string[]): RedactResult;
32
+ /**
33
+ * 递归脱敏任意 JSON 结构(卡片对象/数组/字符串):只改写字符串叶子,结构保持不变。
34
+ * 用于网关出口的深度兜底——进度卡流式正文、diff 卡片、结果卡、notify 文本全部经此。
35
+ */
36
+ export declare function redactDeep<T>(value: T, rules?: readonly RedactRule[], canaryPatterns?: readonly string[]): {
37
+ value: T;
38
+ hits: string[];
39
+ canary: boolean;
40
+ };
41
+ /** 脱敏器门面:内置 + 自定义规则编译产物,供网关 / wiring 复用 */
42
+ export declare class Redactor {
43
+ private rules;
44
+ private canaryPatterns;
45
+ constructor(rules: RedactRule[], canaryPatterns: readonly string[]);
46
+ text(text: string): RedactResult;
47
+ deep<T>(value: T): {
48
+ value: T;
49
+ hits: string[];
50
+ canary: boolean;
51
+ };
52
+ }
53
+ /** Redactor 配置源(config security 段的相关字段) */
54
+ export interface RedactorConfig {
55
+ redactPatterns?: string[];
56
+ canaryPatterns?: string[];
57
+ }
58
+ /** 按配置取脱敏器(模块级 memo,同一份配置只编译一次) */
59
+ export declare function getRedactor(cfg?: RedactorConfig): Redactor;
@@ -0,0 +1,151 @@
1
+ // R3 出站脱敏引擎:所有离开 bridge 进程的文本(卡片/流式块/最终回复/caption)必经的
2
+ // 最后保险丝。定位与边界(方案 v3 §一):
3
+ // - 兜得住「意外」:模型无意识复述凭证形字符串(key/token/PEM/JWT/长 hex);
4
+ // - 兜不住「恶意」:被注入后刻意转述/编码/拆分——恶意的解在 R1(读不到)与 R4(工具不存在),
5
+ // 本模块是保险丝 + 审计采样点,不是安全保证本身。
6
+ // 金丝雀(canary):主人在敏感路径附近埋的假密钥标记;一旦出现在任何出站文本 = 防线被穿透,
7
+ // 除脱敏外必须触发告警(调用方据 canary 标志处置)。
8
+ // ReDoS 对策:内置规则均为线性形态(无嵌套量词);用户自定义正则限制条数与长度、预编译校验,
9
+ // 且逐规则计时超预算即放弃该规则(宁可漏一条自定义规则,不让 bridge 挂死)。
10
+ /** 内置规则源(调试用可读形态;运行期统一 gi/less 编译) */
11
+ export const DEFAULT_REDACT_RULE_SOURCES = [
12
+ // JWT(三段 base64url)
13
+ { id: 'jwt', source: 'eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}', flags: 'g' },
14
+ // Authorization: Bearer xxx / authorization: xxx
15
+ { id: 'bearer', source: 'Authorization["\']?\\s*[:=]\\s*["\']?Bearer\\s+[A-Za-z0-9._~+/=-]{8,}', flags: 'gi' },
16
+ // API key:sk- / sk-ant- / sk-cp- 等前缀(连字符在字符类内,覆盖全部变体)
17
+ { id: 'api-key', source: '\\bsk-[A-Za-z0-9_-]{16,}\\b', flags: 'g' },
18
+ // PEM 私钥块(全文量词封顶,防退化)
19
+ { id: 'pem-key', source: '-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]{0,4000}?-----END[ A-Z]*PRIVATE KEY-----', flags: 'g' },
20
+ // 键值对形态:password=xxx / "api_key": "xxx" —— 只打码值,保留键名(上下文可读)
21
+ {
22
+ id: 'secret-kv',
23
+ source: '\\b(password|passwd|pwd|secret|app_secret|appsecret|api_key|apikey|access_key|access_token|refresh_token|auth_token|client_secret|private_key|token)\\b["\']?\\s*[:=]\\s*["\']?([^\\s"\']{4,})',
24
+ flags: 'gi',
25
+ },
26
+ // URL 内嵌凭证:https://user:pass@host
27
+ { id: 'url-cred', source: '\\bhttps?://[^\\s/@:]+:[^\\s/@]{4,}@', flags: 'g' },
28
+ // ≥32 位连续 hex(密钥/摘要常见形态;git SHA/UUID 会被误伤——已知误报,换取覆盖面)
29
+ { id: 'hex-32', source: '\\b[a-f0-9]{32,}\\b', flags: 'gi' },
30
+ ];
31
+ /** 默认金丝雀标记:命中即视为「防线被穿透」的证据 */
32
+ export const DEFAULT_CANARY_PATTERNS = ['sk-canary-', 'lcb-canary-', 'CANARY-SECRET-'];
33
+ /** 命中后的统一掩码(完整丢弃,不保留前后缀——前缀本身也可能是敏感信息的一部分) */
34
+ export const REDACT_MASK = '******';
35
+ // 自定义规则护栏:条数/长度上限 + 单规则扫描时间预算(毫秒)
36
+ const MAX_CUSTOM_RULES = 20;
37
+ const MAX_CUSTOM_PATTERN_LENGTH = 200;
38
+ const RULE_TIME_BUDGET_MS = 250;
39
+ /** 编译内置规则(模块级单例:正则编译一次复用) */
40
+ const BUILTIN_RULES = DEFAULT_REDACT_RULE_SOURCES.map(({ id, source, flags }) => ({ id, re: new RegExp(source, flags) }));
41
+ /**
42
+ * 编译用户自定义规则(config security.redact_patterns):
43
+ * 非法正则跳过并 warn(配置页能保存的自由文本,不能让一条坏正则拖垮出站链路)。
44
+ */
45
+ export function compileCustomRules(sources) {
46
+ if (!sources?.length)
47
+ return [];
48
+ const out = [];
49
+ for (const [i, raw] of sources.entries()) {
50
+ if (out.length >= MAX_CUSTOM_RULES)
51
+ break;
52
+ if (typeof raw !== 'string' || !raw.trim())
53
+ continue;
54
+ if (raw.length > MAX_CUSTOM_PATTERN_LENGTH) {
55
+ console.warn(`[security] 自定义脱敏正则 #${i + 1} 超过 ${MAX_CUSTOM_PATTERN_LENGTH} 字符,已忽略`);
56
+ continue;
57
+ }
58
+ try {
59
+ out.push({ id: `custom-${i + 1}`, re: new RegExp(raw, 'g') });
60
+ }
61
+ catch (e) {
62
+ console.warn(`[security] 自定义脱敏正则 #${i + 1} 编译失败已忽略(${raw.slice(0, 40)}…):`, e instanceof Error ? e.message : e);
63
+ }
64
+ }
65
+ return out;
66
+ }
67
+ /**
68
+ * 对单段文本执行脱敏。规则依次扫描,命中区间统一替换为 REDACT_MASK(完整丢弃);
69
+ * 逐规则计时,超预算放弃该规则剩余扫描(防用户正则灾难性回溯挂死出站链路)。
70
+ */
71
+ export function redactText(text, rules = [], canaryPatterns = DEFAULT_CANARY_PATTERNS) {
72
+ // 金丝雀先于脱敏检测:标记本身长得像密钥,脱敏后再查就永远查不到了
73
+ const lowered = text.toLowerCase();
74
+ const canary = (canaryPatterns ?? []).some((p) => p && lowered.includes(p.toLowerCase()));
75
+ const hits = [];
76
+ let out = text;
77
+ for (const rule of [...BUILTIN_RULES, ...rules]) {
78
+ const t0 = Date.now();
79
+ out = out.replace(rule.re, (...args) => {
80
+ const match = args[0];
81
+ if (Date.now() - t0 > RULE_TIME_BUDGET_MS)
82
+ return match; // 超预算:本条不再打码(保命优先)
83
+ hits.push(rule.id);
84
+ // secret-kv 规则保留键名只打码值:第二捕获组 = 值本身(键保留,上下文可读)
85
+ if (rule.id === 'secret-kv') {
86
+ const value = args[2];
87
+ if (typeof value === 'string' && value.length > 0) {
88
+ return `${match.slice(0, match.length - value.length)}${REDACT_MASK}`;
89
+ }
90
+ }
91
+ return REDACT_MASK;
92
+ });
93
+ rule.re.lastIndex = 0; // g 标记正则跨调用复用时必须复位(字符串 replace 内部虽会管,防御性复位)
94
+ }
95
+ return { text: out, hits, canary };
96
+ }
97
+ /**
98
+ * 递归脱敏任意 JSON 结构(卡片对象/数组/字符串):只改写字符串叶子,结构保持不变。
99
+ * 用于网关出口的深度兜底——进度卡流式正文、diff 卡片、结果卡、notify 文本全部经此。
100
+ */
101
+ export function redactDeep(value, rules = [], canaryPatterns = DEFAULT_CANARY_PATTERNS) {
102
+ const hits = [];
103
+ let canary = false;
104
+ const walk = (v) => {
105
+ if (typeof v === 'string') {
106
+ const r = redactText(v, rules, canaryPatterns);
107
+ if (r.hits.length)
108
+ hits.push(...r.hits);
109
+ if (r.canary)
110
+ canary = true;
111
+ return r.text;
112
+ }
113
+ if (Array.isArray(v))
114
+ return v.map(walk);
115
+ if (v && typeof v === 'object') {
116
+ const out = {};
117
+ for (const [k, val] of Object.entries(v))
118
+ out[k] = walk(val);
119
+ return out;
120
+ }
121
+ return v;
122
+ };
123
+ return { value: walk(value), hits, canary };
124
+ }
125
+ /** 脱敏器门面:内置 + 自定义规则编译产物,供网关 / wiring 复用 */
126
+ export class Redactor {
127
+ rules;
128
+ canaryPatterns;
129
+ constructor(rules, canaryPatterns) {
130
+ this.rules = rules;
131
+ this.canaryPatterns = canaryPatterns;
132
+ }
133
+ text(text) { return redactText(text, this.rules, this.canaryPatterns); }
134
+ deep(value) { return redactDeep(value, this.rules, this.canaryPatterns); }
135
+ }
136
+ // 配置键 → 编译产物 memo:热重载 mutate config.security 后键变化即自动重编译,
137
+ // 未变化时零开销复用(出站链路每张卡都要走,编译不能反复发生)
138
+ const redactorCache = new Map();
139
+ /** 按配置取脱敏器(模块级 memo,同一份配置只编译一次) */
140
+ export function getRedactor(cfg) {
141
+ const key = JSON.stringify({ r: cfg?.redactPatterns ?? [], c: cfg?.canaryPatterns ?? [] });
142
+ let r = redactorCache.get(key);
143
+ if (!r) {
144
+ r = new Redactor(compileCustomRules(cfg?.redactPatterns), cfg?.canaryPatterns ?? DEFAULT_CANARY_PATTERNS);
145
+ if (redactorCache.size > 16)
146
+ redactorCache.clear();
147
+ redactorCache.set(key, r);
148
+ }
149
+ return r;
150
+ }
151
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/security/redact.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,12 @@ export interface ChannelState {
24
24
  /** 通道级计划模式(/plan 命令切换,跨重启持久;/new 不清除——它是通道偏好而非会话状态)。
25
25
  * true = 任务以 plan mode 启动(模型先出计划 → 飞书卡片批准后执行);缺省 = 直接执行 */
26
26
  planMode?: boolean;
27
+ /** 最近一次任务完成时间(ISO):群聊空闲滚动(session.groupIdleResetHours)的判定基准。
28
+ * 每个任务收尾经 markActivity 刷新;缺省 = 无记录(不触发空闲滚动,首轮轮次滚动仍可生效) */
29
+ lastActiveAt?: string;
30
+ /** 当前会话累计任务轮次(每任务收尾 +1,切换续接指针时清零):群聊轮次滚动
31
+ * (session.groupMaxTurns)的判定基准。口径按飞书消息任务数计(非 CLI 主循环轮次) */
32
+ turnCount?: number;
27
33
  }
28
34
  /**
29
35
  * 通道会话存储:JSON 文件持久化,每个 channelKey 一份 ChannelState。
@@ -52,9 +58,18 @@ export declare class SessionStore {
52
58
  * /new 传 null(下个任务新开会话,历史保留);/resume <n> 传选中 sessionId。
53
59
  * null 显式落盘(JSON 保留 "currentSessionId": null)——读取端以「字段缺失 vs null」
54
60
  * 区分存量数据与用户主动 /new,不能 delete(会退化为 undefined,见 ChannelState 注释)。
61
+ * 切换指针 = 切换会话(三个调用方 /new、/resume <n>、/ws use 与群聊自动滚动同语义),
62
+ * 轮次计数随之清零——turnCount 度量的是「当前会话跑了多少任务」,换了会话从头计。
55
63
  * channel 不存在时以 defaultWorkspace 初始化后设置。
56
64
  */
57
65
  setCurrentSession(key: string, sessionId: string | null, defaultWorkspace?: string): void;
66
+ /**
67
+ * 任务收尾记一次通道活跃(生命周期方案 A3 滚动计数据源):
68
+ * lastActiveAt = 当前时间(群聊空闲滚动基准),turnCount +1(群聊轮次滚动基准)。
69
+ * 成功/出错/被停止的任务都算一轮——只要上下文被消耗就在向滚动阈值累积。
70
+ * 不动指针与会话历史(归档由 archiveSession 负责,两者先后执行互不干扰)。
71
+ */
72
+ markActivity(key: string): void;
58
73
  /**
59
74
  * 开启新会话:channel 不存在时以 defaultWorkspace 初始化;
60
75
  * 已存在时保持工作区与历史不变(历史由 /new 命令显式清空)。
@@ -53,11 +53,27 @@ export class SessionStore {
53
53
  * /new 传 null(下个任务新开会话,历史保留);/resume <n> 传选中 sessionId。
54
54
  * null 显式落盘(JSON 保留 "currentSessionId": null)——读取端以「字段缺失 vs null」
55
55
  * 区分存量数据与用户主动 /new,不能 delete(会退化为 undefined,见 ChannelState 注释)。
56
+ * 切换指针 = 切换会话(三个调用方 /new、/resume <n>、/ws use 与群聊自动滚动同语义),
57
+ * 轮次计数随之清零——turnCount 度量的是「当前会话跑了多少任务」,换了会话从头计。
56
58
  * channel 不存在时以 defaultWorkspace 初始化后设置。
57
59
  */
58
60
  setCurrentSession(key, sessionId, defaultWorkspace = '') {
59
61
  const st = this.data[key] ?? { workspaceName: defaultWorkspace, sessions: [] };
60
62
  st.currentSessionId = sessionId;
63
+ st.turnCount = 0;
64
+ this.data[key] = st;
65
+ this.save();
66
+ }
67
+ /**
68
+ * 任务收尾记一次通道活跃(生命周期方案 A3 滚动计数据源):
69
+ * lastActiveAt = 当前时间(群聊空闲滚动基准),turnCount +1(群聊轮次滚动基准)。
70
+ * 成功/出错/被停止的任务都算一轮——只要上下文被消耗就在向滚动阈值累积。
71
+ * 不动指针与会话历史(归档由 archiveSession 负责,两者先后执行互不干扰)。
72
+ */
73
+ markActivity(key) {
74
+ const st = this.data[key] ?? { workspaceName: '', sessions: [] };
75
+ st.lastActiveAt = new Date().toISOString();
76
+ st.turnCount = (st.turnCount ?? 0) + 1;
61
77
  this.data[key] = st;
62
78
  this.save();
63
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/session/session-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/session/session-store.ts"],"names":[],"mappings":"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"}