dsh-reference-session-collector 0.2.3 → 0.2.5
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/dsh.plugin.json +2 -2
- package/lib/index.d.ts +32 -1
- package/lib/index.js +27 -1
- package/package.json +2 -2
- package/src/index.ts +51 -1
package/dsh.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-reference-session-collector",
|
|
3
3
|
"name": "dsh-reference-session-collector",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.5",
|
|
5
5
|
"description": {
|
|
6
6
|
"en": "Session reference projector (DRS): read-only scan of ~/.dsh/sessions logs, decoded into a private SQLite (segments/replaces/FTS5) with surface flags, recall-pair accounting and a Chinese-capable search face, served via /api/dsh-reference-session-collector. Never writes session files.",
|
|
7
7
|
"zh": "会话原文投影同步器(DRS):只读扫描 ~/.dsh/sessions 会话日志,解码后投影进自有 SQLite(segments/replaces/FTS5),经 /api/dsh-reference-session-collector 提供 surface 标记、召回对账与中文可用的内容检索面。绝不写会话文件。"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"engines": {
|
|
16
|
-
"dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4"
|
|
16
|
+
"dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.1-rc.5"
|
|
17
17
|
},
|
|
18
18
|
"components": {
|
|
19
19
|
"host": "lib/index.js",
|
package/lib/index.d.ts
CHANGED
|
@@ -695,6 +695,37 @@ interface DrsHandlerDeps {
|
|
|
695
695
|
* 未知 op / 缺参 → 400(不留空壳)。
|
|
696
696
|
*/
|
|
697
697
|
declare function handleDrsRequest(deps: DrsHandlerDeps, req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
698
|
+
/**
|
|
699
|
+
* 跨插件只读门面的返回形状:与 HTTP 面 `handleDrsRequest` 同字段
|
|
700
|
+
* (消费方已按那套映射写)。
|
|
701
|
+
*/
|
|
702
|
+
interface DrsReadFacade {
|
|
703
|
+
/** 会话汇总分页(按 last_time_ms 降序)。 */
|
|
704
|
+
listSessions: (offset?: number, limit?: number) => {
|
|
705
|
+
total: number;
|
|
706
|
+
rows: SessionRow[];
|
|
707
|
+
};
|
|
708
|
+
/** 单会话明细;opts.tail 缺省即全量(消费方的重建事实源臂依赖这点)。 */
|
|
709
|
+
sessionDetail: (sessionId: string, opts?: SessionDetailOptions) => {
|
|
710
|
+
session: SessionRow | undefined;
|
|
711
|
+
rows: unknown[];
|
|
712
|
+
};
|
|
713
|
+
/** 全文检索(脱敏臂由 opts.redact 控制)。 */
|
|
714
|
+
search: (query: string, opts?: {
|
|
715
|
+
session?: string;
|
|
716
|
+
limit?: number;
|
|
717
|
+
redact?: boolean;
|
|
718
|
+
}) => {
|
|
719
|
+
query: string;
|
|
720
|
+
match: string;
|
|
721
|
+
hits: Record<string, unknown>[];
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* 取跨插件只读门面。库尚未就绪(apply 延迟初始化未完成)或已 dispose 时返回
|
|
726
|
+
* **undefined**,不抛——让消费方自己决定降级口径(报不可用或回退 HTTP)。
|
|
727
|
+
*/
|
|
728
|
+
declare function drsReadFacade(): DrsReadFacade | undefined;
|
|
698
729
|
/**
|
|
699
730
|
* 插件主体:apply() 立即返回,重活(开库/建 sync/注册路由)推迟到 setImmediate。
|
|
700
731
|
* 宿主插件装载串行同步——apply 不返回则整列插件都装不上,前端一直 Loading plugins…。
|
|
@@ -702,4 +733,4 @@ declare function handleDrsRequest(deps: DrsHandlerDeps, req: IncomingMessage, re
|
|
|
702
733
|
*/
|
|
703
734
|
declare function apply(ctx: Context): void;
|
|
704
735
|
//#endregion
|
|
705
|
-
export { BOOT_SYNC_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DISCOVERY_LIMIT, DRS_API_PATH, type DecodedEvent, DrsHandlerDeps, type ExactCounter, type GroupedSearchHit, type GroupedSearchRequest, INJECTED_BLOCK_TAGS, LEDGER_LRU_CAP, LedgerCache, PROJECTION_SCHEMA_VERSION, type ProjectionOptions, type ProjectionPort, type ProjectionReplace, type ProjectionSegment, type ProjectionStore, ProjectionSync, type QueryContext, SYNC_INTERVAL_ENV, type SessionLogRead, type SessionProjection, type SessionRow, type SessionSummary, type SyncResult, type SyncStorePort, apply, buildSearchSnippet, classifySessionHeader, createQueryContext, createStorePort, decodeSessionLogBytes, decodeSessionLogFile, discoverSessionLogs, extractSearchEventText, extractTitleFromEvents, generationLogFilename, handleDrsRequest, inject, listSessions, openProjectionStore, projectSessionEvents, readArchivedSessionIds, readSessionGenerations, recallReport, reloadSummaries, resolveDshHome, resolveExactCounter, resolveIndexDir, resolveSyncIntervalMs, sanitizeFtsQuery, search, searchGrouped, segmentForIndex, segmentQueryTerm, sessionDetail, startIntervalSync, status, stripInjectedBlocks, surfaceLedger };
|
|
736
|
+
export { BOOT_SYNC_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DISCOVERY_LIMIT, DRS_API_PATH, type DecodedEvent, DrsHandlerDeps, DrsReadFacade, type ExactCounter, type GroupedSearchHit, type GroupedSearchRequest, INJECTED_BLOCK_TAGS, LEDGER_LRU_CAP, LedgerCache, PROJECTION_SCHEMA_VERSION, type ProjectionOptions, type ProjectionPort, type ProjectionReplace, type ProjectionSegment, type ProjectionStore, ProjectionSync, type QueryContext, SYNC_INTERVAL_ENV, type SessionLogRead, type SessionProjection, type SessionRow, type SessionSummary, type SyncResult, type SyncStorePort, apply, buildSearchSnippet, classifySessionHeader, createQueryContext, createStorePort, decodeSessionLogBytes, decodeSessionLogFile, discoverSessionLogs, drsReadFacade, extractSearchEventText, extractTitleFromEvents, generationLogFilename, handleDrsRequest, inject, listSessions, openProjectionStore, projectSessionEvents, readArchivedSessionIds, readSessionGenerations, recallReport, reloadSummaries, resolveDshHome, resolveExactCounter, resolveIndexDir, resolveSyncIntervalMs, sanitizeFtsQuery, search, searchGrouped, segmentForIndex, segmentQueryTerm, sessionDetail, startIntervalSync, status, stripInjectedBlocks, surfaceLedger };
|
package/lib/index.js
CHANGED
|
@@ -2437,6 +2437,29 @@ function safeReadService(ctx, name) {
|
|
|
2437
2437
|
}
|
|
2438
2438
|
}
|
|
2439
2439
|
/**
|
|
2440
|
+
* 活 QueryContext(在 apply 的 setImmediate 臂赋值,dispose 时清空)。
|
|
2441
|
+
*
|
|
2442
|
+
* 为何要模块级一份:消费方从自己包作用域 `import` 本包时,在 **hoisted 布局**
|
|
2443
|
+
* (desktop profile 就是 `nodeLinker: hoisted`)下解析到同一物理 lib/index.js,
|
|
2444
|
+
* Node 的 ESM 缓存会返回**同一个模块实例**,因此读到的是这里已赋值的活库。
|
|
2445
|
+
* 若某个部署是 pnpm 隔离布局且两包各有链接副本,两侧会是不同实例、本变量在消费侧
|
|
2446
|
+
* 为 undefined——门面会诚实返回 undefined,消费方回退自开库,不会读到错数据。
|
|
2447
|
+
*/
|
|
2448
|
+
let liveQuery;
|
|
2449
|
+
/**
|
|
2450
|
+
* 取跨插件只读门面。库尚未就绪(apply 延迟初始化未完成)或已 dispose 时返回
|
|
2451
|
+
* **undefined**,不抛——让消费方自己决定降级口径(报不可用或回退 HTTP)。
|
|
2452
|
+
*/
|
|
2453
|
+
function drsReadFacade() {
|
|
2454
|
+
const ctx = liveQuery;
|
|
2455
|
+
if (ctx === void 0) return void 0;
|
|
2456
|
+
return {
|
|
2457
|
+
listSessions: (offset, limit) => listSessions(ctx, offset, limit),
|
|
2458
|
+
sessionDetail: (sessionId, opts) => sessionDetail(ctx, sessionId, opts),
|
|
2459
|
+
search: (query, opts) => search(ctx, query, opts)
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2440
2463
|
* 插件主体:apply() 立即返回,重活(开库/建 sync/注册路由)推迟到 setImmediate。
|
|
2441
2464
|
* 宿主插件装载串行同步——apply 不返回则整列插件都装不上,前端一直 Loading plugins…。
|
|
2442
2465
|
* @param ctx - host 插件上下文(webServer 声明注入;webStartup/webRuntime 回退臂)。
|
|
@@ -2493,12 +2516,15 @@ function apply(ctx) {
|
|
|
2493
2516
|
if (bootTimer !== void 0) clearTimeout(bootTimer);
|
|
2494
2517
|
disposeInterval();
|
|
2495
2518
|
store?.close();
|
|
2519
|
+
liveQuery = void 0;
|
|
2520
|
+
query = void 0;
|
|
2496
2521
|
};
|
|
2497
2522
|
}, "dsh-reference-session-collector: projection lifecycle");
|
|
2498
2523
|
setImmediate(() => {
|
|
2499
2524
|
try {
|
|
2500
2525
|
store = openProjectionStore(resolveIndexDir());
|
|
2501
2526
|
query = createQueryContext(store);
|
|
2527
|
+
liveQuery = query;
|
|
2502
2528
|
sync = new ProjectionSync({
|
|
2503
2529
|
store: createStorePort(store),
|
|
2504
2530
|
project: (events, options) => projectSessionEvents(events, {
|
|
@@ -2542,4 +2568,4 @@ function apply(ctx) {
|
|
|
2542
2568
|
});
|
|
2543
2569
|
}
|
|
2544
2570
|
//#endregion
|
|
2545
|
-
export { BOOT_SYNC_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DISCOVERY_LIMIT, DRS_API_PATH, INJECTED_BLOCK_TAGS, LEDGER_LRU_CAP, LedgerCache, PROJECTION_SCHEMA_VERSION, ProjectionSync, SYNC_INTERVAL_ENV, apply, buildSearchSnippet, classifySessionHeader, createQueryContext, createStorePort, decodeSessionLogBytes, decodeSessionLogFile, discoverSessionLogs, extractSearchEventText, extractTitleFromEvents, generationLogFilename, handleDrsRequest, inject, listSessions, openProjectionStore, projectSessionEvents, readArchivedSessionIds, readSessionGenerations, recallReport, reloadSummaries, resolveDshHome, resolveExactCounter, resolveIndexDir, resolveSyncIntervalMs, sanitizeFtsQuery, search, searchGrouped, segmentForIndex, segmentQueryTerm, sessionDetail, startIntervalSync, status, stripInjectedBlocks, surfaceLedger };
|
|
2571
|
+
export { BOOT_SYNC_DELAY_MS, DEFAULT_SYNC_INTERVAL_MS, DISCOVERY_LIMIT, DRS_API_PATH, INJECTED_BLOCK_TAGS, LEDGER_LRU_CAP, LedgerCache, PROJECTION_SCHEMA_VERSION, ProjectionSync, SYNC_INTERVAL_ENV, apply, buildSearchSnippet, classifySessionHeader, createQueryContext, createStorePort, decodeSessionLogBytes, decodeSessionLogFile, discoverSessionLogs, drsReadFacade, extractSearchEventText, extractTitleFromEvents, generationLogFilename, handleDrsRequest, inject, listSessions, openProjectionStore, projectSessionEvents, readArchivedSessionIds, readSessionGenerations, recallReport, reloadSummaries, resolveDshHome, resolveExactCounter, resolveIndexDir, resolveSyncIntervalMs, sanitizeFtsQuery, search, searchGrouped, segmentForIndex, segmentQueryTerm, sessionDetail, startIntervalSync, status, stripInjectedBlocks, surfaceLedger };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-reference-session-collector",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"tag": "beta",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
],
|
|
73
73
|
"engines": {
|
|
74
74
|
"node": ">=22",
|
|
75
|
-
"dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4"
|
|
75
|
+
"dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2 || 0.2.1-rc.3 || 0.2.1-rc.4 || 0.2.1-rc.5"
|
|
76
76
|
},
|
|
77
77
|
"license": "MIT",
|
|
78
78
|
"dependencies": {
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* - 启动延迟 2.5s 首轮 syncAll + interval 轮(缺省 30s,env 可关);
|
|
12
12
|
* dispose 关库清定时器。
|
|
13
13
|
*
|
|
14
|
+
* - 跨插件读面:`drsReadFacade()` 返回绑本插件**活 QueryContext** 的只读门面(供
|
|
15
|
+
* 消费方进程内调用,绕开宿主对插件服务端请求的 HTTP 鉴权)。消费方只需认这一个
|
|
16
|
+
* 稳定符号,不必知道 QueryContext/store 的存在,也不必自己开库(自开库会多占一份
|
|
17
|
+
* 常驻 summaries 与一个读事务,且要自己拿五个内部导出名)。库未就绪/已 dispose
|
|
18
|
+
* 时返回 undefined,由消费方降级。
|
|
19
|
+
*
|
|
14
20
|
* 只读纪律:本文件不直接触碰会话文件——全部经 ProjectionSync 端口。
|
|
15
21
|
*/
|
|
16
22
|
import type { Context } from '@deepseek-ai/cordis'
|
|
@@ -25,8 +31,9 @@ import {
|
|
|
25
31
|
status,
|
|
26
32
|
surfaceLedger,
|
|
27
33
|
type QueryContext,
|
|
34
|
+
type SessionDetailOptions,
|
|
28
35
|
} from './surface.ts'
|
|
29
|
-
import { openProjectionStore, type ProjectionStore } from './schema.ts'
|
|
36
|
+
import { openProjectionStore, type ProjectionStore, type SessionRow } from './schema.ts'
|
|
30
37
|
import { projectSessionEvents } from './projection.ts'
|
|
31
38
|
import type { SessionProjection } from './projection.ts'
|
|
32
39
|
|
|
@@ -352,6 +359,44 @@ function safeReadService(ctx: Context, name: string): unknown {
|
|
|
352
359
|
}
|
|
353
360
|
}
|
|
354
361
|
|
|
362
|
+
/**
|
|
363
|
+
* 跨插件只读门面的返回形状:与 HTTP 面 `handleDrsRequest` 同字段
|
|
364
|
+
* (消费方已按那套映射写)。
|
|
365
|
+
*/
|
|
366
|
+
export interface DrsReadFacade {
|
|
367
|
+
/** 会话汇总分页(按 last_time_ms 降序)。 */
|
|
368
|
+
listSessions: (offset?: number, limit?: number) => { total: number; rows: SessionRow[] }
|
|
369
|
+
/** 单会话明细;opts.tail 缺省即全量(消费方的重建事实源臂依赖这点)。 */
|
|
370
|
+
sessionDetail: (sessionId: string, opts?: SessionDetailOptions) => { session: SessionRow | undefined; rows: unknown[] }
|
|
371
|
+
/** 全文检索(脱敏臂由 opts.redact 控制)。 */
|
|
372
|
+
search: (query: string, opts?: { session?: string; limit?: number; redact?: boolean }) => { query: string; match: string; hits: Record<string, unknown>[] }
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* 活 QueryContext(在 apply 的 setImmediate 臂赋值,dispose 时清空)。
|
|
377
|
+
*
|
|
378
|
+
* 为何要模块级一份:消费方从自己包作用域 `import` 本包时,在 **hoisted 布局**
|
|
379
|
+
* (desktop profile 就是 `nodeLinker: hoisted`)下解析到同一物理 lib/index.js,
|
|
380
|
+
* Node 的 ESM 缓存会返回**同一个模块实例**,因此读到的是这里已赋值的活库。
|
|
381
|
+
* 若某个部署是 pnpm 隔离布局且两包各有链接副本,两侧会是不同实例、本变量在消费侧
|
|
382
|
+
* 为 undefined——门面会诚实返回 undefined,消费方回退自开库,不会读到错数据。
|
|
383
|
+
*/
|
|
384
|
+
let liveQuery: QueryContext | undefined
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* 取跨插件只读门面。库尚未就绪(apply 延迟初始化未完成)或已 dispose 时返回
|
|
388
|
+
* **undefined**,不抛——让消费方自己决定降级口径(报不可用或回退 HTTP)。
|
|
389
|
+
*/
|
|
390
|
+
export function drsReadFacade(): DrsReadFacade | undefined {
|
|
391
|
+
const ctx = liveQuery
|
|
392
|
+
if (ctx === undefined) return undefined
|
|
393
|
+
return {
|
|
394
|
+
listSessions: (offset, limit) => listSessions(ctx, offset, limit),
|
|
395
|
+
sessionDetail: (sessionId, opts) => sessionDetail(ctx, sessionId, opts),
|
|
396
|
+
search: (query, opts) => search(ctx, query, opts),
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
355
400
|
/**
|
|
356
401
|
* 插件主体:apply() 立即返回,重活(开库/建 sync/注册路由)推迟到 setImmediate。
|
|
357
402
|
* 宿主插件装载串行同步——apply 不返回则整列插件都装不上,前端一直 Loading plugins…。
|
|
@@ -419,6 +464,9 @@ export function apply(ctx: Context): void {
|
|
|
419
464
|
if (bootTimer !== undefined) clearTimeout(bootTimer)
|
|
420
465
|
disposeInterval()
|
|
421
466
|
store?.close()
|
|
467
|
+
// 库已关 → 门面必须同步失效,否则消费方拿到的是指向已关 db 的 QueryContext。
|
|
468
|
+
liveQuery = undefined
|
|
469
|
+
query = undefined
|
|
422
470
|
}
|
|
423
471
|
}, 'dsh-reference-session-collector: projection lifecycle')
|
|
424
472
|
|
|
@@ -428,6 +476,8 @@ export function apply(ctx: Context): void {
|
|
|
428
476
|
const storeDir = resolveIndexDir()
|
|
429
477
|
store = openProjectionStore(storeDir)
|
|
430
478
|
query = createQueryContext(store)
|
|
479
|
+
// 对跨插件消费方暴露活查询面(见 drsReadFacade 注)。
|
|
480
|
+
liveQuery = query
|
|
431
481
|
|
|
432
482
|
sync = new ProjectionSync({
|
|
433
483
|
store: createStorePort(store),
|