sessix-server 0.2.8 → 0.2.9
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/dist/index.js +63 -23
- package/dist/server.js +63 -23
- package/package.json +10 -1
- package/dist/approval/ApprovalProxy.d.ts +0 -86
- package/dist/approval/ApprovalProxy.d.ts.map +0 -1
- package/dist/approval/ApprovalProxy.js +0 -363
- package/dist/approval/ApprovalProxy.js.map +0 -1
- package/dist/hooks/HookInstaller.d.ts +0 -55
- package/dist/hooks/HookInstaller.d.ts.map +0 -1
- package/dist/hooks/HookInstaller.js +0 -215
- package/dist/hooks/HookInstaller.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mdns/MdnsService.d.ts +0 -36
- package/dist/mdns/MdnsService.d.ts.map +0 -1
- package/dist/mdns/MdnsService.js +0 -66
- package/dist/mdns/MdnsService.js.map +0 -1
- package/dist/notification/ActivityPushChannel.d.ts +0 -54
- package/dist/notification/ActivityPushChannel.d.ts.map +0 -1
- package/dist/notification/ActivityPushChannel.js +0 -235
- package/dist/notification/ActivityPushChannel.js.map +0 -1
- package/dist/notification/ExpoNotificationChannel.d.ts +0 -17
- package/dist/notification/ExpoNotificationChannel.d.ts.map +0 -1
- package/dist/notification/ExpoNotificationChannel.js +0 -57
- package/dist/notification/ExpoNotificationChannel.js.map +0 -1
- package/dist/notification/MacNotificationChannel.d.ts +0 -22
- package/dist/notification/MacNotificationChannel.d.ts.map +0 -1
- package/dist/notification/MacNotificationChannel.js +0 -33
- package/dist/notification/MacNotificationChannel.js.map +0 -1
- package/dist/notification/NotificationService.d.ts +0 -50
- package/dist/notification/NotificationService.d.ts.map +0 -1
- package/dist/notification/NotificationService.js +0 -177
- package/dist/notification/NotificationService.js.map +0 -1
- package/dist/providers/ExecutionProvider.d.ts +0 -60
- package/dist/providers/ExecutionProvider.d.ts.map +0 -1
- package/dist/providers/ExecutionProvider.js +0 -3
- package/dist/providers/ExecutionProvider.js.map +0 -1
- package/dist/providers/ProcessProvider.d.ts +0 -117
- package/dist/providers/ProcessProvider.d.ts.map +0 -1
- package/dist/providers/ProcessProvider.js +0 -507
- package/dist/providers/ProcessProvider.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/session/ProjectReader.d.ts +0 -44
- package/dist/session/ProjectReader.d.ts.map +0 -1
- package/dist/session/ProjectReader.js +0 -471
- package/dist/session/ProjectReader.js.map +0 -1
- package/dist/session/SessionFileWatcher.d.ts +0 -35
- package/dist/session/SessionFileWatcher.d.ts.map +0 -1
- package/dist/session/SessionFileWatcher.js +0 -207
- package/dist/session/SessionFileWatcher.js.map +0 -1
- package/dist/session/SessionManager.d.ts +0 -114
- package/dist/session/SessionManager.d.ts.map +0 -1
- package/dist/session/SessionManager.js +0 -356
- package/dist/session/SessionManager.js.map +0 -1
- package/dist/ws/WsBridge.d.ts +0 -55
- package/dist/ws/WsBridge.d.ts.map +0 -1
- package/dist/ws/WsBridge.js +0 -220
- package/dist/ws/WsBridge.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -3031,16 +3031,23 @@ async function getHistoricalSessions(projectPath) {
|
|
|
3031
3031
|
const entries = await (0, import_promises3.readdir)(projectDir, { withFileTypes: true });
|
|
3032
3032
|
const jsonlFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
3033
3033
|
const mtimeMap = /* @__PURE__ */ new Map();
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3034
|
+
await Promise.all(
|
|
3035
|
+
jsonlFiles.map(async (entry) => {
|
|
3036
|
+
const sessionId = entry.name.slice(0, -6);
|
|
3037
|
+
const filePath = (0, import_path.join)(projectDir, entry.name);
|
|
3038
|
+
try {
|
|
3039
|
+
const contentTs = await extractLastTimestamp(filePath);
|
|
3040
|
+
if (contentTs) {
|
|
3041
|
+
mtimeMap.set(sessionId, contentTs);
|
|
3042
|
+
} else {
|
|
3043
|
+
const fileStat = await (0, import_promises3.stat)(filePath);
|
|
3044
|
+
mtimeMap.set(sessionId, fileStat.mtimeMs);
|
|
3045
|
+
}
|
|
3046
|
+
} catch {
|
|
3047
|
+
mtimeMap.set(sessionId, 0);
|
|
3048
|
+
}
|
|
3049
|
+
})
|
|
3050
|
+
);
|
|
3044
3051
|
const uuidDirs = entries.filter(
|
|
3045
3052
|
(e) => e.isDirectory() && UUID_RE.test(e.name) && !mtimeMap.has(e.name)
|
|
3046
3053
|
);
|
|
@@ -3191,6 +3198,32 @@ async function getSessionHistory(projectPath, sessionId) {
|
|
|
3191
3198
|
};
|
|
3192
3199
|
}
|
|
3193
3200
|
}
|
|
3201
|
+
async function extractLastTimestamp(filePath) {
|
|
3202
|
+
let fileHandle;
|
|
3203
|
+
try {
|
|
3204
|
+
fileHandle = await (0, import_promises3.open)(filePath, "r");
|
|
3205
|
+
const fileStat = await fileHandle.stat();
|
|
3206
|
+
const readSize = Math.min(fileStat.size, 8192);
|
|
3207
|
+
const buffer = Buffer.alloc(readSize);
|
|
3208
|
+
await fileHandle.read(buffer, 0, readSize, fileStat.size - readSize);
|
|
3209
|
+
const tail = buffer.toString("utf-8");
|
|
3210
|
+
const lines = tail.split("\n").filter((l) => l.trim());
|
|
3211
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
3212
|
+
try {
|
|
3213
|
+
const obj = JSON.parse(lines[i]);
|
|
3214
|
+
if (obj.timestamp) {
|
|
3215
|
+
const ts = new Date(obj.timestamp).getTime();
|
|
3216
|
+
if (!isNaN(ts)) return ts;
|
|
3217
|
+
}
|
|
3218
|
+
} catch {
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
} catch {
|
|
3222
|
+
} finally {
|
|
3223
|
+
await fileHandle?.close();
|
|
3224
|
+
}
|
|
3225
|
+
return void 0;
|
|
3226
|
+
}
|
|
3194
3227
|
async function extractFirstPrompt(filePath) {
|
|
3195
3228
|
let fileHandle;
|
|
3196
3229
|
try {
|
|
@@ -3259,17 +3292,24 @@ async function countJsonlFilesWithMtime(dirPath) {
|
|
|
3259
3292
|
(e) => e.isDirectory() && UUID_RE.test(e.name) && !jsonlNames.has(e.name)
|
|
3260
3293
|
);
|
|
3261
3294
|
let latestMtime = 0;
|
|
3262
|
-
const
|
|
3263
|
-
|
|
3264
|
-
...
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
}
|
|
3272
|
-
|
|
3295
|
+
const jsonlEntries = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
3296
|
+
await Promise.all([
|
|
3297
|
+
...jsonlEntries.map(async (entry) => {
|
|
3298
|
+
try {
|
|
3299
|
+
const contentTs = await extractLastTimestamp((0, import_path.join)(dirPath, entry.name));
|
|
3300
|
+
const ts = contentTs ?? (await (0, import_promises3.stat)((0, import_path.join)(dirPath, entry.name))).mtimeMs;
|
|
3301
|
+
if (ts > latestMtime) latestMtime = ts;
|
|
3302
|
+
} catch {
|
|
3303
|
+
}
|
|
3304
|
+
}),
|
|
3305
|
+
...uuidDirs.map(async (entry) => {
|
|
3306
|
+
try {
|
|
3307
|
+
const fileStat = await (0, import_promises3.stat)((0, import_path.join)(dirPath, entry.name));
|
|
3308
|
+
if (fileStat.mtimeMs > latestMtime) latestMtime = fileStat.mtimeMs;
|
|
3309
|
+
} catch {
|
|
3310
|
+
}
|
|
3311
|
+
})
|
|
3312
|
+
]);
|
|
3273
3313
|
return { count: jsonlNames.size + uuidDirs.length, latestMtime };
|
|
3274
3314
|
} catch {
|
|
3275
3315
|
return { count: 0, latestMtime: 0 };
|
|
@@ -3903,9 +3943,9 @@ async function start(opts = {}) {
|
|
|
3903
3943
|
}
|
|
3904
3944
|
case "terminal_exec": {
|
|
3905
3945
|
const activeSession = sessionManager.getActiveSessions().find((s) => s.id === event.sessionId);
|
|
3906
|
-
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId);
|
|
3946
|
+
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId) ?? event.projectPath;
|
|
3907
3947
|
if (!cwd) {
|
|
3908
|
-
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message:
|
|
3948
|
+
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message: `Session not found (id: ${event.sessionId.slice(0, 8)}\u2026)`, sessionId: event.sessionId });
|
|
3909
3949
|
break;
|
|
3910
3950
|
}
|
|
3911
3951
|
terminalExecutor.exec(event.sessionId, event.command, cwd);
|
package/dist/server.js
CHANGED
|
@@ -3037,16 +3037,23 @@ async function getHistoricalSessions(projectPath) {
|
|
|
3037
3037
|
const entries = await (0, import_promises3.readdir)(projectDir, { withFileTypes: true });
|
|
3038
3038
|
const jsonlFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
3039
3039
|
const mtimeMap = /* @__PURE__ */ new Map();
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3040
|
+
await Promise.all(
|
|
3041
|
+
jsonlFiles.map(async (entry) => {
|
|
3042
|
+
const sessionId = entry.name.slice(0, -6);
|
|
3043
|
+
const filePath = (0, import_path.join)(projectDir, entry.name);
|
|
3044
|
+
try {
|
|
3045
|
+
const contentTs = await extractLastTimestamp(filePath);
|
|
3046
|
+
if (contentTs) {
|
|
3047
|
+
mtimeMap.set(sessionId, contentTs);
|
|
3048
|
+
} else {
|
|
3049
|
+
const fileStat = await (0, import_promises3.stat)(filePath);
|
|
3050
|
+
mtimeMap.set(sessionId, fileStat.mtimeMs);
|
|
3051
|
+
}
|
|
3052
|
+
} catch {
|
|
3053
|
+
mtimeMap.set(sessionId, 0);
|
|
3054
|
+
}
|
|
3055
|
+
})
|
|
3056
|
+
);
|
|
3050
3057
|
const uuidDirs = entries.filter(
|
|
3051
3058
|
(e) => e.isDirectory() && UUID_RE.test(e.name) && !mtimeMap.has(e.name)
|
|
3052
3059
|
);
|
|
@@ -3197,6 +3204,32 @@ async function getSessionHistory(projectPath, sessionId) {
|
|
|
3197
3204
|
};
|
|
3198
3205
|
}
|
|
3199
3206
|
}
|
|
3207
|
+
async function extractLastTimestamp(filePath) {
|
|
3208
|
+
let fileHandle;
|
|
3209
|
+
try {
|
|
3210
|
+
fileHandle = await (0, import_promises3.open)(filePath, "r");
|
|
3211
|
+
const fileStat = await fileHandle.stat();
|
|
3212
|
+
const readSize = Math.min(fileStat.size, 8192);
|
|
3213
|
+
const buffer = Buffer.alloc(readSize);
|
|
3214
|
+
await fileHandle.read(buffer, 0, readSize, fileStat.size - readSize);
|
|
3215
|
+
const tail = buffer.toString("utf-8");
|
|
3216
|
+
const lines = tail.split("\n").filter((l) => l.trim());
|
|
3217
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
3218
|
+
try {
|
|
3219
|
+
const obj = JSON.parse(lines[i]);
|
|
3220
|
+
if (obj.timestamp) {
|
|
3221
|
+
const ts = new Date(obj.timestamp).getTime();
|
|
3222
|
+
if (!isNaN(ts)) return ts;
|
|
3223
|
+
}
|
|
3224
|
+
} catch {
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
} catch {
|
|
3228
|
+
} finally {
|
|
3229
|
+
await fileHandle?.close();
|
|
3230
|
+
}
|
|
3231
|
+
return void 0;
|
|
3232
|
+
}
|
|
3200
3233
|
async function extractFirstPrompt(filePath) {
|
|
3201
3234
|
let fileHandle;
|
|
3202
3235
|
try {
|
|
@@ -3265,17 +3298,24 @@ async function countJsonlFilesWithMtime(dirPath) {
|
|
|
3265
3298
|
(e) => e.isDirectory() && UUID_RE.test(e.name) && !jsonlNames.has(e.name)
|
|
3266
3299
|
);
|
|
3267
3300
|
let latestMtime = 0;
|
|
3268
|
-
const
|
|
3269
|
-
|
|
3270
|
-
...
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
}
|
|
3278
|
-
|
|
3301
|
+
const jsonlEntries = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
3302
|
+
await Promise.all([
|
|
3303
|
+
...jsonlEntries.map(async (entry) => {
|
|
3304
|
+
try {
|
|
3305
|
+
const contentTs = await extractLastTimestamp((0, import_path.join)(dirPath, entry.name));
|
|
3306
|
+
const ts = contentTs ?? (await (0, import_promises3.stat)((0, import_path.join)(dirPath, entry.name))).mtimeMs;
|
|
3307
|
+
if (ts > latestMtime) latestMtime = ts;
|
|
3308
|
+
} catch {
|
|
3309
|
+
}
|
|
3310
|
+
}),
|
|
3311
|
+
...uuidDirs.map(async (entry) => {
|
|
3312
|
+
try {
|
|
3313
|
+
const fileStat = await (0, import_promises3.stat)((0, import_path.join)(dirPath, entry.name));
|
|
3314
|
+
if (fileStat.mtimeMs > latestMtime) latestMtime = fileStat.mtimeMs;
|
|
3315
|
+
} catch {
|
|
3316
|
+
}
|
|
3317
|
+
})
|
|
3318
|
+
]);
|
|
3279
3319
|
return { count: jsonlNames.size + uuidDirs.length, latestMtime };
|
|
3280
3320
|
} catch {
|
|
3281
3321
|
return { count: 0, latestMtime: 0 };
|
|
@@ -3909,9 +3949,9 @@ async function start(opts = {}) {
|
|
|
3909
3949
|
}
|
|
3910
3950
|
case "terminal_exec": {
|
|
3911
3951
|
const activeSession = sessionManager.getActiveSessions().find((s) => s.id === event.sessionId);
|
|
3912
|
-
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId);
|
|
3952
|
+
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId) ?? event.projectPath;
|
|
3913
3953
|
if (!cwd) {
|
|
3914
|
-
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message:
|
|
3954
|
+
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message: `Session not found (id: ${event.sessionId.slice(0, 8)}\u2026)`, sessionId: event.sessionId });
|
|
3915
3955
|
break;
|
|
3916
3956
|
}
|
|
3917
3957
|
terminalExecutor.exec(event.sessionId, event.command, cwd);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sessix-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"bin": {
|
|
5
5
|
"sessix-server": "./dist/index.js"
|
|
6
6
|
},
|
|
@@ -17,6 +17,15 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/ampere1988/Sessix-Server.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/ampere1988/Sessix-Server#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/ampere1988/Sessix-Server/issues"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
20
29
|
"engines": {
|
|
21
30
|
"node": ">=22.0.0"
|
|
22
31
|
},
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { ApprovalRequest, ApprovalDecision } from '@sessix/shared';
|
|
2
|
-
/** ApprovalProxy 配置 */
|
|
3
|
-
interface ApprovalProxyOptions {
|
|
4
|
-
port: number;
|
|
5
|
-
token: string;
|
|
6
|
-
}
|
|
7
|
-
/** 外部注入的连接信息回调(用于 /health 端点) */
|
|
8
|
-
interface StatusInfo {
|
|
9
|
-
connections: number;
|
|
10
|
-
activeSessions: number;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* 审批代理 HTTP 服务
|
|
14
|
-
*
|
|
15
|
-
* 接收 Claude Code hook 发来的工具审批请求,通过长轮询机制
|
|
16
|
-
* hold 住响应,等待手机端用户做出审批决策后再返回。
|
|
17
|
-
*/
|
|
18
|
-
export declare class ApprovalProxy {
|
|
19
|
-
private server;
|
|
20
|
-
private token;
|
|
21
|
-
private port;
|
|
22
|
-
private settingsPath;
|
|
23
|
-
/** 待处理的审批请求:requestId -> { resolve, timer, request } */
|
|
24
|
-
private pendingApprovals;
|
|
25
|
-
/** 审批请求回调(通知外部推送到手机) */
|
|
26
|
-
private approvalRequestCallbacks;
|
|
27
|
-
/** 获取状态信息的回调(由外部注入) */
|
|
28
|
-
private statusInfoProvider;
|
|
29
|
-
constructor(options: ApprovalProxyOptions);
|
|
30
|
-
/**
|
|
31
|
-
* 异步工厂方法:等待端口监听成功后 resolve,端口占用等错误时 reject。
|
|
32
|
-
*/
|
|
33
|
-
static create(options: ApprovalProxyOptions): Promise<ApprovalProxy>;
|
|
34
|
-
/** 注册审批请求回调(当有新的审批请求时触发) */
|
|
35
|
-
onApprovalRequest(callback: (request: ApprovalRequest) => void): void;
|
|
36
|
-
/** 设置状态信息提供者(用于 /health 端点) */
|
|
37
|
-
setStatusInfoProvider(provider: () => StatusInfo): void;
|
|
38
|
-
/**
|
|
39
|
-
* 注入审批结果
|
|
40
|
-
*
|
|
41
|
-
* 从 pendingApprovals 中取出对应请求,resolve promise,
|
|
42
|
-
* 让长轮询的 HTTP 响应返回审批结果给 Claude Code hook。
|
|
43
|
-
*/
|
|
44
|
-
resolveApproval(requestId: string, decision: ApprovalDecision): boolean;
|
|
45
|
-
/** 获取当前待处理的审批数量 */
|
|
46
|
-
getPendingCount(): number;
|
|
47
|
-
/** 检查指定审批请求是否仍在等待用户决策 */
|
|
48
|
-
isPending(requestId: string): boolean;
|
|
49
|
-
/** 检查工具是否已在 settings.json permissions.allow 中(检查项目级和全局) */
|
|
50
|
-
private isToolInClaudeSettings;
|
|
51
|
-
/** 将工具写入 settings.json permissions.allow(项目级或全局) */
|
|
52
|
-
addToClaudeSettings(projectPath: string | undefined, toolName: string): void;
|
|
53
|
-
/** 获取指定会话的所有 pending approval requests(用于 subscribe 重发) */
|
|
54
|
-
getPendingRequestsForSession(sessionId: string): ApprovalRequest[];
|
|
55
|
-
/**
|
|
56
|
-
* 批量允许所有待处理的审批请求(手机端断线时调用)
|
|
57
|
-
*/
|
|
58
|
-
approveAll(reason?: string): void;
|
|
59
|
-
/** 优雅关闭 HTTP 服务 */
|
|
60
|
-
close(): Promise<void>;
|
|
61
|
-
/** 路由请求 */
|
|
62
|
-
private handleRequest;
|
|
63
|
-
/**
|
|
64
|
-
* 核心端点:处理 Claude Code hook 的审批请求
|
|
65
|
-
*
|
|
66
|
-
* 长轮询实现:
|
|
67
|
-
* 1. 解析请求 body
|
|
68
|
-
* 2. 创建 ApprovalRequest 对象
|
|
69
|
-
* 3. 通知外部(推到手机)
|
|
70
|
-
* 4. 创建 Promise 并 hold 住 response
|
|
71
|
-
* 5. 等待 resolveApproval() 被调用或超时
|
|
72
|
-
*/
|
|
73
|
-
private handleApprovalHook;
|
|
74
|
-
/** 健康检查端点 */
|
|
75
|
-
private handleHealth;
|
|
76
|
-
/** 返回连接 token(仅本机访问) */
|
|
77
|
-
private handleToken;
|
|
78
|
-
/** 通知所有注册的审批请求回调 */
|
|
79
|
-
private notifyApprovalRequest;
|
|
80
|
-
/** 手动解析请求的 JSON body(限制最大 1MB 防止滥用) */
|
|
81
|
-
private parseJsonBody;
|
|
82
|
-
/** 发送 JSON 响应的辅助方法 */
|
|
83
|
-
private sendJson;
|
|
84
|
-
}
|
|
85
|
-
export {};
|
|
86
|
-
//# sourceMappingURL=ApprovalProxy.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ApprovalProxy.d.ts","sourceRoot":"","sources":["../../src/approval/ApprovalProxy.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEvE,uBAAuB;AACvB,UAAU,oBAAoB;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,iCAAiC;AACjC,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,YAAY,CAAsD;IAE1E,wDAAwD;IACxD,OAAO,CAAC,gBAAgB,CAIpB;IAEJ,wBAAwB;IACxB,OAAO,CAAC,wBAAwB,CAAgD;IAEhF,uBAAuB;IACvB,OAAO,CAAC,kBAAkB,CAAkC;gBAEhD,OAAO,EAAE,oBAAoB;IAazC;;OAEG;WACU,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IAe1E,4BAA4B;IAC5B,iBAAiB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAIrE,+BAA+B;IAC/B,qBAAqB,CAAC,QAAQ,EAAE,MAAM,UAAU,GAAG,IAAI;IAIvD;;;;;OAKG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO;IAkBvE,mBAAmB;IACnB,eAAe,IAAI,MAAM;IAIzB,yBAAyB;IACzB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,sBAAsB;IAsB9B,oDAAoD;IACpD,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwC5E,2DAA2D;IAC3D,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE;IAUlE;;OAEG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAUjC,mBAAmB;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BtB,WAAW;IACX,OAAO,CAAC,aAAa;IA2BrB;;;;;;;;;OASG;YACW,kBAAkB;IAyDhC,aAAa;IACb,OAAO,CAAC,YAAY;IASpB,wBAAwB;IACxB,OAAO,CAAC,WAAW;IAenB,oBAAoB;IACpB,OAAO,CAAC,qBAAqB;IAU7B,uCAAuC;IACvC,OAAO,CAAC,aAAa;IAgCrB,sBAAsB;IACtB,OAAO,CAAC,QAAQ;CAQjB"}
|