@jesonliu/lark-claudecode-bridge 1.4.3 → 2.0.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.
- package/assets/web/css/main.css +766 -574
- package/assets/web/index.html +37 -17
- package/assets/web/js/auth.js +217 -0
- package/assets/web/js/bootstrap.js +36 -34
- package/assets/web/js/core.js +4 -3
- package/assets/web/js/main.js +79 -20
- package/assets/web/js/markdown.js +64 -0
- package/assets/web/js/pages/apps.js +338 -251
- package/assets/web/js/pages/chats.js +446 -0
- package/assets/web/js/pages/claude.js +243 -180
- package/assets/web/js/pages/mcp.js +59 -43
- package/assets/web/js/pages/memory.js +39 -43
- package/assets/web/js/pages/overview.js +344 -76
- package/assets/web/js/pages/permissions.js +40 -32
- package/assets/web/js/pages/plugins.js +51 -37
- package/assets/web/js/pages/skills.js +68 -92
- package/assets/web/js/pages/slash.js +31 -23
- package/assets/web/js/pages/workspaces.js +114 -73
- package/assets/web/js/theme.js +21 -18
- package/assets/web/js/ui.js +75 -32
- package/dist/bin/lcb.js +15 -0
- package/dist/bin/lcb.js.map +1 -1
- package/dist/gateway/feishu-gateway.d.ts +11 -0
- package/dist/gateway/feishu-gateway.js +5 -0
- package/dist/gateway/feishu-gateway.js.map +1 -1
- package/dist/gateway/gateway-registry.d.ts +16 -0
- package/dist/gateway/gateway-registry.js +10 -0
- package/dist/gateway/gateway-registry.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/web/chats-api.d.ts +77 -0
- package/dist/web/chats-api.js +475 -0
- package/dist/web/chats-api.js.map +1 -0
- package/dist/web/logs-api.d.ts +37 -0
- package/dist/web/logs-api.js +141 -0
- package/dist/web/logs-api.js.map +1 -0
- package/dist/web/server.js +125 -6
- package/dist/web/server.js.map +1 -1
- package/dist/web/webauth.d.ts +44 -0
- package/dist/web/webauth.js +177 -0
- package/dist/web/webauth.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface ChatChannelSummary {
|
|
2
|
+
chatId: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
/** p2p / group;拉不到时可能为空串 */
|
|
5
|
+
chatType: string;
|
|
6
|
+
nameSource: 'feishu' | 'access' | 'fallback';
|
|
7
|
+
users: Array<{
|
|
8
|
+
userId: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** 有记录的日期(新→旧),前端日期下拉直接用 */
|
|
12
|
+
dates: string[];
|
|
13
|
+
lastActiveAt: string;
|
|
14
|
+
/** 话题数(session-store 口径 = 该通道全部 CC 会话) */
|
|
15
|
+
topics: number;
|
|
16
|
+
sizeBytes: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ChatBotSummary {
|
|
19
|
+
appId: string;
|
|
20
|
+
name: string;
|
|
21
|
+
channels: ChatChannelSummary[];
|
|
22
|
+
}
|
|
23
|
+
export declare function chatsTree(configPath: string): Promise<{
|
|
24
|
+
bots: ChatBotSummary[];
|
|
25
|
+
}>;
|
|
26
|
+
export interface ChatTopicSummary {
|
|
27
|
+
sessionId: string;
|
|
28
|
+
title: string;
|
|
29
|
+
updatedAt: string;
|
|
30
|
+
users: string[];
|
|
31
|
+
}
|
|
32
|
+
/** 某通道的话题列表(session-store 聚合:跨 userId 合并、同 sessionId 去重取最新)。标题 = 首条消息摘要 */
|
|
33
|
+
export declare function chatTopics(appId: string, chatId: string): {
|
|
34
|
+
topics: ChatTopicSummary[];
|
|
35
|
+
};
|
|
36
|
+
export interface ToolStep {
|
|
37
|
+
ts: string;
|
|
38
|
+
tool: string;
|
|
39
|
+
ok?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** 任务 = 一条飞书消息触发的一次 CC 执行:user 提问 + 流式回复拼接 + 工具步骤 + 收尾状态 */
|
|
42
|
+
export interface ChatTask {
|
|
43
|
+
date: string;
|
|
44
|
+
ts: string;
|
|
45
|
+
userId: string;
|
|
46
|
+
workspace?: string;
|
|
47
|
+
/** 权威 CC 会话 id(result 行优先;新话题首轮 user 行的起点指针兜底) */
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
prompt: string;
|
|
50
|
+
/** 流式回复块顺序拼接;无流式块时回退 result 文本(错误信息等) */
|
|
51
|
+
reply: string;
|
|
52
|
+
tools: ToolStep[];
|
|
53
|
+
result?: {
|
|
54
|
+
subtype: string;
|
|
55
|
+
producedFiles?: string[];
|
|
56
|
+
turns?: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export interface ChatTimelineResult {
|
|
60
|
+
tasks: ChatTask[];
|
|
61
|
+
truncated: boolean;
|
|
62
|
+
partial: boolean;
|
|
63
|
+
scanDays: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 时间线查询。三种口径:
|
|
67
|
+
* - date 指定:单日视图(不过索引,直读该日文件)
|
|
68
|
+
* - session 指定:话题视图(索引定位该会话出现的日期,再跨天聚合归属任务)——任何历史话题都能看全
|
|
69
|
+
* - 都不传:最新往旧全量(防呆上限内),供「全部记录」浏览
|
|
70
|
+
* 返回任务序列(时间升序);truncated=达到单次返回上限,partial=索引被防呆上限截断。
|
|
71
|
+
*/
|
|
72
|
+
export declare function chatTimeline(appId: string, chatId: string, query: {
|
|
73
|
+
date?: string;
|
|
74
|
+
session?: string;
|
|
75
|
+
user?: string;
|
|
76
|
+
limit?: number;
|
|
77
|
+
}): ChatTimelineResult;
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
// 「会话记录」页后端(三接口,全部只读):树(机器人 → 通道)/ 话题(CC 会话聚合)/ 时间线。
|
|
2
|
+
// 数据源全部是 LCB 自有落盘,与记忆增强是否开启完全无关:
|
|
3
|
+
// - transcripts/<appId>/<chatId>/<YYYY-MM-DD>.jsonl:对话全文流水(transcript-writer,按天分文件)
|
|
4
|
+
// - sessions.<appId>.json:每通道话题索引(sessionId + 首条消息摘要,/resume 列表同源)
|
|
5
|
+
// - access.json:userId → 飞书人名
|
|
6
|
+
// 群名/会话类型经运行中网关的飞书 REST 现拉(gateway-registry;成功缓存 24h、失败短缓存 10 分钟
|
|
7
|
+
// ——权限补开后十分钟内自动恢复真名,不必重启)。lcb ui 独立进程无网关来源 → 走降级显示名。
|
|
8
|
+
// 设计基调:查看器不能因数据缺失报错——目录/文件缺失按空处理、坏行跳过、ID 白名单防路径穿越。
|
|
9
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { CONFIG_DIR, loadConfig } from '../config.js';
|
|
12
|
+
import { getChatInfoSource } from '../gateway/gateway-registry.js';
|
|
13
|
+
const TRANSCRIPTS_DIR = join(CONFIG_DIR, 'transcripts');
|
|
14
|
+
/** 路径安全:appId/chatId 仅接受飞书 id 字符集(拼路径前把守,杜绝 ../ 穿越);日期由白名单正则把守 */
|
|
15
|
+
const ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
16
|
+
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
17
|
+
const JSONL_RE = /^\d{4}-\d{2}-\d{2}\.jsonl$/;
|
|
18
|
+
/** 话题跨天索引的防呆上限(主人已拍板:无天数上限;此处仅防异常巨库一次性拖死进程) */
|
|
19
|
+
const MAX_SCAN_FILES = 300;
|
|
20
|
+
const MAX_SCAN_BYTES = 150 * 1024 * 1024;
|
|
21
|
+
/** 时间线单次返回的任务数上限(前端「仅显示最近 N 条」提示的口径) */
|
|
22
|
+
const DEFAULT_TASK_LIMIT = 400;
|
|
23
|
+
function listDirs(dir) {
|
|
24
|
+
try {
|
|
25
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
26
|
+
.filter((e) => e.isDirectory() && ID_RE.test(e.name))
|
|
27
|
+
.map((e) => e.name)
|
|
28
|
+
.sort();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return [];
|
|
32
|
+
} // transcripts 目录不存在(尚无任何对话)= 空树而非报错
|
|
33
|
+
}
|
|
34
|
+
function listDateFiles(dir) {
|
|
35
|
+
try {
|
|
36
|
+
return readdirSync(dir).filter((f) => JSONL_RE.test(f)).sort().reverse(); // 新→旧
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** access.json 人名表(userId → name;损坏/缺失按空表,查看器不因准入数据报错) */
|
|
43
|
+
function readAccessNames() {
|
|
44
|
+
const out = new Map();
|
|
45
|
+
try {
|
|
46
|
+
const raw = JSON.parse(readFileSync(join(CONFIG_DIR, 'access.json'), 'utf8'));
|
|
47
|
+
for (const [uid, u] of Object.entries(raw.users ?? {})) {
|
|
48
|
+
if (u?.name)
|
|
49
|
+
out.set(uid, u.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch { /* 无准入数据:人名全部走 chatId/尾号降级 */ }
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
/** sessions.<appId>.json 原样读(channelKey → ChannelState);缺失/损坏按空表 */
|
|
56
|
+
function readSessionStore(appId) {
|
|
57
|
+
try {
|
|
58
|
+
const raw = JSON.parse(readFileSync(join(CONFIG_DIR, `sessions.${appId}.json`), 'utf8'));
|
|
59
|
+
return raw && typeof raw === 'object' ? raw : {};
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const chatMetaCache = new Map(); // key `${appId}/${chatId}`
|
|
66
|
+
const META_OK_TTL_MS = 24 * 60 * 60 * 1000; // 群名成功缓存 24h(群改名次日自动刷新)
|
|
67
|
+
const META_FAIL_TTL_MS = 10 * 60 * 1000; // 拉取失败短缓存:im:chat 权限补开后十分钟内自动恢复真名
|
|
68
|
+
async function fetchChatMeta(appId, chatId) {
|
|
69
|
+
const key = `${appId}/${chatId}`;
|
|
70
|
+
const hit = chatMetaCache.get(key);
|
|
71
|
+
// 失败态(无 name)用短 TTL 重试;成功态 24h
|
|
72
|
+
if (hit && Date.now() - hit.at < (hit.name ? META_OK_TTL_MS : META_FAIL_TTL_MS))
|
|
73
|
+
return hit;
|
|
74
|
+
const src = getChatInfoSource(appId);
|
|
75
|
+
if (!src)
|
|
76
|
+
return hit; // 桥未运行(lcb ui 独立进程):吃旧缓存,没有则降级
|
|
77
|
+
try {
|
|
78
|
+
const res = await src.request({ method: 'GET', url: `/open-apis/im/v1/chats/${encodeURIComponent(chatId)}` });
|
|
79
|
+
const data = res.data;
|
|
80
|
+
if (res.code === 0 && typeof data?.name === 'string' && data.name) {
|
|
81
|
+
const meta = {
|
|
82
|
+
name: data.name,
|
|
83
|
+
chatType: typeof data.chat_type === 'string' ? data.chat_type : '',
|
|
84
|
+
at: Date.now(),
|
|
85
|
+
};
|
|
86
|
+
chatMetaCache.set(key, meta);
|
|
87
|
+
return meta;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch { /* 机器人不在群 / 权限缺失 / 网络失败:降级显示名 */ }
|
|
91
|
+
const failed = { at: Date.now() };
|
|
92
|
+
chatMetaCache.set(key, failed);
|
|
93
|
+
// 曾拉到过真名(缓存过期后的重拉失败)→ 继续用旧真名,好过降级串
|
|
94
|
+
return hit?.name ? hit : failed;
|
|
95
|
+
}
|
|
96
|
+
function chatIdTail(chatId) {
|
|
97
|
+
return chatId.length > 6 ? chatId.slice(-6) : chatId;
|
|
98
|
+
}
|
|
99
|
+
const userNameCache = new Map(); // key `${appId}/${openId}`
|
|
100
|
+
const USER_OK_TTL_MS = 24 * 60 * 60 * 1000;
|
|
101
|
+
const USER_FAIL_TTL_MS = 10 * 60 * 1000;
|
|
102
|
+
/** contact batch 接口单次 user_ids 上限(官方约定 ≤50) */
|
|
103
|
+
const USER_BATCH_SIZE = 50;
|
|
104
|
+
/** 批量解析 open_id → 姓名。整批失败(权限/网络)落短缓存防每轮树接口重打;零结果视为失败态 */
|
|
105
|
+
async function fetchUserNames(appId, ids) {
|
|
106
|
+
const out = new Map();
|
|
107
|
+
const need = [];
|
|
108
|
+
for (const id of ids) {
|
|
109
|
+
const hit = userNameCache.get(`${appId}/${id}`);
|
|
110
|
+
if (hit && Date.now() - hit.at < (hit.name ? USER_OK_TTL_MS : USER_FAIL_TTL_MS)) {
|
|
111
|
+
if (hit.name)
|
|
112
|
+
out.set(id, hit.name);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
need.push(id);
|
|
116
|
+
}
|
|
117
|
+
if (!need.length)
|
|
118
|
+
return out;
|
|
119
|
+
const src = getChatInfoSource(appId);
|
|
120
|
+
if (!src)
|
|
121
|
+
return out; // 桥未运行(lcb ui 独立进程):吃缓存,没有则本轮降级,不报错
|
|
122
|
+
for (let i = 0; i < need.length; i += USER_BATCH_SIZE) {
|
|
123
|
+
const batch = need.slice(i, i + USER_BATCH_SIZE);
|
|
124
|
+
const qs = batch.map((id) => `user_ids=${encodeURIComponent(id)}`).join('&');
|
|
125
|
+
let okBatch = false;
|
|
126
|
+
try {
|
|
127
|
+
const res = await src.request({
|
|
128
|
+
method: 'GET',
|
|
129
|
+
url: `/open-apis/contact/v3/users/batch?user_id_type=open_id&${qs}`,
|
|
130
|
+
});
|
|
131
|
+
const items = res.code === 0
|
|
132
|
+
? res.data?.items
|
|
133
|
+
: undefined;
|
|
134
|
+
if (Array.isArray(items)) {
|
|
135
|
+
const got = new Set();
|
|
136
|
+
for (const it of items) {
|
|
137
|
+
const uid = it.user_id;
|
|
138
|
+
const name = it.name;
|
|
139
|
+
if (typeof uid === 'string' && typeof name === 'string' && name) {
|
|
140
|
+
userNameCache.set(`${appId}/${uid}`, { name, at: Date.now() });
|
|
141
|
+
out.set(uid, name);
|
|
142
|
+
got.add(uid);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
okBatch = true;
|
|
146
|
+
// 本批未被接口返回的 id:落失败短缓存(10 分钟后自动重试,可能后配对)
|
|
147
|
+
for (const id of batch) {
|
|
148
|
+
if (!got.has(id))
|
|
149
|
+
userNameCache.set(`${appId}/${id}`, { at: Date.now() });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch { /* 机器人无该用户可见范围 / 权限缺失 / 网络失败:降级 */ }
|
|
154
|
+
if (!okBatch) {
|
|
155
|
+
for (const id of batch)
|
|
156
|
+
userNameCache.set(`${appId}/${id}`, { at: Date.now() });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
/** 显示名三级降级:飞书真名 → access 人名(单用户=p2p)→ 「群聊(N人)/会话 ·尾号」 */
|
|
162
|
+
function buildDisplayName(meta, users, access, chatId) {
|
|
163
|
+
if (meta?.name)
|
|
164
|
+
return { displayName: meta.name, chatType: meta.chatType || '', nameSource: 'feishu' };
|
|
165
|
+
if (users.length === 1) {
|
|
166
|
+
const n = access.get(users[0]);
|
|
167
|
+
if (n)
|
|
168
|
+
return { displayName: n, chatType: 'p2p', nameSource: 'access' };
|
|
169
|
+
}
|
|
170
|
+
const label = users.length > 1 ? `群聊(${users.length}人)` : '会话';
|
|
171
|
+
return { displayName: `${label} ·${chatIdTail(chatId)}`, chatType: users.length > 1 ? 'group' : '', nameSource: 'fallback' };
|
|
172
|
+
}
|
|
173
|
+
export async function chatsTree(configPath) {
|
|
174
|
+
let config;
|
|
175
|
+
try {
|
|
176
|
+
config = loadConfig(configPath);
|
|
177
|
+
}
|
|
178
|
+
catch { /* 配置损坏也照常扫目录:显示名退化为 appId */ }
|
|
179
|
+
const appNames = new Map((config?.apps ?? []).map((a) => [a.appId, a.name || a.appId]));
|
|
180
|
+
const access = readAccessNames();
|
|
181
|
+
const bots = [];
|
|
182
|
+
for (const appId of listDirs(TRANSCRIPTS_DIR)) {
|
|
183
|
+
const store = readSessionStore(appId);
|
|
184
|
+
// channelKey = `${chatId}:${userId}`(session/channel.ts 口径)→ 按 chatId 聚合用户与话题数
|
|
185
|
+
const usersByChat = new Map();
|
|
186
|
+
const topicCountByChat = new Map();
|
|
187
|
+
for (const [key, st] of Object.entries(store)) {
|
|
188
|
+
const i = key.lastIndexOf(':');
|
|
189
|
+
if (i <= 0)
|
|
190
|
+
continue;
|
|
191
|
+
const chatId = key.slice(0, i);
|
|
192
|
+
const userId = key.slice(i + 1);
|
|
193
|
+
let arr = usersByChat.get(chatId);
|
|
194
|
+
if (!arr)
|
|
195
|
+
usersByChat.set(chatId, arr = []);
|
|
196
|
+
if (!arr.includes(userId))
|
|
197
|
+
arr.push(userId);
|
|
198
|
+
topicCountByChat.set(chatId, (topicCountByChat.get(chatId) ?? 0) + (st.sessions?.length ?? 0));
|
|
199
|
+
}
|
|
200
|
+
const channels = [];
|
|
201
|
+
for (const chatId of listDirs(join(TRANSCRIPTS_DIR, appId))) {
|
|
202
|
+
const dates = [];
|
|
203
|
+
let lastActiveMs = 0;
|
|
204
|
+
let sizeBytes = 0;
|
|
205
|
+
for (const f of listDateFiles(join(TRANSCRIPTS_DIR, appId, chatId))) {
|
|
206
|
+
dates.push(f.slice(0, 10));
|
|
207
|
+
try {
|
|
208
|
+
const st = statSync(join(TRANSCRIPTS_DIR, appId, chatId, f));
|
|
209
|
+
lastActiveMs = Math.max(lastActiveMs, st.mtimeMs);
|
|
210
|
+
sizeBytes += st.size;
|
|
211
|
+
}
|
|
212
|
+
catch { /* 文件恰好被清理:跳过 */ }
|
|
213
|
+
}
|
|
214
|
+
const users = usersByChat.get(chatId) ?? [];
|
|
215
|
+
const meta = await fetchChatMeta(appId, chatId);
|
|
216
|
+
// 发信人真名:access(配对人名,用户自填优先)+ 飞书通讯录解析兜底,合并后同源展示
|
|
217
|
+
const feishuNames = await fetchUserNames(appId, users);
|
|
218
|
+
const nameMap = new Map([...feishuNames, ...access]);
|
|
219
|
+
const name = buildDisplayName(meta, users, nameMap, chatId);
|
|
220
|
+
channels.push({
|
|
221
|
+
chatId,
|
|
222
|
+
displayName: name.displayName,
|
|
223
|
+
chatType: name.chatType,
|
|
224
|
+
nameSource: name.nameSource,
|
|
225
|
+
users: users.map((userId) => ({ userId, ...(nameMap.get(userId) ? { name: nameMap.get(userId) } : {}) })),
|
|
226
|
+
dates,
|
|
227
|
+
lastActiveAt: lastActiveMs ? new Date(lastActiveMs).toISOString() : '',
|
|
228
|
+
topics: topicCountByChat.get(chatId) ?? 0,
|
|
229
|
+
sizeBytes,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
channels.sort((a, b) => b.lastActiveAt.localeCompare(a.lastActiveAt));
|
|
233
|
+
bots.push({ appId, name: appNames.get(appId) ?? appId, channels });
|
|
234
|
+
}
|
|
235
|
+
return { bots };
|
|
236
|
+
}
|
|
237
|
+
/** 某通道的话题列表(session-store 聚合:跨 userId 合并、同 sessionId 去重取最新)。标题 = 首条消息摘要 */
|
|
238
|
+
export function chatTopics(appId, chatId) {
|
|
239
|
+
if (!ID_RE.test(appId) || !ID_RE.test(chatId))
|
|
240
|
+
return { topics: [] };
|
|
241
|
+
const store = readSessionStore(appId);
|
|
242
|
+
const prefix = `${chatId}:`;
|
|
243
|
+
const bySid = new Map();
|
|
244
|
+
for (const [key, st] of Object.entries(store)) {
|
|
245
|
+
if (!key.startsWith(prefix))
|
|
246
|
+
continue;
|
|
247
|
+
const userId = key.slice(prefix.length);
|
|
248
|
+
for (const t of st.sessions ?? []) {
|
|
249
|
+
if (!t?.sessionId)
|
|
250
|
+
continue;
|
|
251
|
+
const cur = bySid.get(t.sessionId);
|
|
252
|
+
if (cur) {
|
|
253
|
+
cur.users.add(userId);
|
|
254
|
+
if ((t.updatedAt ?? '') > cur.updatedAt) {
|
|
255
|
+
cur.updatedAt = t.updatedAt ?? '';
|
|
256
|
+
cur.title = t.summary ?? '';
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
bySid.set(t.sessionId, { title: t.summary ?? '', updatedAt: t.updatedAt ?? '', users: new Set([userId]) });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const topics = [...bySid.entries()]
|
|
265
|
+
.map(([sessionId, v]) => ({
|
|
266
|
+
sessionId,
|
|
267
|
+
title: v.title || sessionId.slice(0, 8), // 无摘要的历史数据退化为短 id
|
|
268
|
+
updatedAt: v.updatedAt,
|
|
269
|
+
users: [...v.users],
|
|
270
|
+
}))
|
|
271
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
272
|
+
return { topics };
|
|
273
|
+
}
|
|
274
|
+
/** 单日 JSONL → 任务序列(顺序行走;坏行跳过;孤儿 assistant/tool 不进时间线)。
|
|
275
|
+
* assistant 事件是流式分块(每块一行),顺序拼接即完整回复;reply 为空时回退 result 文本 */
|
|
276
|
+
function parseDayTasks(dir, date) {
|
|
277
|
+
let text;
|
|
278
|
+
try {
|
|
279
|
+
text = readFileSync(join(dir, `${date}.jsonl`), 'utf8');
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return [];
|
|
283
|
+
} // 缺天 = 空
|
|
284
|
+
const tasks = [];
|
|
285
|
+
let cur = null;
|
|
286
|
+
for (const line of text.split('\n')) {
|
|
287
|
+
if (!line.trim())
|
|
288
|
+
continue;
|
|
289
|
+
let ev;
|
|
290
|
+
try {
|
|
291
|
+
ev = JSON.parse(line);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
if (ev.kind === 'user') {
|
|
297
|
+
cur = {
|
|
298
|
+
date,
|
|
299
|
+
ts: ev.ts,
|
|
300
|
+
userId: ev.userId,
|
|
301
|
+
...(ev.workspace ? { workspace: ev.workspace } : {}),
|
|
302
|
+
...(ev.sessionId ? { sessionId: ev.sessionId } : {}),
|
|
303
|
+
prompt: ev.text,
|
|
304
|
+
reply: '',
|
|
305
|
+
tools: [],
|
|
306
|
+
};
|
|
307
|
+
tasks.push(cur);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (!cur)
|
|
311
|
+
continue;
|
|
312
|
+
if (ev.kind === 'assistant') {
|
|
313
|
+
cur.reply += ev.text;
|
|
314
|
+
}
|
|
315
|
+
else if (ev.kind === 'tool') {
|
|
316
|
+
if (ev.phase === 'start') {
|
|
317
|
+
cur.tools.push({ ts: ev.ts, tool: ev.tool });
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
// result 相位回填同工具的执行状态(倒序找最近一个未定状态的 start)
|
|
321
|
+
for (let i = cur.tools.length - 1; i >= 0; i--) {
|
|
322
|
+
if (cur.tools[i].tool === ev.tool && cur.tools[i].ok === undefined) {
|
|
323
|
+
cur.tools[i].ok = ev.ok;
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else if (ev.kind === 'result') {
|
|
330
|
+
cur.result = {
|
|
331
|
+
subtype: ev.subtype,
|
|
332
|
+
...(ev.producedFiles?.length ? { producedFiles: ev.producedFiles } : {}),
|
|
333
|
+
...(ev.turns !== undefined ? { turns: ev.turns } : {}),
|
|
334
|
+
};
|
|
335
|
+
if (ev.sessionId)
|
|
336
|
+
cur.sessionId = ev.sessionId; // 权威口径覆盖起点指针
|
|
337
|
+
if (!cur.reply && ev.text)
|
|
338
|
+
cur.reply = ev.text;
|
|
339
|
+
cur = null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return tasks;
|
|
343
|
+
}
|
|
344
|
+
function extractJsonString(line, key) {
|
|
345
|
+
const marker = `"${key}":"`;
|
|
346
|
+
const i = line.indexOf(marker);
|
|
347
|
+
if (i < 0)
|
|
348
|
+
return '';
|
|
349
|
+
const start = i + marker.length;
|
|
350
|
+
const end = line.indexOf('"', start);
|
|
351
|
+
return end < 0 ? '' : line.slice(start, end);
|
|
352
|
+
}
|
|
353
|
+
const indexCache = new Map(); // key = 通道目录
|
|
354
|
+
function fingerprintOf(dir, files) {
|
|
355
|
+
const parts = [];
|
|
356
|
+
for (const f of files) {
|
|
357
|
+
try {
|
|
358
|
+
const st = statSync(join(dir, f));
|
|
359
|
+
parts.push(`${f}:${st.mtimeMs}:${st.size}`);
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
parts.push(f);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return parts.join('|');
|
|
366
|
+
}
|
|
367
|
+
/** 建「会话 → 出现日期」索引:行级子串抽取(user=起点指针 / result=权威 id),不做全量 JSON.parse。
|
|
368
|
+
* 无天数上限(新→旧扫全部历史);仅文件数/字节数防呆。首次建后进程内缓存,文件指纹变化才重建 */
|
|
369
|
+
function buildTopicIndex(dir, files) {
|
|
370
|
+
const datesBySession = new Map();
|
|
371
|
+
let bytes = 0;
|
|
372
|
+
let scanned = 0;
|
|
373
|
+
let partial = false;
|
|
374
|
+
for (const f of files) {
|
|
375
|
+
if (scanned >= MAX_SCAN_FILES || bytes > MAX_SCAN_BYTES) {
|
|
376
|
+
partial = true;
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
let size = 0;
|
|
380
|
+
try {
|
|
381
|
+
size = statSync(join(dir, f)).size;
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
bytes += size;
|
|
387
|
+
scanned++;
|
|
388
|
+
let text;
|
|
389
|
+
try {
|
|
390
|
+
text = readFileSync(join(dir, f), 'utf8');
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const date = f.slice(0, 10);
|
|
396
|
+
let pending = ''; // 最近一条 user 行的起点指针(新话题首轮为空,由 result 行权威 id 补齐)
|
|
397
|
+
const reg = (sid) => {
|
|
398
|
+
if (!sid)
|
|
399
|
+
return;
|
|
400
|
+
let arr = datesBySession.get(sid);
|
|
401
|
+
if (!arr)
|
|
402
|
+
datesBySession.set(sid, arr = []);
|
|
403
|
+
if (!arr.includes(date))
|
|
404
|
+
arr.push(date);
|
|
405
|
+
};
|
|
406
|
+
for (const line of text.split('\n')) {
|
|
407
|
+
if (line.includes('"kind":"user"')) {
|
|
408
|
+
pending = extractJsonString(line, 'sessionId');
|
|
409
|
+
reg(pending);
|
|
410
|
+
}
|
|
411
|
+
else if (line.includes('"kind":"result"')) {
|
|
412
|
+
reg(extractJsonString(line, 'sessionId'));
|
|
413
|
+
reg(pending);
|
|
414
|
+
pending = '';
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
reg(pending); // 无 result 收尾(进程被杀)的任务同样归进索引
|
|
418
|
+
}
|
|
419
|
+
return { fingerprint: fingerprintOf(dir, files), datesBySession, partial };
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* 时间线查询。三种口径:
|
|
423
|
+
* - date 指定:单日视图(不过索引,直读该日文件)
|
|
424
|
+
* - session 指定:话题视图(索引定位该会话出现的日期,再跨天聚合归属任务)——任何历史话题都能看全
|
|
425
|
+
* - 都不传:最新往旧全量(防呆上限内),供「全部记录」浏览
|
|
426
|
+
* 返回任务序列(时间升序);truncated=达到单次返回上限,partial=索引被防呆上限截断。
|
|
427
|
+
*/
|
|
428
|
+
export function chatTimeline(appId, chatId, query) {
|
|
429
|
+
const empty = { tasks: [], truncated: false, partial: false, scanDays: 0 };
|
|
430
|
+
if (!ID_RE.test(appId) || !ID_RE.test(chatId))
|
|
431
|
+
return empty;
|
|
432
|
+
const dir = join(TRANSCRIPTS_DIR, appId, chatId);
|
|
433
|
+
const files = listDateFiles(dir);
|
|
434
|
+
if (files.length === 0)
|
|
435
|
+
return empty;
|
|
436
|
+
const limit = Math.min(Math.max(query.limit ?? DEFAULT_TASK_LIMIT, 1), 1000);
|
|
437
|
+
let scanDates;
|
|
438
|
+
let partial = false;
|
|
439
|
+
if (query.date && DATE_RE.test(query.date)) {
|
|
440
|
+
scanDates = [query.date];
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
let index = indexCache.get(dir);
|
|
444
|
+
const fingerprint = fingerprintOf(dir, files);
|
|
445
|
+
if (!index || index.fingerprint !== fingerprint) {
|
|
446
|
+
index = buildTopicIndex(dir, files);
|
|
447
|
+
indexCache.set(dir, index);
|
|
448
|
+
}
|
|
449
|
+
partial = index.partial;
|
|
450
|
+
scanDates = query.session
|
|
451
|
+
? (index.datesBySession.get(query.session) ?? [])
|
|
452
|
+
: files.map((f) => f.slice(0, 10));
|
|
453
|
+
}
|
|
454
|
+
const tasks = [];
|
|
455
|
+
let truncated = false;
|
|
456
|
+
for (const date of scanDates) {
|
|
457
|
+
if (!DATE_RE.test(date))
|
|
458
|
+
continue;
|
|
459
|
+
for (const t of parseDayTasks(dir, date)) {
|
|
460
|
+
if (query.session && t.sessionId !== query.session)
|
|
461
|
+
continue;
|
|
462
|
+
if (query.user && t.userId !== query.user)
|
|
463
|
+
continue;
|
|
464
|
+
tasks.push(t);
|
|
465
|
+
if (tasks.length >= limit) {
|
|
466
|
+
truncated = true;
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (truncated)
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
return { tasks, truncated, partial, scanDays: scanDates.length };
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=chats-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chats-api.js","sourceRoot":"","sources":["../../src/web/chats-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface LogFileEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
size: number;
|
|
4
|
+
mtime: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function listLogFiles(configPath: string): {
|
|
7
|
+
dir: string;
|
|
8
|
+
files: LogFileEntry[];
|
|
9
|
+
};
|
|
10
|
+
export interface LogTail {
|
|
11
|
+
name: string;
|
|
12
|
+
size: number;
|
|
13
|
+
/** true = 文件过大只读了末尾窗口,首行可能不完整(前端丢弃首行残缺即可) */
|
|
14
|
+
truncated: boolean;
|
|
15
|
+
lines: string[];
|
|
16
|
+
}
|
|
17
|
+
/** 取尾部 maxLines 行(默认 500,上限 5000) */
|
|
18
|
+
export declare function tailLogFile(configPath: string, name: string, maxLines: number): LogTail | {
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
21
|
+
export interface LogRangeTail {
|
|
22
|
+
from: string;
|
|
23
|
+
to: string;
|
|
24
|
+
/** 实际并入的日志文件(升序 = 时间序),前端可提示覆盖了哪些天 */
|
|
25
|
+
files: string[];
|
|
26
|
+
/** true = 达到总量上限或某文件只读了末尾窗口 */
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
lines: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 日期范围聚合尾读:from~to(含两端)每天的 bridge-YYYY-MM-DD.log 依时间序合并。
|
|
32
|
+
* 每文件最多 RANGE_PER_FILE_LINES 行(防止单日巨日志吃光配额),总量再按 maxLines 截尾。
|
|
33
|
+
* 单日文件过大只读末尾窗口时同样标记 truncated。
|
|
34
|
+
*/
|
|
35
|
+
export declare function tailLogRange(configPath: string, from: string, to: string, maxLines: number): LogRangeTail | {
|
|
36
|
+
error: string;
|
|
37
|
+
};
|