dsh-manage-session 0.5.1 → 0.5.4
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/CHANGELOG.ja.md +207 -242
- package/CHANGELOG.ko.md +207 -242
- package/CHANGELOG.md +341 -341
- package/INSTALL.ja.md +164 -179
- package/INSTALL.ko.md +164 -179
- package/INSTALL.md +164 -179
- package/INSTALL.zh.md +164 -179
- package/LICENSE +21 -21
- package/README.en.md +4 -12
- package/README.ja.md +0 -12
- package/README.ko.md +0 -12
- package/README.md +4 -14
- package/cordis.patch.yml +16 -11
- package/dsh.plugin.json +4 -4
- package/lib/client.js +3882 -690
- package/lib/index.d.ts +759 -29
- package/lib/index.js +2604 -93
- package/locale/de.json +6 -0
- package/locale/en.json +6 -0
- package/locale/es.json +6 -0
- package/locale/fr.json +6 -0
- package/locale/it.json +6 -0
- package/locale/ja.json +6 -0
- package/locale/ko.json +6 -0
- package/locale/ru.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +43 -32
- package/src/client/bridge-scope.ts +213 -0
- package/src/client/card.tsx +150 -150
- package/src/client/history-panel.tsx +319 -319
- package/src/client/index.ts +465 -354
- package/src/client/locales.ts +857 -698
- package/src/client/panel.tsx +139 -118
- package/src/client/search/card.tsx +563 -0
- package/src/client/search/host-api.ts +208 -0
- package/src/client/search/locales.ts +780 -0
- package/src/client/search/manage.tsx +400 -0
- package/src/client/search/panel.tsx +815 -0
- package/src/client/search/platform.ts +136 -0
- package/src/config.ts +82 -33
- package/src/host/health/attribution.ts +118 -118
- package/src/host/health/lossless.ts +128 -128
- package/src/host/health/source-kind.ts +350 -350
- package/src/host/history/archive-source.ts +250 -202
- package/src/host/history/archive.ts +249 -194
- package/src/host/history/favorites.ts +71 -0
- package/src/host/history/purge.ts +370 -370
- package/src/host/index/archive-source.ts +90 -0
- package/src/host/index/engine.ts +571 -0
- package/src/host/index/extract.ts +272 -0
- package/src/host/index/peers.ts +62 -0
- package/src/host/index/rebuild.ts +368 -0
- package/src/host/index/schema.ts +136 -0
- package/src/host/index/snapshot.ts +135 -0
- package/src/host/index/sync.ts +286 -0
- package/src/host/registry/archive-registry.ts +317 -0
- package/src/host/settings-bridge.ts +237 -0
- package/src/index.ts +1421 -532
- package/README.de.md +0 -120
- package/README.es.md +0 -120
- package/README.fr.md +0 -120
- package/README.it.md +0 -120
- package/README.ru.md +0 -120
package/lib/index.d.ts
CHANGED
|
@@ -294,7 +294,7 @@ declare class Fiber {
|
|
|
294
294
|
//#endregion
|
|
295
295
|
//#region node_modules/cordis/lib/events.d.ts
|
|
296
296
|
type Parameters<F> = F extends ((...args: infer P) => any) ? P : never;
|
|
297
|
-
type ReturnType<F> = F extends ((...args: any) => infer R) ? R : never;
|
|
297
|
+
type ReturnType$1<F> = F extends ((...args: any) => infer R) ? R : never;
|
|
298
298
|
type ThisType<F> = F extends ((this: infer T, ...args: any) => any) ? T : never;
|
|
299
299
|
type DispatchMode = 'emit' | 'parallel' | 'serial' | 'bail' | 'waterfall';
|
|
300
300
|
declare module './context' {
|
|
@@ -303,12 +303,12 @@ declare module './context' {
|
|
|
303
303
|
parallel<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): Promise<void>;
|
|
304
304
|
emit<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): void;
|
|
305
305
|
emit<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): void;
|
|
306
|
-
serial<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType<Events[K]>>;
|
|
307
|
-
serial<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType<Events[K]>>;
|
|
308
|
-
bail<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>;
|
|
309
|
-
bail<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>;
|
|
310
|
-
waterfall<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>;
|
|
311
|
-
waterfall<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType<Events[K]>;
|
|
306
|
+
serial<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType$1<Events[K]>>;
|
|
307
|
+
serial<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): Promisify<ReturnType$1<Events[K]>>;
|
|
308
|
+
bail<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType$1<Events[K]>;
|
|
309
|
+
bail<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType$1<Events[K]>;
|
|
310
|
+
waterfall<K extends keyof Events>(name: K, ...args: Parameters<Events[K]>): ReturnType$1<Events[K]>;
|
|
311
|
+
waterfall<K extends keyof Events>(thisArg: NoInfer<ThisType<Events[K]>>, name: K, ...args: Parameters<Events[K]>): ReturnType$1<Events[K]>;
|
|
312
312
|
on<K extends keyof Events>(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean;
|
|
313
313
|
once<K extends keyof Events>(name: K, listener: Events[K], options?: boolean | EventOptions): () => boolean;
|
|
314
314
|
}
|
|
@@ -460,27 +460,59 @@ declare abstract class Service<out T = never> {
|
|
|
460
460
|
//#endregion
|
|
461
461
|
//#region src/config.d.ts
|
|
462
462
|
/**
|
|
463
|
-
* dsh-manage-session
|
|
463
|
+
* dsh-manage-session 的共享配置面(合并包:管家子域 + 搜索索引子域)。
|
|
464
464
|
*
|
|
465
465
|
* 与 host 半身(schemastery schema 在 src/index.ts)以及浏览器半身共用同一形状,
|
|
466
|
-
* 使一处 admitted 的值在另一处也 admitted
|
|
467
|
-
*
|
|
466
|
+
* 使一处 admitted 的值在另一处也 admitted。
|
|
467
|
+
*
|
|
468
|
+
* 两个设置命名空间**并存且互不迁移**:
|
|
469
|
+
* - `session-steward` —— 管家子域(enabled/historyFiles/healthCheck/search 等共享键);
|
|
470
|
+
* - `switch-search` —— 搜索子域的历史命名空间,存储键承诺保持稳定(见
|
|
471
|
+
* dsh-search-index README「存储键保持稳定,不做迁移」);0.1.7 起两者实际
|
|
472
|
+
* 都落在同一 composition entry(configForms),旧宿主才按命名空间分流。
|
|
468
473
|
*/
|
|
469
474
|
/** 会话管家运行时配置(设置命名空间 + 组合入口)。 */
|
|
470
475
|
interface StewardConfig {
|
|
471
|
-
/**
|
|
476
|
+
/** 插件总开关(合并包唯一 master:关闭后不注册任何子域路由)。 */
|
|
472
477
|
enabled: boolean;
|
|
473
478
|
/** 会话历史文件(归档浏览与清理)。关闭后不注册 history 路由、不渲染「养老院」页签。 */
|
|
474
479
|
historyFiles?: boolean;
|
|
475
480
|
/** 会话健康检查(体检 → 处方 → 出院)。关闭后不注册 health 路由、不渲染「体检」页签。 */
|
|
476
481
|
healthCheck?: boolean;
|
|
482
|
+
/** 搜索索引子域(`index-*` 路由与侧栏搜索入口)。关闭后索引子域整体停摆。 */
|
|
483
|
+
search?: boolean;
|
|
477
484
|
}
|
|
478
485
|
/** 缺省值。 */
|
|
479
486
|
declare const DEFAULT_CONFIG: Required<StewardConfig>;
|
|
480
487
|
/** host 半身注册的设置命名空间(与 src/index.ts 保持一致)。 */
|
|
481
488
|
declare const STEWARD_SETTINGS_NAMESPACE = "session-steward";
|
|
482
|
-
/** host
|
|
489
|
+
/** host 路由前缀(管家子域;与搜索子域的 /switch-search/api 互不干扰)。 */
|
|
483
490
|
declare const STEWARD_API_PREFIX = "/session-steward/api";
|
|
491
|
+
/** 搜索子域路由前缀(历史值,浏览器旧 bundle 与快照文件名依赖它,保持不变)。 */
|
|
492
|
+
declare const SWITCH_API_PREFIX = "/switch-search/api";
|
|
493
|
+
/** 搜索面板打开时的默认模式。 */
|
|
494
|
+
type SwitchSearchDefaultMode = 'title' | 'content';
|
|
495
|
+
/** 搜索子域可调配置(独立于 StewardConfig 的历史形状,字段名保持稳定)。 */
|
|
496
|
+
interface SwitchSearchConfig {
|
|
497
|
+
/**
|
|
498
|
+
* 搜索卡上的「启用」开关。合并包里它与管家 `enabled` 是**同一个**组合入口
|
|
499
|
+
* 字段(0.1.7 configForms 单 scope);保留在此处是为了 legacy settingsScope
|
|
500
|
+
* 回退路径(旧 switch-search 命名空间的存储形状)与设置卡类型不变。
|
|
501
|
+
*/
|
|
502
|
+
enabled?: boolean;
|
|
503
|
+
/** 面板默认模式。 */
|
|
504
|
+
defaultMode: SwitchSearchDefaultMode;
|
|
505
|
+
/** 独立索引是否后台自动同步(水位轮询)。 */
|
|
506
|
+
autoSync?: boolean;
|
|
507
|
+
/** 增量同步间隔(ms)。 */
|
|
508
|
+
syncIntervalMs?: number;
|
|
509
|
+
/** 整理索引后保留的归档份数。 */
|
|
510
|
+
archiveKeep?: number;
|
|
511
|
+
/** 独立索引文件的可选绝对目录。 */
|
|
512
|
+
indexDir?: string;
|
|
513
|
+
}
|
|
514
|
+
/** 搜索子域缺省值。 */
|
|
515
|
+
declare const SWITCH_DEFAULT_CONFIG: Required<SwitchSearchConfig>;
|
|
484
516
|
//#endregion
|
|
485
517
|
//#region src/host/history/archive-source.d.ts
|
|
486
518
|
/** 一次归档读取的结果:ids 以及服务它的来源。 */
|
|
@@ -549,6 +581,36 @@ declare function pruneArchiveFile(ids: readonly string[], log?: (msg: string) =>
|
|
|
549
581
|
remaining: number;
|
|
550
582
|
file?: string;
|
|
551
583
|
};
|
|
584
|
+
/**
|
|
585
|
+
* 把会话 id 加入存储中枢的 `global.archivedSessionIds`(= 归档,prune 的逆操作)。
|
|
586
|
+
*
|
|
587
|
+
* 与 prune 同一写入口与协议(备份 + 临时文件 + 原子改名);已在集合中的 id
|
|
588
|
+
* 不重复追加。运行中的宿主把集合留在内存里、只在启动时重载 —— 调用方必须
|
|
589
|
+
* 提示需要重启 DSH。
|
|
590
|
+
* @param ids - 要加入归档数组的会话 id。
|
|
591
|
+
* @param log - 可选日志出口。
|
|
592
|
+
* @param searchPaths - 可选候选路径覆盖(测试注入用)。
|
|
593
|
+
* @returns 实际新增数量与操作后的集合总数。
|
|
594
|
+
*/
|
|
595
|
+
declare function archiveArchiveFile(ids: readonly string[], log?: (msg: string) => void, searchPaths?: readonly string[]): {
|
|
596
|
+
added: number;
|
|
597
|
+
total: number;
|
|
598
|
+
file?: string;
|
|
599
|
+
};
|
|
600
|
+
//#endregion
|
|
601
|
+
//#region src/host/settings-bridge.d.ts
|
|
602
|
+
/** 桥对 handleMethod 暴露的面。 */
|
|
603
|
+
interface LegacySettingsBridge {
|
|
604
|
+
/** 读一个命名空间文档(无文档/非对象 → undefined)。 */
|
|
605
|
+
get(ns: string): Record<string, unknown> | undefined;
|
|
606
|
+
/** 合并写一个命名空间文档;宿主拒绝时抛错(调用方转显式失败)。 */
|
|
607
|
+
update(ns: string, patch: Record<string, unknown>): Promise<void>;
|
|
608
|
+
}
|
|
609
|
+
/** 桥运行时状态(revision 随每次成功写自增,客户端据此识别权威新值)。 */
|
|
610
|
+
interface BridgeState {
|
|
611
|
+
bridge: LegacySettingsBridge | undefined;
|
|
612
|
+
revision: number;
|
|
613
|
+
}
|
|
552
614
|
//#endregion
|
|
553
615
|
//#region src/host/health/decode.d.ts
|
|
554
616
|
/** 一次读取的统计与问题清单。 */
|
|
@@ -873,6 +935,492 @@ declare class HealthCache {
|
|
|
873
935
|
clear(): void;
|
|
874
936
|
}
|
|
875
937
|
//#endregion
|
|
938
|
+
//#region src/host/index/schema.d.ts
|
|
939
|
+
/**
|
|
940
|
+
* Which SQLite driver served the handle (better-sqlite3 when the optional
|
|
941
|
+
* dependency installed, node:sqlite otherwise). Surfaced in logs and
|
|
942
|
+
* index-status so rebuild speed can be compared across drivers.
|
|
943
|
+
*/
|
|
944
|
+
type SwitchSqliteDriver = 'better-sqlite3' | 'node:sqlite';
|
|
945
|
+
//#endregion
|
|
946
|
+
//#region src/host/index/extract.d.ts
|
|
947
|
+
/**
|
|
948
|
+
* First-party semantic text extraction for the independent switch-search index.
|
|
949
|
+
*
|
|
950
|
+
* Semantics mirror the official session-query `extractSessionEventText` and the
|
|
951
|
+
* core-session surface fold, mirrored structurally: the plugin must not
|
|
952
|
+
* value-import official packages, so the event data is inspected as plain
|
|
953
|
+
* records. Structural boundaries, embedded raw streams, request envelopes, and
|
|
954
|
+
* unknown declaration-merged events contribute no text.
|
|
955
|
+
*/
|
|
956
|
+
/** One raw session event the plugin reads through sessionQuery.readSession. */
|
|
957
|
+
interface SwitchRawEvent {
|
|
958
|
+
seq: number;
|
|
959
|
+
type: string;
|
|
960
|
+
time?: number;
|
|
961
|
+
ignorable?: boolean;
|
|
962
|
+
surfaceOp?: unknown;
|
|
963
|
+
data: unknown;
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* 从会话事件流里抽出**最后一帧标题**(`session/title` log-only 事件)。
|
|
967
|
+
*
|
|
968
|
+
* 这是标题的基础层:入索引时随事件白拿,不依赖 readTitleSnapshots(后者
|
|
969
|
+
* 对归档 id 可能整批失败——beta.4 标题全军覆没的根因)。数据形状按历史
|
|
970
|
+
* 演变兼容三种:`{ title: string }`、`{ title: { title } }`、`{ title: { val } }`。
|
|
971
|
+
*/
|
|
972
|
+
declare function extractTitleFromEvents(events: readonly SwitchRawEvent[]): string;
|
|
973
|
+
//#endregion
|
|
974
|
+
//#region src/host/index/engine.d.ts
|
|
975
|
+
/** One indexed session header row. */
|
|
976
|
+
interface SwitchIndexedSession {
|
|
977
|
+
sessionId: string;
|
|
978
|
+
version: number;
|
|
979
|
+
title: string;
|
|
980
|
+
cwd: string;
|
|
981
|
+
updatedAt: number;
|
|
982
|
+
indexedAt: number;
|
|
983
|
+
archived: boolean;
|
|
984
|
+
}
|
|
985
|
+
/** One session-grouped search hit. */
|
|
986
|
+
interface SwitchSearchHit {
|
|
987
|
+
sessionId: string;
|
|
988
|
+
title: string;
|
|
989
|
+
seq: number;
|
|
990
|
+
type: string;
|
|
991
|
+
/** Timestamp of the strongest matching document. Per-hit, not per-session. */
|
|
992
|
+
time: number;
|
|
993
|
+
/**
|
|
994
|
+
* Session-level last-activity timestamp. Distinct from `time`: a session
|
|
995
|
+
* may hold an old best match yet have moved one minute ago. This is the
|
|
996
|
+
* field recency ordering and any client-side re-sort must key on.
|
|
997
|
+
*/
|
|
998
|
+
updatedAt: number;
|
|
999
|
+
snippet: string;
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Result ordering for one search.
|
|
1003
|
+
* - `relevance` (default) — weighted BM25, the historical behaviour.
|
|
1004
|
+
* - `time` — session recency first, relevance as the tie-break.
|
|
1005
|
+
*/
|
|
1006
|
+
type SwitchSearchSort = 'relevance' | 'time';
|
|
1007
|
+
/** Coarse type-filter buckets mapped onto raw session event types. */
|
|
1008
|
+
type SwitchIndexContentType = 'all' | 'user' | 'reply' | 'tool';
|
|
1009
|
+
/** Constructor options for one engine instance. */
|
|
1010
|
+
interface SwitchIndexEngineOptions {
|
|
1011
|
+
/** Absolute path of the index file this engine owns. */
|
|
1012
|
+
path: string;
|
|
1013
|
+
}
|
|
1014
|
+
/** One open index handle. All mutating calls are synchronous; callers pace
|
|
1015
|
+
* them off the HTTP hot path (background sync / rebuild tasks). */
|
|
1016
|
+
declare class SwitchIndexEngine {
|
|
1017
|
+
private readonly options;
|
|
1018
|
+
private db;
|
|
1019
|
+
private driver;
|
|
1020
|
+
private inBatch;
|
|
1021
|
+
constructor(options: SwitchIndexEngineOptions);
|
|
1022
|
+
/** Which SQLite driver is serving this handle. */
|
|
1023
|
+
get driverLabel(): SwitchSqliteDriver;
|
|
1024
|
+
/**
|
|
1025
|
+
* Run one write inside the current batched transaction, or its own
|
|
1026
|
+
* IMMEDIATE transaction when not batching (nested calls join the batch).
|
|
1027
|
+
*/
|
|
1028
|
+
withWriteTx<T>(fn: () => T): T;
|
|
1029
|
+
/**
|
|
1030
|
+
* Run one function as a single batched transaction (one fsync checkpoint):
|
|
1031
|
+
* upserts inside it join via withWriteTx instead of opening their own.
|
|
1032
|
+
*/
|
|
1033
|
+
runBatched<T>(fn: () => T): T;
|
|
1034
|
+
/** Whether the handle is open. */
|
|
1035
|
+
get isOpen(): boolean;
|
|
1036
|
+
/** Open (creating or migrating) the index file. Idempotent. */
|
|
1037
|
+
open(): Promise<void>;
|
|
1038
|
+
/** Close the handle. Idempotent. */
|
|
1039
|
+
close(): void;
|
|
1040
|
+
/** Remove one session's FTS entries for external-content bookkeeping. */
|
|
1041
|
+
private deleteSessionFts;
|
|
1042
|
+
/** Insert or replace one session's documents and header row. */
|
|
1043
|
+
upsertSession(input: {
|
|
1044
|
+
sessionId: string;
|
|
1045
|
+
version: number;
|
|
1046
|
+
title?: string;
|
|
1047
|
+
cwd?: string;
|
|
1048
|
+
updatedAt?: number;
|
|
1049
|
+
events: readonly SwitchRawEvent[];
|
|
1050
|
+
/**
|
|
1051
|
+
* 归档标记。缺省时**保留行上现有值**(归档态翻转由 setArchived 单独负责,
|
|
1052
|
+
* 全量重灌不改变归档状态);显式传入时以传入值为准(重建/导入路径)。
|
|
1053
|
+
*/
|
|
1054
|
+
archived?: boolean;
|
|
1055
|
+
}): void;
|
|
1056
|
+
/**
|
|
1057
|
+
* Write an archived session's header row without any document content.
|
|
1058
|
+
*
|
|
1059
|
+
* @deprecated 旧"归档即软删"语义的遗物,合并包 R1 已改为归档保留 docs;仅剩
|
|
1060
|
+
* 旧快照兼容路径可落 header 行。新代码一律 upsertSession + setArchived。
|
|
1061
|
+
*/
|
|
1062
|
+
upsertArchivedHeader(input: {
|
|
1063
|
+
sessionId: string;
|
|
1064
|
+
version: number;
|
|
1065
|
+
title?: string;
|
|
1066
|
+
cwd?: string;
|
|
1067
|
+
updatedAt?: number;
|
|
1068
|
+
}): void;
|
|
1069
|
+
/**
|
|
1070
|
+
* Apply the official archive set: flip the archived flag both ways.
|
|
1071
|
+
*
|
|
1072
|
+
* 合表复用语义(R1):归档**保留全部 docs 与 FTS**——正文在归档态不可变
|
|
1073
|
+
* (归档门只拒新回合),翻转只是检索域成员资格的变化;恢复也不再需要重灌
|
|
1074
|
+
* (旧实现的 version = -1 强制重读随"归档即删 docs"一并废除)。
|
|
1075
|
+
*/
|
|
1076
|
+
setArchived(archivedIds: ReadonlySet<string>): void;
|
|
1077
|
+
/**
|
|
1078
|
+
* Flip one session's archived flag (steward write-side linkage). No-op when
|
|
1079
|
+
* the row does not exist — flag state on an unindexed session is meaningless.
|
|
1080
|
+
*/
|
|
1081
|
+
setArchivedOne(sessionId: string, archived: boolean): void;
|
|
1082
|
+
/** One session's stored documents, ascending seq (snapshot export face). */
|
|
1083
|
+
exportSessionDocs(sessionId: string): {
|
|
1084
|
+
seq: number;
|
|
1085
|
+
type: string;
|
|
1086
|
+
surface: string;
|
|
1087
|
+
time: number;
|
|
1088
|
+
text: string;
|
|
1089
|
+
}[];
|
|
1090
|
+
/**
|
|
1091
|
+
* Insert or replace one session from already-extracted documents
|
|
1092
|
+
* (snapshot import face; no re-extraction, what was exported is restored;
|
|
1093
|
+
* segmentation is recomputed for the current index format).
|
|
1094
|
+
*/
|
|
1095
|
+
importSessionDocs(input: {
|
|
1096
|
+
sessionId: string;
|
|
1097
|
+
version: number;
|
|
1098
|
+
title?: string;
|
|
1099
|
+
/** 归档标记随快照往返;旧快照缺省为活跃。 */
|
|
1100
|
+
archived?: boolean;
|
|
1101
|
+
docs: readonly {
|
|
1102
|
+
seq: number;
|
|
1103
|
+
type: string;
|
|
1104
|
+
surface: string;
|
|
1105
|
+
time: number;
|
|
1106
|
+
text: string;
|
|
1107
|
+
}[];
|
|
1108
|
+
}): void;
|
|
1109
|
+
/** Remove one session and its documents entirely. */
|
|
1110
|
+
removeSession(sessionId: string): void;
|
|
1111
|
+
/** Update only a session's header row (title backfill), keeping documents. */
|
|
1112
|
+
updateSessionHeader(input: {
|
|
1113
|
+
sessionId: string;
|
|
1114
|
+
title?: string;
|
|
1115
|
+
cwd?: string;
|
|
1116
|
+
updatedAt?: number;
|
|
1117
|
+
}): void;
|
|
1118
|
+
/** One indexed session row, or undefined. */
|
|
1119
|
+
getSession(sessionId: string): SwitchIndexedSession | undefined;
|
|
1120
|
+
/** All indexed sessions (active AND archived), newest first — the title
|
|
1121
|
+
* corpus and the manage console both read this; the `archived` flag rides
|
|
1122
|
+
* each row so clients filter locally. */
|
|
1123
|
+
listIndexedSessions(): SwitchIndexedSession[];
|
|
1124
|
+
/** Archived (soft-deleted) sessions, newest first — the archive viewer face. */
|
|
1125
|
+
listArchived(): SwitchIndexedSession[];
|
|
1126
|
+
/** Number of indexed sessions (active + archived — the whole corpus). */
|
|
1127
|
+
countSessions(): number;
|
|
1128
|
+
/** Number of archived (soft-deleted) sessions. */
|
|
1129
|
+
countArchived(): number;
|
|
1130
|
+
/**
|
|
1131
|
+
* Run one session-grouped full-text search.
|
|
1132
|
+
*
|
|
1133
|
+
* One statement: the FTS match is bounded by rank in a subquery (its rowid
|
|
1134
|
+
* aligns with docs.doc_id), then the type/surface filters join in — no
|
|
1135
|
+
* second round-trip, no large IN parameter lists.
|
|
1136
|
+
* @param request - query text, coarse type filter, page size, ordering.
|
|
1137
|
+
* @returns hits ordered by `sortBy` (relevance by default).
|
|
1138
|
+
*/
|
|
1139
|
+
search(request: {
|
|
1140
|
+
query: string;
|
|
1141
|
+
types?: readonly SwitchIndexContentType[];
|
|
1142
|
+
limit?: number;
|
|
1143
|
+
sortBy?: SwitchSearchSort;
|
|
1144
|
+
/**
|
|
1145
|
+
* 检索域:`'active'` 仅活跃、`'archived'` 仅归档、`'all'`(缺省)两者。
|
|
1146
|
+
* 归档正文入索引后的筛选 chip 即此参数。
|
|
1147
|
+
*/
|
|
1148
|
+
archived?: 'active' | 'archived' | 'all';
|
|
1149
|
+
/** 更新时间下界(epoch ms,含)。 */
|
|
1150
|
+
from?: number;
|
|
1151
|
+
/** 更新时间上界(epoch ms,排他)。 */
|
|
1152
|
+
to?: number;
|
|
1153
|
+
}): SwitchSearchHit[];
|
|
1154
|
+
private requireDb;
|
|
1155
|
+
}
|
|
1156
|
+
//#endregion
|
|
1157
|
+
//#region src/host/index/sync.d.ts
|
|
1158
|
+
/** The sessionQuery faces the sync reads (structural mirrors). */
|
|
1159
|
+
interface SwitchSyncSessionQuery {
|
|
1160
|
+
listSessions(): Promise<readonly {
|
|
1161
|
+
header: {
|
|
1162
|
+
id: string;
|
|
1163
|
+
version: number;
|
|
1164
|
+
createdAt?: number;
|
|
1165
|
+
cwd?: string;
|
|
1166
|
+
};
|
|
1167
|
+
}[]>;
|
|
1168
|
+
readSession(sessionId: string): Promise<{
|
|
1169
|
+
session: {
|
|
1170
|
+
id: string;
|
|
1171
|
+
version: number;
|
|
1172
|
+
createdAt?: number;
|
|
1173
|
+
cwd?: string;
|
|
1174
|
+
};
|
|
1175
|
+
events: readonly SwitchRawEvent[];
|
|
1176
|
+
}>;
|
|
1177
|
+
readTitleSnapshots?(sessionIds: readonly string[]): Promise<readonly {
|
|
1178
|
+
status: 'fulfilled' | 'rejected';
|
|
1179
|
+
value?: {
|
|
1180
|
+
session: {
|
|
1181
|
+
id: string;
|
|
1182
|
+
};
|
|
1183
|
+
title?: {
|
|
1184
|
+
title: string;
|
|
1185
|
+
};
|
|
1186
|
+
};
|
|
1187
|
+
}[]>;
|
|
1188
|
+
}
|
|
1189
|
+
/** Live sync progress reported to the status endpoint. */
|
|
1190
|
+
interface SwitchSyncState {
|
|
1191
|
+
/** What the syncer is doing right now. */
|
|
1192
|
+
state: 'idle' | 'syncing' | 'error';
|
|
1193
|
+
/** Epoch ms of the last completed pass. */
|
|
1194
|
+
lastSyncAt: number;
|
|
1195
|
+
/** Sessions currently in the index. */
|
|
1196
|
+
indexed: number;
|
|
1197
|
+
/** Sessions seen in the corpus at the last pass. */
|
|
1198
|
+
total: number;
|
|
1199
|
+
/** Sessions re-read in the last pass. */
|
|
1200
|
+
updated: number;
|
|
1201
|
+
/** Per-session failures from the last pass. */
|
|
1202
|
+
failures: {
|
|
1203
|
+
sessionId: string;
|
|
1204
|
+
error: string;
|
|
1205
|
+
}[];
|
|
1206
|
+
/** Last pass error (whole-pass abort), if any. */
|
|
1207
|
+
error?: string;
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* The official archive-set face (workspaceRegistry mirror): read-only.
|
|
1211
|
+
* Resolved lazily per pass — the registry may mount after this plugin.
|
|
1212
|
+
*/
|
|
1213
|
+
interface SwitchArchiveSource {
|
|
1214
|
+
readonly archivedSessionIds: readonly string[];
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* One watermark syncer bound to one open engine. `poll()` is re-entrant-safe:
|
|
1218
|
+
* overlapping calls collapse into the running pass.
|
|
1219
|
+
*/
|
|
1220
|
+
declare class SwitchWatermarkSync {
|
|
1221
|
+
private readonly engine;
|
|
1222
|
+
private readonly sessionQuery;
|
|
1223
|
+
private readonly readArchiveSource?;
|
|
1224
|
+
private readonly log?;
|
|
1225
|
+
private readonly readSessionFromFile?;
|
|
1226
|
+
/**
|
|
1227
|
+
* 第三标题源(可选):官方投影缓存里的 title 行。事件流没有 session/title
|
|
1228
|
+
* 的老会话,快照服务又整片不可用时,这是最后兜底。
|
|
1229
|
+
*/
|
|
1230
|
+
private readonly readProjectionTitle?;
|
|
1231
|
+
private running;
|
|
1232
|
+
private readonly state;
|
|
1233
|
+
/**
|
|
1234
|
+
* @param readSessionFromFile - 可选的**文件级兜底读取器**(管家 health 侧的
|
|
1235
|
+
* 多帧 zstd 读取器):sessionQuery.readSession 对某些会话(典型:归档会话,
|
|
1236
|
+
* 或服务面退化)失败时改读转录文件。返回 undefined 表示文件也不可用。
|
|
1237
|
+
*/
|
|
1238
|
+
constructor(engine: SwitchIndexEngine, sessionQuery: SwitchSyncSessionQuery, readArchiveSource?: (() => SwitchArchiveSource | undefined) | undefined, log?: ((msg: string) => void) | undefined, readSessionFromFile?: ((sessionId: string) => Promise<{
|
|
1239
|
+
session: {
|
|
1240
|
+
id: string;
|
|
1241
|
+
version: number;
|
|
1242
|
+
createdAt?: number;
|
|
1243
|
+
cwd?: string;
|
|
1244
|
+
};
|
|
1245
|
+
events: readonly SwitchRawEvent[];
|
|
1246
|
+
} | undefined>) | undefined,
|
|
1247
|
+
/**
|
|
1248
|
+
* 第三标题源(可选):官方投影缓存里的 title 行。事件流没有 session/title
|
|
1249
|
+
* 的老会话,快照服务又整片不可用时,这是最后兜底。
|
|
1250
|
+
*/
|
|
1251
|
+
readProjectionTitle?: ((sessionId: string) => string) | undefined);
|
|
1252
|
+
/**
|
|
1253
|
+
* 读取一个会话的日志:服务面优先,失败落文件兜底。两条路都失败时抛最后
|
|
1254
|
+
* 一个错误,由调用方按会话隔离记失败。
|
|
1255
|
+
*/
|
|
1256
|
+
private readSessionLog;
|
|
1257
|
+
/** Current progress snapshot (cloned). */
|
|
1258
|
+
snapshot(): SwitchSyncState;
|
|
1259
|
+
/**
|
|
1260
|
+
* Fold titles for an explicit id set without running a full pass.
|
|
1261
|
+
*
|
|
1262
|
+
* Used by the `session/title` event listener so a rename lands immediately
|
|
1263
|
+
* rather than at the next poll. It deliberately leaves watermarks alone: a
|
|
1264
|
+
* title-only refresh can never make the index claim content it has not read,
|
|
1265
|
+
* and the next poll still re-ingests the session off its bumped version.
|
|
1266
|
+
* Safe for unknown ids — the header write is a no-op when no row exists.
|
|
1267
|
+
* @param sessionIds - sessions whose titles should be re-folded.
|
|
1268
|
+
*/
|
|
1269
|
+
refreshTitles(sessionIds: readonly string[]): Promise<void>;
|
|
1270
|
+
/**
|
|
1271
|
+
* Run one incremental pass (or await the running one).
|
|
1272
|
+
* @returns the state after the pass completes.
|
|
1273
|
+
*/
|
|
1274
|
+
poll(): Promise<SwitchSyncState>;
|
|
1275
|
+
private runPass;
|
|
1276
|
+
/**
|
|
1277
|
+
* Fold latest titles for changed sessions into the index header rows.
|
|
1278
|
+
*
|
|
1279
|
+
* beta.4 教训:整批一次调用,任何一个坏 id(典型:归档 id)让整个 promise
|
|
1280
|
+
* reject,catch 一吞就是**全部**标题丢失。改为分块 + 块失败时逐 id 重试 ——
|
|
1281
|
+
* 单点坏 id 最多损失它自己的精修标题(入索引时的 extractTitleFromEvents
|
|
1282
|
+
* 基础层仍然在)。
|
|
1283
|
+
*/
|
|
1284
|
+
private backfillTitles;
|
|
1285
|
+
}
|
|
1286
|
+
//#endregion
|
|
1287
|
+
//#region src/host/index/archive-source.d.ts
|
|
1288
|
+
/** One resolved archive read: ids plus which source served them. */
|
|
1289
|
+
interface SwitchArchiveRead {
|
|
1290
|
+
ids: readonly string[];
|
|
1291
|
+
source: 'registry' | 'storage-file' | 'none';
|
|
1292
|
+
}
|
|
1293
|
+
/** The workspaceRegistry mirror face (getter only). */
|
|
1294
|
+
interface SwitchRegistryFace {
|
|
1295
|
+
readonly archivedSessionIds: readonly string[];
|
|
1296
|
+
}
|
|
1297
|
+
/** Diagnostics describing how the archive set is being resolved. */
|
|
1298
|
+
interface SwitchArchiveDiagnostics {
|
|
1299
|
+
source: 'registry' | 'storage-file' | 'none';
|
|
1300
|
+
ids: number;
|
|
1301
|
+
error?: string;
|
|
1302
|
+
}
|
|
1303
|
+
/** Build the lazy source face the syncer expects, with diagnostics capture. */
|
|
1304
|
+
declare function createArchiveSource(getRegistry: () => SwitchRegistryFace | undefined): {
|
|
1305
|
+
read: () => SwitchArchiveRead;
|
|
1306
|
+
diagnostics: () => SwitchArchiveDiagnostics;
|
|
1307
|
+
};
|
|
1308
|
+
//#endregion
|
|
1309
|
+
//#region src/host/index/rebuild.d.ts
|
|
1310
|
+
/** The corpus reader a rebuild needs (same faces as the syncer). */
|
|
1311
|
+
interface SwitchRebuildSessionQuery {
|
|
1312
|
+
listSessions(): Promise<readonly {
|
|
1313
|
+
header: {
|
|
1314
|
+
id: string;
|
|
1315
|
+
version: number;
|
|
1316
|
+
createdAt?: number;
|
|
1317
|
+
cwd?: string;
|
|
1318
|
+
};
|
|
1319
|
+
}[]>;
|
|
1320
|
+
readSession(sessionId: string): Promise<{
|
|
1321
|
+
session: {
|
|
1322
|
+
id: string;
|
|
1323
|
+
version: number;
|
|
1324
|
+
createdAt?: number;
|
|
1325
|
+
cwd?: string;
|
|
1326
|
+
};
|
|
1327
|
+
events: readonly SwitchRawEvent[];
|
|
1328
|
+
}>;
|
|
1329
|
+
}
|
|
1330
|
+
/** Live rebuild progress reported to the status endpoint. */
|
|
1331
|
+
interface SwitchRebuildState {
|
|
1332
|
+
state: 'idle' | 'building' | 'swapping' | 'error';
|
|
1333
|
+
/** Sessions written into the shadow index so far. */
|
|
1334
|
+
done: number;
|
|
1335
|
+
/** Sessions seen in the corpus when the build started. */
|
|
1336
|
+
total: number;
|
|
1337
|
+
/** Epoch ms when the build started. */
|
|
1338
|
+
startedAt: number;
|
|
1339
|
+
/** Epoch ms when the last build finished. */
|
|
1340
|
+
finishedAt: number;
|
|
1341
|
+
/** Per-session failures during the last build. */
|
|
1342
|
+
failures: {
|
|
1343
|
+
sessionId: string;
|
|
1344
|
+
error: string;
|
|
1345
|
+
}[];
|
|
1346
|
+
error?: string;
|
|
1347
|
+
}
|
|
1348
|
+
/** Filesystem layout of one index directory. */
|
|
1349
|
+
interface SwitchIndexLayout {
|
|
1350
|
+
/** Directory holding every index file. */
|
|
1351
|
+
dir: string;
|
|
1352
|
+
/** Active index file name. */
|
|
1353
|
+
active: string;
|
|
1354
|
+
/** Shadow file name used while building. */
|
|
1355
|
+
building: string;
|
|
1356
|
+
/** Archive file name prefix. */
|
|
1357
|
+
archivePrefix: string;
|
|
1358
|
+
}
|
|
1359
|
+
/** Default layout names. */
|
|
1360
|
+
declare const DEFAULT_INDEX_LAYOUT: SwitchIndexLayout;
|
|
1361
|
+
/**
|
|
1362
|
+
* Inspect the index directory for half-built leftovers from an abnormally
|
|
1363
|
+
* terminated rebuild and recover:
|
|
1364
|
+
* - shadow present + active present: the build never finished — the shadow
|
|
1365
|
+
* is garbage (the active index kept serving) and is discarded.
|
|
1366
|
+
* - shadow present + active missing: the crash hit the rename window — the
|
|
1367
|
+
* newest archive is restored as the active index, the shadow discarded.
|
|
1368
|
+
* Runs at host activation, before the engine opens (opening would create a
|
|
1369
|
+
* fresh empty active file and mask the swap-window case).
|
|
1370
|
+
*/
|
|
1371
|
+
declare function recoverIndex(layout: SwitchIndexLayout, log?: (msg: string) => void): Promise<string[]>;
|
|
1372
|
+
/**
|
|
1373
|
+
* Build a fresh index into the shadow file, then swap it in atomically.
|
|
1374
|
+
*
|
|
1375
|
+
* During the build the caller's active engine stays open and queryable; only
|
|
1376
|
+
* the final swap briefly reopens the handle.
|
|
1377
|
+
* @param activeEngine - the currently-serving engine (its file is replaced).
|
|
1378
|
+
* @param layout - filesystem layout of the index directory.
|
|
1379
|
+
* @param sessionQuery - corpus reader for the full rebuild.
|
|
1380
|
+
* @param keepArchives - how many archive files to retain (oldest pruned).
|
|
1381
|
+
* @param onProgress - optional progress callback after each session.
|
|
1382
|
+
* @returns the rebuild state snapshot after completion.
|
|
1383
|
+
*/
|
|
1384
|
+
/** Optional observability callbacks for rebuildIndex. */
|
|
1385
|
+
interface SwitchRebuildHooks {
|
|
1386
|
+
/** Progress log line sink (cordis logger bridge). */
|
|
1387
|
+
log?: (msg: string) => void;
|
|
1388
|
+
/** State-mutation sink: called after every change so index-status sees
|
|
1389
|
+
* live progress (the "0/?" bug was state cloned only at completion). */
|
|
1390
|
+
onState?: (state: SwitchRebuildState) => void;
|
|
1391
|
+
/**
|
|
1392
|
+
* 文件级兜底读取器(与同步器同语义):readSession 对归档/服务面退化会话
|
|
1393
|
+
* 失败时改读转录文件;返回 undefined 表示文件也不可用(记失败)。
|
|
1394
|
+
*/
|
|
1395
|
+
readSessionFromFile?: (sessionId: string) => Promise<{
|
|
1396
|
+
session: {
|
|
1397
|
+
id: string;
|
|
1398
|
+
version: number;
|
|
1399
|
+
createdAt?: number;
|
|
1400
|
+
cwd?: string;
|
|
1401
|
+
};
|
|
1402
|
+
events: readonly SwitchRawEvent[];
|
|
1403
|
+
} | undefined>;
|
|
1404
|
+
}
|
|
1405
|
+
declare function rebuildIndex(activeEngine: SwitchIndexEngine, layout: SwitchIndexLayout, sessionQuery: SwitchRebuildSessionQuery, keepArchives: number, onProgress?: (done: number, total: number) => void, archiveSource?: () => SwitchArchiveSource | undefined, hooks?: SwitchRebuildHooks): Promise<SwitchRebuildState>;
|
|
1406
|
+
/** One doc-level record the snapshot importer feeds in. */
|
|
1407
|
+
interface SwitchImportRecord {
|
|
1408
|
+
sessionId: string;
|
|
1409
|
+
version: number;
|
|
1410
|
+
title?: string;
|
|
1411
|
+
/** 归档标记(旧快照缺省活跃)。 */
|
|
1412
|
+
archived?: boolean;
|
|
1413
|
+
docs: readonly {
|
|
1414
|
+
seq: number;
|
|
1415
|
+
type: string;
|
|
1416
|
+
surface: string;
|
|
1417
|
+
time: number;
|
|
1418
|
+
text: string;
|
|
1419
|
+
}[];
|
|
1420
|
+
}
|
|
1421
|
+
/** Import doc-level records into the shadow file and swap it in (same swap path). */
|
|
1422
|
+
declare function importIntoIndex(activeEngine: SwitchIndexEngine, layout: SwitchIndexLayout, records: readonly SwitchImportRecord[], keepArchives: number): Promise<SwitchRebuildState>;
|
|
1423
|
+
//#endregion
|
|
876
1424
|
//#region src/host/history/archive.d.ts
|
|
877
1425
|
/** 一行历史文件条目(尽力而为的元数据 + 磁盘占用)。 */
|
|
878
1426
|
interface StewardHistoryRow {
|
|
@@ -940,6 +1488,26 @@ interface StewardHistoryPruneResult {
|
|
|
940
1488
|
* @param searchPaths - 可选候选路径覆盖(测试注入用)。
|
|
941
1489
|
*/
|
|
942
1490
|
declare function pruneHistory(payload: unknown, log?: (msg: string) => void, searchPaths?: readonly string[]): StewardHistoryPruneResult;
|
|
1491
|
+
/** 归档结果。 */
|
|
1492
|
+
interface StewardHistoryArchiveResult {
|
|
1493
|
+
ok: boolean;
|
|
1494
|
+
/** 本次新加入归档集合的数量(已在集合中的 id 不重复计)。 */
|
|
1495
|
+
added?: number;
|
|
1496
|
+
/** 操作后归档集合总数。 */
|
|
1497
|
+
total?: number;
|
|
1498
|
+
requiresRestart?: boolean;
|
|
1499
|
+
error?: string;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* `session-history-archive`:把会话批量加入官方归档集合(prune 的逆操作)。
|
|
1503
|
+
* 与 prune 同一条纪律:校验入参 → 备份并原子替换存储文件 → 读回校验 →
|
|
1504
|
+
* 要求重启(宿主内存集合只在启动时重载)。会话文件不动、工作区成员表不动
|
|
1505
|
+
* (归档只改可见性,与宿主 archiveSession 的文件语义一致)。
|
|
1506
|
+
* @param payload - `{ sessionIds: string[] }`。
|
|
1507
|
+
* @param log - 可选日志出口。
|
|
1508
|
+
* @param searchPaths - 可选候选路径覆盖(测试注入用)。
|
|
1509
|
+
*/
|
|
1510
|
+
declare function archiveHistory(payload: unknown, log?: (msg: string) => void, searchPaths?: readonly string[]): StewardHistoryArchiveResult;
|
|
943
1511
|
//#endregion
|
|
944
1512
|
//#region src/host/history/purge.d.ts
|
|
945
1513
|
/** 一个归档会话在磁盘上的实体与占用。 */
|
|
@@ -1329,18 +1897,78 @@ declare function scanSessions(options: {
|
|
|
1329
1897
|
now?: () => number;
|
|
1330
1898
|
}): HealthScanResult;
|
|
1331
1899
|
//#endregion
|
|
1900
|
+
//#region src/host/index/snapshot.d.ts
|
|
1901
|
+
/**
|
|
1902
|
+
* Export the whole index (active AND archived) as a JSON Lines string.
|
|
1903
|
+
* 归档行带 archived 标记一起导出——快照是完整备份,不是活跃子集。
|
|
1904
|
+
* @param engine - the open active engine.
|
|
1905
|
+
* @returns the complete snapshot text (header line first).
|
|
1906
|
+
*/
|
|
1907
|
+
declare function exportSnapshot(engine: SwitchIndexEngine): string;
|
|
1908
|
+
/** One parsed snapshot: importable records plus skipped-line count. */
|
|
1909
|
+
interface SwitchParsedSnapshot {
|
|
1910
|
+
records: SwitchImportRecord[];
|
|
1911
|
+
skipped: number;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Parse a snapshot's JSON Lines text into importable records.
|
|
1915
|
+
* The header line and any malformed line are skipped, not fatal.
|
|
1916
|
+
* @param text - raw snapshot text.
|
|
1917
|
+
* @returns importable records and how many lines were skipped.
|
|
1918
|
+
*/
|
|
1919
|
+
declare function parseSnapshot(text: string): SwitchParsedSnapshot;
|
|
1920
|
+
//#endregion
|
|
1921
|
+
//#region src/host/index/peers.d.ts
|
|
1922
|
+
/** Resolution outcome for a peer plugin package. */
|
|
1923
|
+
type PeerPresence = 'installed' | 'missing' | 'unknown';
|
|
1924
|
+
/**
|
|
1925
|
+
* Probe whether a package resolves from this plugin's own module graph.
|
|
1926
|
+
*
|
|
1927
|
+
* The bundle lives at `<profile>/node_modules/dsh-search-index/lib/index.mjs`,
|
|
1928
|
+
* so resolution runs against `<profile>/node_modules` — exactly where a
|
|
1929
|
+
* profile dependency lands, and therefore the same place the host would load
|
|
1930
|
+
* the peer from.
|
|
1931
|
+
*
|
|
1932
|
+
* @param name - the package name to resolve.
|
|
1933
|
+
* @param base - resolution base; defaults to this module's own URL, i.e. the
|
|
1934
|
+
* plugin's install directory. Injectable so the classification can be tested
|
|
1935
|
+
* against a fixture that fails in a way this checkout cannot produce.
|
|
1936
|
+
* @returns `installed` when it resolves; `missing` only for a genuine
|
|
1937
|
+
* module-not-found; `unknown` for every other failure, because an
|
|
1938
|
+
* unanswerable probe is not evidence of absence.
|
|
1939
|
+
*/
|
|
1940
|
+
declare function probePeer(name: string, base?: string): PeerPresence;
|
|
1941
|
+
/**
|
|
1942
|
+
* Probe whether {@link STEWARD_PACKAGE} is installed alongside this plugin.
|
|
1943
|
+
*
|
|
1944
|
+
* @returns the resolution state, never a throw.
|
|
1945
|
+
*/
|
|
1946
|
+
declare function detectSteward(): PeerPresence;
|
|
1947
|
+
//#endregion
|
|
1332
1948
|
//#region src/index.d.ts
|
|
1333
|
-
/** 本插件声明的宿主服务(与 toggle 相同的注入面)。 */
|
|
1949
|
+
/** 本插件声明的宿主服务(与 toggle 相同的注入面)。0.2.1-a.2 起 webRuntime 更名 webStartup,读取面走双名回退链。 */
|
|
1334
1950
|
declare const inject: string[];
|
|
1335
|
-
/** 运行时配置 schema(与 src/config.ts 的形状保持一致)。0.1.7
|
|
1951
|
+
/** 运行时配置 schema(与 src/config.ts 的形状保持一致)。0.1.7+:volatile 字段即设置表单。 */
|
|
1336
1952
|
declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
1337
|
-
enabled: z<boolean, boolean, "
|
|
1338
|
-
historyFiles: z<boolean, boolean, "
|
|
1339
|
-
healthCheck: z<boolean, boolean, "
|
|
1953
|
+
enabled: z<boolean, boolean, "defined">;
|
|
1954
|
+
historyFiles: z<boolean, boolean, "defined">;
|
|
1955
|
+
healthCheck: z<boolean, boolean, "defined">;
|
|
1956
|
+
search: z<boolean, boolean, "defined">;
|
|
1957
|
+
defaultMode: z<"title" | "content", "title" | "content", "defined">;
|
|
1958
|
+
autoSync: z<boolean, boolean, "defined">;
|
|
1959
|
+
syncIntervalMs: z<number, number, "defined">;
|
|
1960
|
+
archiveKeep: z<number, number, "defined">;
|
|
1961
|
+
indexDir: z<string, string, "defined">;
|
|
1340
1962
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
1341
|
-
enabled: z<boolean, boolean, "
|
|
1342
|
-
historyFiles: z<boolean, boolean, "
|
|
1343
|
-
healthCheck: z<boolean, boolean, "
|
|
1963
|
+
enabled: z<boolean, boolean, "defined">;
|
|
1964
|
+
historyFiles: z<boolean, boolean, "defined">;
|
|
1965
|
+
healthCheck: z<boolean, boolean, "defined">;
|
|
1966
|
+
search: z<boolean, boolean, "defined">;
|
|
1967
|
+
defaultMode: z<"title" | "content", "title" | "content", "defined">;
|
|
1968
|
+
autoSync: z<boolean, boolean, "defined">;
|
|
1969
|
+
syncIntervalMs: z<number, number, "defined">;
|
|
1970
|
+
archiveKeep: z<number, number, "defined">;
|
|
1971
|
+
indexDir: z<string, string, "defined">;
|
|
1344
1972
|
}>>, "plain">;
|
|
1345
1973
|
/** 运行时依赖。 */
|
|
1346
1974
|
interface StewardRuntime {
|
|
@@ -1361,6 +1989,23 @@ interface StewardRuntime {
|
|
|
1361
1989
|
* 不影响任何判定结果)。`apply()` 总是提供实例。
|
|
1362
1990
|
*/
|
|
1363
1991
|
cache?: HealthCache;
|
|
1992
|
+
/**
|
|
1993
|
+
* Legacy 设置桥(≤0.1.5;可选):老宿主 settings 服务的 register/get/update
|
|
1994
|
+
* 租约。缺省(单测/modern 宿主)= describe 回空投影、mutate 显式拒绝。
|
|
1995
|
+
*/
|
|
1996
|
+
settingsBridge?: BridgeState;
|
|
1997
|
+
/**
|
|
1998
|
+
* 搜索索引联动钩子(可选):管家写侧操作成功后同步翻索引的归档标记 /
|
|
1999
|
+
* 删除索引行,消灭"搜索还挂着 30s 前的幽灵"的窗口。缺省(单测/降级)为无联动。
|
|
2000
|
+
*/
|
|
2001
|
+
index?: {
|
|
2002
|
+
/** 批量归档成功 → 翻 archived=true。 */
|
|
2003
|
+
onArchive: (sessionIds: readonly string[]) => void;
|
|
2004
|
+
/** 取消归档成功 → 翻 archived=false。 */
|
|
2005
|
+
onUnarchive: (sessionIds: readonly string[]) => void;
|
|
2006
|
+
/** 清理成功(物理删除)→ 索引行整个移除。 */
|
|
2007
|
+
onPurged: (sessionIds: readonly string[]) => void;
|
|
2008
|
+
};
|
|
1364
2009
|
}
|
|
1365
2010
|
/**
|
|
1366
2011
|
* 支持的路由方法(按子域分组;用于对外声明与测试断言)。
|
|
@@ -1368,22 +2013,107 @@ interface StewardRuntime {
|
|
|
1368
2013
|
* `session-history-prune` 与 `session-history-purge` 是**两件事**,不可合并:
|
|
1369
2014
|
* prune = 取消归档状态(可逆,会话回到侧边栏);purge = 清理归档文件(不可逆,真删实体)。
|
|
1370
2015
|
*/
|
|
1371
|
-
declare const HISTORY_METHODS: readonly ["session-history-list", "session-history-prune", "session-history-purge"];
|
|
2016
|
+
declare const HISTORY_METHODS: readonly ["session-history-list", "session-history-archive", "session-history-prune", "session-history-purge", "session-history-favorites-list", "session-history-favorite-set"];
|
|
1372
2017
|
declare const HEALTH_METHODS: readonly ["session-health-status", "session-health-scan", "session-health-session", "session-health-repair", "session-health-source-migrate"];
|
|
2018
|
+
/** 搜索索引子域方法(`/switch-search/api`;index-export/import 走原始体,其余 JSON)。 */
|
|
2019
|
+
declare const INDEX_METHODS: readonly ["list-sessions", "content-search", "search-status", "index-status", "index-rebuild", "index-export", "index-import"];
|
|
1373
2020
|
/** 依据开关判定某方法是否启用。 */
|
|
1374
2021
|
declare function methodEnabled(method: string, config: Required<StewardConfig>): boolean;
|
|
2022
|
+
/** ------------------------------------------------------------------ 搜索子域 handlers */
|
|
1375
2023
|
/**
|
|
1376
|
-
*
|
|
1377
|
-
* @param method - 路由方法名。
|
|
1378
|
-
* @param payload - 已解析的请求体。
|
|
1379
|
-
* @param runtime - 运行时依赖。
|
|
2024
|
+
* One session header shape the query service returns (structural subset).
|
|
1380
2025
|
*/
|
|
2026
|
+
interface SwitchSessionHeader {
|
|
2027
|
+
id: string;
|
|
2028
|
+
version: number;
|
|
2029
|
+
createdAt: number;
|
|
2030
|
+
cwd?: string;
|
|
2031
|
+
parentSession?: string;
|
|
2032
|
+
seedLength?: number;
|
|
2033
|
+
delegationDepth?: number;
|
|
2034
|
+
agentPreset?: string;
|
|
2035
|
+
}
|
|
2036
|
+
/** One logical-session record (structural subset). */
|
|
2037
|
+
interface SwitchSessionRecord {
|
|
2038
|
+
header: SwitchSessionHeader;
|
|
2039
|
+
live: boolean;
|
|
2040
|
+
persisted: boolean;
|
|
2041
|
+
}
|
|
2042
|
+
/** One title observation result (structural subset). */
|
|
2043
|
+
interface SwitchTitleObservationResult {
|
|
2044
|
+
status: 'fulfilled' | 'rejected';
|
|
2045
|
+
value?: {
|
|
2046
|
+
session: SwitchSessionHeader;
|
|
2047
|
+
title?: {
|
|
2048
|
+
title: string;
|
|
2049
|
+
};
|
|
2050
|
+
};
|
|
2051
|
+
reason?: unknown;
|
|
2052
|
+
}
|
|
2053
|
+
/** The session-query service face: corpus reads, title folding, FTS5 search. */
|
|
2054
|
+
interface SwitchSessionQuery {
|
|
2055
|
+
listSessions(signal?: AbortSignal): Promise<readonly SwitchSessionRecord[]>;
|
|
2056
|
+
readSession?(sessionId: string): Promise<{
|
|
2057
|
+
session: SwitchSessionHeader;
|
|
2058
|
+
events: readonly SwitchRawEvent[];
|
|
2059
|
+
}>;
|
|
2060
|
+
readTitleSnapshots(sessionIds: readonly string[], signal?: AbortSignal): Promise<readonly SwitchTitleObservationResult[]>;
|
|
2061
|
+
searchSessions?(request: {
|
|
2062
|
+
query: string;
|
|
2063
|
+
eventFilters?: readonly unknown[];
|
|
2064
|
+
limit?: number;
|
|
2065
|
+
}, exec?: {
|
|
2066
|
+
signal?: AbortSignal;
|
|
2067
|
+
}): Promise<{
|
|
2068
|
+
items: readonly unknown[];
|
|
2069
|
+
nextCursor?: string;
|
|
2070
|
+
}>;
|
|
2071
|
+
}
|
|
2072
|
+
/** ------------------------------------------------------------------ index service */
|
|
2073
|
+
/** The per-activation index service state, carried in the apply closure. */
|
|
2074
|
+
interface SwitchIndexServiceState {
|
|
2075
|
+
engine: SwitchIndexEngine;
|
|
2076
|
+
sync: SwitchWatermarkSync;
|
|
2077
|
+
layout: SwitchIndexLayout;
|
|
2078
|
+
rebuild: SwitchRebuildState;
|
|
2079
|
+
/** Official archive-set reader (registry first, storage-hub file fallback). */
|
|
2080
|
+
archiveReader: ReturnType<typeof createArchiveSource>;
|
|
2081
|
+
}
|
|
2082
|
+
/**
|
|
2083
|
+
* Everything the search handlers need, captured from the apply closure: the
|
|
2084
|
+
* optional live sessionQuery, the index service state, and the latest config.
|
|
2085
|
+
* Handlers never touch the cordis context — arbitrary property writes on a
|
|
2086
|
+
* Context are rejected ("cannot set property ... without provide").
|
|
2087
|
+
*/
|
|
2088
|
+
interface SearchRuntime {
|
|
2089
|
+
sessionQuery: SwitchSessionQuery | undefined;
|
|
2090
|
+
index: SwitchIndexServiceState;
|
|
2091
|
+
config: () => Required<StewardConfig> & SwitchSearchConfig;
|
|
2092
|
+
/** Lazy official archive-set source (registry first, file fallback). */
|
|
2093
|
+
registry: () => {
|
|
2094
|
+
archivedSessionIds: readonly string[];
|
|
2095
|
+
};
|
|
2096
|
+
/** Cordis logger bridge ([session-steward] prefixed). */
|
|
2097
|
+
log: (msg: string) => void;
|
|
2098
|
+
/** 文件级兜底读取器(重建钩子透传;见 SwitchWatermarkSync 注释)。 */
|
|
2099
|
+
readSessionFromFile: (sessionId: string) => Promise<{
|
|
2100
|
+
session: {
|
|
2101
|
+
id: string;
|
|
2102
|
+
version: number;
|
|
2103
|
+
createdAt?: number;
|
|
2104
|
+
cwd?: string;
|
|
2105
|
+
};
|
|
2106
|
+
events: readonly SwitchRawEvent[];
|
|
2107
|
+
} | undefined>;
|
|
2108
|
+
}
|
|
2109
|
+
/** JSON 面的搜索子域方法分发(index-export/import 走原始体,在路由层特判)。 */
|
|
2110
|
+
declare function handleIndexMethod(method: string, payload: unknown, srt: SearchRuntime): Promise<unknown>;
|
|
1381
2111
|
declare function handleMethod(method: string, payload: unknown, runtime: StewardRuntime): Promise<unknown>;
|
|
1382
2112
|
/**
|
|
1383
|
-
*
|
|
1384
|
-
* @param ctx - host 插件上下文(webServer / webRuntime
|
|
2113
|
+
* 插件主体:装配运行时、挂载两条 fenced 路由与索引生命周期。
|
|
2114
|
+
* @param ctx - host 插件上下文(webServer / webStartup(旧名 webRuntime)/ 可选 sessionQuery、workspaceRegistry)。
|
|
1385
2115
|
* @param config - 组合条目(0.1.7:`.volatile()` 字段为 live ref)。
|
|
1386
2116
|
*/
|
|
1387
|
-
declare function apply(ctx: Context, config?: Partial<StewardConfig>): void;
|
|
2117
|
+
declare function apply(ctx: Context, config?: Partial<StewardConfig & SwitchSearchConfig>): void;
|
|
1388
2118
|
//#endregion
|
|
1389
|
-
export { Config, DEFAULT_CONFIG, type DiscoveredSession, type GenerationArtifact, HEALTH_METHODS, HISTORY_METHODS, HealthCache, type HealthCacheEntry, type LogArtifact, type LogCompression, type RepairAssessment, type RepairVerdict, SOURCE_MIGRATE_BACKUP_SUFFIX, STEWARD_API_PREFIX, STEWARD_SETTINGS_NAMESPACE, type SessionGenerations, type SessionPriority, type StewardConfig, StewardRuntime, V4_HOST_MIN, apply, assessRepair, backupFilesIn, buildProjectionOwnerIndex, buildSessionReport, classifyGenerationFilename, countCorpus, createAttributor, decodeSessionLogBytes, decodeSessionLogFile, dirSize, discoverSessions, editWorkspaceDocument, findSession, findSessionLog, firstLosslessViolation, gateColdRead, gateGeneration, gateLogIntegrity, gateLosslessJson, gateProjectionCache, gateSourceKind, generationLogFilename, handleMethod, indexSessionDirs, inject, isLossless, isMigrationStagingFilename, isSafeChild, isSourceMigrateBackupName, latestArtifactMtime, listHistory, locateSessionUsage, methodEnabled, migrateLegacySource, migrateSessionSourceKind, parseGenerationLogFilename, prescribe, projCacheRootFor, pruneArchiveFile, pruneHistory, purgeHistory, quarantineProjectionCache, readArchiveSet, readProjectionCache, readSessionGenerations, readSourceKindFacts, readTailFacts, scanSessions, scanZstdFrames, sessionPriority, sessionsRootFor };
|
|
2119
|
+
export { Config, DEFAULT_CONFIG, DEFAULT_INDEX_LAYOUT, type DiscoveredSession, type GenerationArtifact, HEALTH_METHODS, HISTORY_METHODS, HealthCache, type HealthCacheEntry, INDEX_METHODS, type LogArtifact, type LogCompression, type RepairAssessment, type RepairVerdict, SOURCE_MIGRATE_BACKUP_SUFFIX, STEWARD_API_PREFIX, STEWARD_SETTINGS_NAMESPACE, SWITCH_API_PREFIX, SWITCH_DEFAULT_CONFIG, SearchRuntime, type SessionGenerations, type SessionPriority, type StewardConfig, StewardRuntime, type SwitchArchiveDiagnostics, SwitchIndexEngine, SwitchIndexServiceState, type SwitchSearchConfig, SwitchWatermarkSync, V4_HOST_MIN, apply, archiveArchiveFile, archiveHistory, assessRepair, backupFilesIn, buildProjectionOwnerIndex, buildSessionReport, classifyGenerationFilename, countCorpus, createArchiveSource, createAttributor, decodeSessionLogBytes, decodeSessionLogFile, detectSteward, dirSize, discoverSessions, editWorkspaceDocument, exportSnapshot, extractTitleFromEvents, findSession, findSessionLog, firstLosslessViolation, gateColdRead, gateGeneration, gateLogIntegrity, gateLosslessJson, gateProjectionCache, gateSourceKind, generationLogFilename, handleIndexMethod, handleMethod, importIntoIndex, indexSessionDirs, inject, isLossless, isMigrationStagingFilename, isSafeChild, isSourceMigrateBackupName, latestArtifactMtime, listHistory, locateSessionUsage, methodEnabled, migrateLegacySource, migrateSessionSourceKind, parseGenerationLogFilename, parseSnapshot, prescribe, probePeer, projCacheRootFor, pruneArchiveFile, pruneHistory, purgeHistory, quarantineProjectionCache, readArchiveSet, readProjectionCache, readSessionGenerations, readSourceKindFacts, readTailFacts, rebuildIndex, recoverIndex, scanSessions, scanZstdFrames, sessionPriority, sessionsRootFor };
|