@morlay/session-rdb 0.1.10-alpha.0 → 0.1.10-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +18 -3
  2. package/dist/artifact.d.mts +118 -2
  3. package/dist/artifact.mjs +5 -3
  4. package/dist/{log-TYgd8Xkr.d.mts → backend-BKtJ5sO5.d.mts} +183 -284
  5. package/dist/backend-rdb-BDCntVDy.mjs +1341 -0
  6. package/dist/branch-CG1PUlO6.mjs +833 -0
  7. package/dist/deletion-SSX7IqU8.mjs +35 -0
  8. package/dist/deletion.d.mts +1 -1
  9. package/dist/deletion.mjs +2 -2
  10. package/dist/export-CfJQjQfr.mjs +123 -0
  11. package/dist/export.d.mts +1 -1
  12. package/dist/export.mjs +31 -55
  13. package/dist/import.d.mts +1 -1
  14. package/dist/import.mjs +31 -76
  15. package/dist/index-CUD2ZpTA.d.mts +71 -0
  16. package/dist/index.d.mts +20 -2
  17. package/dist/index.mjs +1561 -4
  18. package/dist/open-YoyD_kah.mjs +561 -0
  19. package/dist/organize.d.mts +9 -0
  20. package/dist/organize.mjs +30 -0
  21. package/dist/route-DpfY0zq-.mjs +114 -0
  22. package/dist/storage.d.mts +41 -48
  23. package/dist/storage.mjs +3 -1
  24. package/dist/testing.d.mts +9 -1
  25. package/dist/testing.mjs +25 -4
  26. package/dist/usage-row-BQQM-_t6.mjs +36 -0
  27. package/dist/usage.d.mts +1 -1
  28. package/dist/usage.mjs +7 -40
  29. package/dist/write-guard-CYrY58GM.mjs +174 -0
  30. package/package.json +32 -36
  31. package/src/artifact.ts +4 -1
  32. package/src/backend-rdb.ts +331 -0
  33. package/src/backend.ts +32 -15
  34. package/src/{branch.ts → branch/index.ts} +109 -110
  35. package/src/branch/port.ts +62 -0
  36. package/src/branch/semantics.ts +69 -0
  37. package/src/db/open.ts +180 -0
  38. package/src/db/stats.ts +449 -0
  39. package/src/deletion-error.ts +17 -0
  40. package/src/deletion.ts +19 -72
  41. package/src/entities/index.ts +16 -1
  42. package/src/entities/v3/event-usage.ts +3 -3
  43. package/src/entities/v3/events.ts +3 -3
  44. package/src/entities/v3/index.ts +4 -16
  45. package/src/entities/v3/persistence-state.ts +3 -3
  46. package/src/entities/v3/schema-meta.ts +3 -3
  47. package/src/entities/v3/session-counts.ts +3 -3
  48. package/src/entities/v3/session-events.ts +3 -3
  49. package/src/entities/v3/session-projcache-rows.ts +3 -3
  50. package/src/entities/v3/session-usage.ts +3 -3
  51. package/src/entities/v3/sessions.ts +3 -3
  52. package/src/entities/v3/storage-records.ts +17 -0
  53. package/src/entities/v3/storage-units.ts +3 -3
  54. package/src/{schema.ts → event-shape.ts} +0 -46
  55. package/src/export.ts +32 -78
  56. package/src/handles.ts +349 -0
  57. package/src/http/route.ts +178 -0
  58. package/src/import-storages.ts +5 -2
  59. package/src/import.ts +63 -125
  60. package/src/index.ts +15 -1666
  61. package/src/legacy.ts +3 -1
  62. package/src/live-routing.ts +205 -0
  63. package/src/log/export.ts +84 -0
  64. package/src/{log.ts → log/repair.ts} +1 -268
  65. package/src/log/rows.ts +107 -0
  66. package/src/log/usage-row.ts +64 -0
  67. package/src/migrations.ts +196 -0
  68. package/src/organize.ts +38 -0
  69. package/src/read-path.ts +190 -0
  70. package/src/routes.ts +2 -1
  71. package/src/rows.ts +25 -77
  72. package/src/session-ops.ts +444 -0
  73. package/src/session-store.ts +675 -0
  74. package/src/stats-fold.ts +44 -0
  75. package/src/storage-takeover/index.ts +2 -5
  76. package/src/storage-takeover/legacy-domain-migration.ts +118 -0
  77. package/src/storage-takeover/projection-cache.ts +122 -71
  78. package/src/storage-takeover/read-model.ts +189 -0
  79. package/src/storage-takeover/repository.ts +236 -442
  80. package/src/storage-takeover/storage-backend.ts +44 -159
  81. package/src/storage-takeover/types.ts +45 -19
  82. package/src/storage-takeover/workspace-documents.ts +65 -0
  83. package/src/storage.ts +4 -2
  84. package/src/testing.ts +21 -1
  85. package/src/usage.ts +11 -65
  86. package/src/version.ts +13 -0
  87. package/src/write-path.ts +286 -0
  88. package/dist/branch-CoPCRKer.mjs +0 -401
  89. package/dist/deletion-CWl89TIR.mjs +0 -2249
  90. package/dist/gc.d.mts +0 -4
  91. package/dist/gc.mjs +0 -48
  92. package/dist/log-CcWy46VE.mjs +0 -558
  93. package/dist/routes-hZjTcX_R.mjs +0 -9
  94. package/dist/sqlite-BNRd1aqR.mjs +0 -1778
  95. package/drizzle/postgres/20260908072805_v2_initial/migration.sql +0 -58
  96. package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +0 -686
  97. package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +0 -1
  98. package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +0 -673
  99. package/drizzle/postgres/20260910120001_v3_storage_tables/migration.sql +0 -65
  100. package/drizzle/postgres/20260910120001_v3_storage_tables/snapshot.json +0 -1183
  101. package/drizzle/postgres/20260910130001_v3_session_title_backfill/migration.sql +0 -10
  102. package/drizzle/postgres/20260910130001_v3_session_title_backfill/snapshot.json +0 -1183
  103. package/drizzle/postgres/20260918120000_v3_event_usage/migration.sql +0 -14
  104. package/drizzle/postgres/20260918120000_v3_event_usage/snapshot.json +0 -1309
  105. package/drizzle/postgres/20260921075900_v3_agent_preset/migration.sql +0 -1
  106. package/drizzle/postgres/20260922090001_v3_pinned_seq/migration.sql +0 -2
  107. package/drizzle/postgres/20260922093001_v3_last_event_at/migration.sql +0 -10
  108. package/drizzle/postgres/20260923120000_v3_usage_materialized/migration.sql +0 -48
  109. package/drizzle/postgres/20261008103001_v3_schedule_tasks/migration.sql +0 -11
  110. package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +0 -53
  111. package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +0 -492
  112. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +0 -6
  113. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +0 -513
  114. package/drizzle/sqlite/20260910120000_v3_storage_tables/migration.sql +0 -66
  115. package/drizzle/sqlite/20260910120000_v3_storage_tables/snapshot.json +0 -905
  116. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/migration.sql +0 -13
  117. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/snapshot.json +0 -905
  118. package/drizzle/sqlite/20260918120000_v3_event_usage/migration.sql +0 -14
  119. package/drizzle/sqlite/20260918120000_v3_event_usage/snapshot.json +0 -1031
  120. package/drizzle/sqlite/20260921075855_v3_agent_preset/migration.sql +0 -7
  121. package/drizzle/sqlite/20260921075855_v3_agent_preset/snapshot.json +0 -1041
  122. package/drizzle/sqlite/20260922090000_v3_pinned_seq/migration.sql +0 -4
  123. package/drizzle/sqlite/20260922093000_v3_last_event_at/migration.sql +0 -13
  124. package/drizzle/sqlite/20260923120000_v3_usage_materialized/migration.sql +0 -48
  125. package/drizzle/sqlite/20261008103000_v3_schedule_tasks/migration.sql +0 -14
  126. package/src/adapters/index.ts +0 -12
  127. package/src/adapters/to-postgres.ts +0 -93
  128. package/src/adapters/to-sqlite.ts +0 -83
  129. package/src/adapters/types.ts +0 -44
  130. package/src/drizzle/postgres-v2.ts +0 -10
  131. package/src/drizzle/postgres-v3.ts +0 -18
  132. package/src/drizzle/sqlite-v2.ts +0 -9
  133. package/src/drizzle/sqlite-v3.ts +0 -18
  134. package/src/entities/v2/index.ts +0 -20
  135. package/src/entities/v2/session-events.ts +0 -10
  136. package/src/entities/v3/schedule-tasks.ts +0 -16
  137. package/src/entities/v3/workspace-sessions.ts +0 -19
  138. package/src/entities/v3/workspace-state.ts +0 -12
  139. package/src/entities/v3/workspaces.ts +0 -14
  140. package/src/gc.ts +0 -77
  141. package/src/postgres.ts +0 -1015
  142. package/src/sqlite.ts +0 -1096
@@ -1,51 +1,79 @@
1
- import { Session, SessionEvent, SessionHeader, SessionId, SessionLogOffset } from "@deepseek-ai/dsh-session";
1
+ import { Database } from "@morlay/rdbkit";
2
+ import { SessionEvent, SessionHeader, SessionId, SessionLogOffset } from "@deepseek-ai/dsh-session";
2
3
  import { SessionAccess, SessionHandle, SessionHandleAppendOptions, SessionHandleFlushOptions, SessionHandleReadOptions, SessionHandleReadResult, SessionPersistence, SessionPersistenceCreateOptions, SessionPersistenceListOptions, SessionPersistenceOpenOptions, SessionPersistenceRevision, SessionPersistenceSnapshot, SessionPersistenceStatOptions, SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
3
- import { ScheduleTask } from "@deepseek-ai/dsh-schedule";
4
+ import "@deepseek-ai/dsh-schedule";
4
5
  import { CheckpointIdentity } from "@deepseek-ai/dsh-session-projection-cache";
5
6
  import { ProjectionCheckpoint } from "@deepseek-ai/dsh-session-projection";
6
- import { WorkspaceDomainState, WorkspaceRecord } from "@deepseek-ai/dsh-workspace";
7
+ import "@deepseek-ai/dsh-workspace";
7
8
  import { Context } from "@deepseek-ai/cordis";
8
9
  import { Volatile } from "@deepseek-ai/cosmokit";
9
10
  import z from "@deepseek-ai/schemastery";
10
- import { BranchAnchorMode, BranchBoundary, ForkFromOptions, SessionBranch, SessionBranchProvider } from "@morlay/session-branch";
11
+ interface EventUsageRow {
12
+ fEventId: string;
13
+ fCreatedAt: number;
14
+ fDay: string;
15
+ fProvider: string | null;
16
+ fModel: string | null;
17
+ fReferenced: number;
18
+ fSubagent: number;
19
+ fInputTokens: number;
20
+ fOutputTokens: number;
21
+ fCacheReadTokens: number;
22
+ fReasoningTokens: number;
23
+ fTotalTokens: number;
24
+ }
25
+ declare function usageRowOf(event: {
26
+ fEventId: string;
27
+ fCreatedAt: number;
28
+ fType: string;
29
+ fData: string;
30
+ }, subagent: boolean): EventUsageRow | undefined;
31
+ interface DomainRecord {
32
+ table: string;
33
+ key: string;
34
+ value: unknown;
35
+ }
36
+ interface WorkspaceIndexEntry {
37
+ id: string;
38
+ title: string;
39
+ sessionIds: string[];
40
+ }
11
41
  interface StoredProjcacheEntry {
12
42
  sessionId: SessionId;
13
43
  identity: CheckpointIdentity;
14
44
  rows: ProjectionCheckpoint;
45
+ /** 会话标题(随快照一起加载 / 写路径刷新;`cachedSnapshot` 缺标题时用它补,不回库直读)。 */
46
+ title?: {
47
+ title: string;
48
+ seq: number;
49
+ };
15
50
  }
16
51
  interface StorageRepository {
17
52
  readUnitVersion(name: string): Promise<number | undefined>;
18
53
  insertUnitVersion(name: string, version: number): Promise<void>;
19
- listWorkspaces(): Promise<Array<{
20
- id: string;
21
- record: WorkspaceRecord;
22
- }>>;
23
- putWorkspace(id: string, record: WorkspaceRecord): Promise<void>;
24
- deleteWorkspace(id: string): Promise<void>;
25
- deleteWorkspaces(ids: readonly string[]): Promise<void>;
26
- readWorkspaceState(): Promise<WorkspaceDomainState | null>;
27
- writeWorkspaceState(state: WorkspaceDomainState): Promise<void>;
28
- listScheduleTasks(): Promise<Array<{
29
- id: string;
30
- task: ScheduleTask;
31
- }>>;
32
- putScheduleTask(id: string, task: ScheduleTask): Promise<void>;
33
- deleteScheduleTask(id: string): Promise<void>;
34
- deleteScheduleTasks(ids: readonly string[]): Promise<void>;
54
+ listDomainRecords(domain: string): Promise<DomainRecord[]>;
55
+ readDomainGlobal(domain: string): Promise<unknown>;
56
+ putDomainRecord(domain: string, table: string, key: string, value: unknown): Promise<void>;
57
+ deleteDomainRecord(domain: string, table: string, key: string): Promise<void>;
58
+ deleteDomainRecords(domain: string, table: string, keys: readonly string[]): Promise<void>;
59
+ writeDomainGlobal(domain: string, value: unknown): Promise<void>;
60
+ listWorkspaceIndex(): Promise<WorkspaceIndexEntry[]>;
35
61
  loadProjcache(): Promise<StoredProjcacheEntry[]>;
36
- readProjcacheDirect?(sessionId: string): StoredProjcacheEntry | undefined;
37
- readSessionTitleDirect?(sessionId: string): {
62
+ /** 会话标题(投影缓存的镜像刷新与 `cachedSnapshot` 补标题用)。 */
63
+ readSessionTitle(sessionId: string): Promise<{
38
64
  title: string;
39
65
  seq: number;
40
- } | undefined;
66
+ } | undefined>;
41
67
  putProjcache(sessionId: string, rows: ProjectionCheckpoint): Promise<void>;
68
+ /** 增量写回:只 upsert `changed` 里的行、删掉 `removedKeys`,其余行原样不动。 */
69
+ patchProjcache(sessionId: string, changed: ProjectionCheckpoint, removedKeys: readonly string[]): Promise<void>;
42
70
  pruneStaleProjcache(): Promise<number>;
43
71
  }
44
72
  declare const SESSION_ROWS_PATH = "/api/morlay/v1/session/rows";
45
73
  declare const SESSION_EXPORT_PATH = "/api/morlay/v1/session/export";
46
74
  declare const SESSION_IMPORT_PATH = "/api/morlay/v1/session/import";
47
75
  declare const SESSION_DELETE_PATH = "/api/morlay/v1/session/delete";
48
- declare const SESSION_GC_PATH = "/api/morlay/v1/session/gc";
76
+ declare const SESSION_ORGANIZE_PATH = "/api/morlay/v1/session/organize";
49
77
  declare const SESSION_USAGE_PATH = "/api/morlay/v1/session/usage";
50
78
  declare class WriteGuard {
51
79
  private readonly headSeqs;
@@ -53,160 +81,6 @@ declare class WriteGuard {
53
81
  has(id: SessionId): boolean;
54
82
  assertNoConcurrentWriter(id: SessionId, storedHead: number): void;
55
83
  }
56
- declare const SCHEMA_VERSION = 3;
57
- declare const SESSION_PERSISTENCE_SQLITE_APPLICATION_ID = 1146308688;
58
- declare const EVENT_ENCODING = "json";
59
- declare const tPersistenceState: any;
60
- declare const tSchemaMeta: any;
61
- declare const tSessions: any;
62
- declare const tEvents: any;
63
- declare const tSessionEvents: any;
64
- declare const tStorageUnits: any;
65
- declare const tWorkspaces: any;
66
- declare const tWorkspaceSessions: any;
67
- declare const tWorkspaceState: any;
68
- declare const tScheduleTasks: any;
69
- declare const tSessionProjcacheRows: any;
70
- declare const tEventUsage: any;
71
- declare const tSessionUsage: any;
72
- declare const tSessionCounts: any;
73
- type JournalMode = "wal" | "delete" | "truncate" | "persist";
74
- declare const DEFAULT_BUSY_TIMEOUT_MS = 5000;
75
- type EventKind = "message" | "thinking" | "turn" | "tool" | "request" | "config" | "audit" | "lifecycle" | "inbox" | "compaction" | "llm" | "subagent" | "team" | "workflow" | "goal" | "schedule" | "todo" | "web";
76
- type EventRole = "user" | "assistant" | "tool";
77
- declare function eventKind(event: {
78
- type: string;
79
- data?: unknown;
80
- }): EventKind | "";
81
- declare function eventDimensions(event: SessionEvent): {
82
- kind: string;
83
- role: string;
84
- name: string;
85
- actionId: string;
86
- };
87
- interface SessionRowsItem {
88
- sessionId: string;
89
- title: string | null;
90
- origin: string | null;
91
- cwd: string | null;
92
- createdAt: number;
93
- updatedAt: number;
94
- archived: boolean;
95
- workspace: string | null;
96
- }
97
- interface SessionRowsValue {
98
- items: SessionRowsItem[];
99
- total: number;
100
- page: number;
101
- pageSize: number;
102
- }
103
- declare function locateTurnEnd(events: readonly SessionEvent[], atSeq?: number, mode?: BranchAnchorMode): number;
104
- interface LiveSessionHooks {
105
- getSession(id: SessionId): Session | undefined;
106
- getAgent(id: SessionId): LiveAgentLike | undefined;
107
- flush(session: Session): Promise<boolean>;
108
- warn?(message: string): void;
109
- resetProjections?(session: Session): void;
110
- resetTokenMeter?(session: Session): void;
111
- refreshProjectionCache?(session: ProjectionCacheSession): Promise<void>;
112
- }
113
- interface ProjectionCacheSession {
114
- readonly id: SessionId;
115
- readonly header: SessionHeader;
116
- readonly inheritedEventCount: SessionLogOffset;
117
- readonly headSeq?: number;
118
- snapshotEvents(): readonly SessionEvent[];
119
- }
120
- interface LiveAgentLike {
121
- session: Session;
122
- requestHeaderLogged?: boolean;
123
- inbox?: {
124
- clear(): void;
125
- };
126
- }
127
- /**
128
- * 会话**当前内存 log** 的快照(复制一份)。用于"需要完整序列"的操作(首次落库的 seed、rewind / fork 的历史),
129
- * 不走已弃用的同步历史读 `snapshotEvents()`——那三个读口上游已声明「新调用禁止」,而这里要的是当前内存里
130
- * 那份完整日志,不是按需分页的历史。
131
- * @param session - 会话。
132
- * @returns 事件副本(调用方可以自由遍历)。
133
- */
134
- declare function liveEventsOf(session: Session): readonly SessionEvent[];
135
- /** @returns 截断后日志里最后一个 `turn/start` 的 turn 号(没有则 0)。 */
136
- declare function truncateLiveSession(session: Session, newLength: number): number;
137
- declare class SessionBranchRdbProvider implements SessionBranchProvider {
138
- private readonly persistence;
139
- private readonly live;
140
- readonly name = "session-rdb";
141
- constructor(persistence: SessionPersistenceRdb, live?: LiveSessionHooks);
142
- readBranchPrefix(id: SessionId, atSeq?: number, mode?: BranchAnchorMode, signal?: AbortSignal): Promise<BranchBoundary>;
143
- readRawEvents(id: SessionId, signal?: AbortSignal): Promise<{
144
- meta: SessionHeader;
145
- events: readonly SessionEvent[];
146
- }>;
147
- forkFrom(sourceId: SessionId, options?: ForkFromOptions, signal?: AbortSignal): Promise<SessionId>;
148
- rewind(id: SessionId, toBoundary: number, signal?: AbortSignal): Promise<SessionPersistenceSnapshot>;
149
- private rewindKeepLength;
150
- private refreshProjectionCache;
151
- }
152
- declare class SessionBranchRdb extends SessionBranch {
153
- static inject: string[];
154
- private readonly warned;
155
- constructor(ctx: import("@deepseek-ai/cordis").Context);
156
- resetLiveDerivedState(session: Session): void;
157
- private warnOnce;
158
- private resetProjectionCells;
159
- private resetTokenMeterFold;
160
- private readonly provider;
161
- readBranchPrefix(id: SessionId, atSeq?: number, mode?: BranchAnchorMode, signal?: AbortSignal): Promise<BranchBoundary>;
162
- readRawEvents(id: SessionId, signal?: AbortSignal): Promise<{
163
- meta: SessionHeader;
164
- events: readonly SessionEvent[];
165
- }>;
166
- forkFrom(sourceId: SessionId, options?: ForkFromOptions, signal?: AbortSignal): Promise<SessionId>;
167
- rewind(id: SessionId, toBoundary: number, signal?: AbortSignal): Promise<SessionPersistenceSnapshot>;
168
- }
169
- interface SessionPersistenceRdbInternals {
170
- readonly backend: Backend;
171
- readonly writeGuard: WriteGuard;
172
- create(meta: SessionHeader, inheritedEventCount?: number): Promise<SessionHandle>;
173
- append(id: SessionId, events: readonly SessionEvent[]): Promise<void>;
174
- load(id: SessionId): Promise<import("@deepseek-ai/dsh-session-persistence").SessionInspection>;
175
- inspect(id: SessionId, signal?: AbortSignal): Promise<import("@deepseek-ai/dsh-session-persistence").SessionInspection>;
176
- readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{
177
- meta: SessionHeader;
178
- inheritedEventCount: number;
179
- events: readonly SessionEvent[];
180
- }>;
181
- listSnapshots(signal?: AbortSignal): Promise<SessionPersistenceSnapshot[]>;
182
- readStoredRevision(id: SessionId, signal?: AbortSignal): Promise<import("@deepseek-ai/dsh-session-persistence").SessionPersistenceRevision | undefined>;
183
- registerReuseEventIds(childId: SessionId, map: ReadonlyMap<number, string>): void;
184
- dropReuseEventIds(childId: SessionId): void;
185
- }
186
- interface ProjectionCacheOptions {
187
- writeEveryEvents?: number;
188
- writeIntervalMs?: number;
189
- }
190
- type Config = {
191
- type: "sqlite";
192
- path: string;
193
- journalMode?: JournalMode | undefined;
194
- busyTimeout?: number | undefined;
195
- projectionCache?: ProjectionCacheOptions | undefined;
196
- preparedSessionCacheSize?: number | undefined;
197
- } | {
198
- type: "postgres";
199
- connectionString: string;
200
- schema?: string | undefined;
201
- projectionCache?: ProjectionCacheOptions | undefined;
202
- preparedSessionCacheSize?: number | undefined;
203
- };
204
- type ResolvedConfig = Volatile<Config>;
205
- type SessionDeletionErrorCode = "SESSION_NOT_FOUND" | "SESSION_NOT_ARCHIVED" | "SESSION_LIVE";
206
- declare class SessionDeletionError extends Error {
207
- readonly code: SessionDeletionErrorCode;
208
- constructor(message: string, code: SessionDeletionErrorCode);
209
- }
210
84
  interface PendingSession {
211
85
  readonly header: SessionHeader;
212
86
  readonly revision: SessionPersistenceRevision;
@@ -274,20 +148,99 @@ declare class RdbSessionHandle implements SessionHandle {
274
148
  private assertOpen;
275
149
  static readonly LIVE_WRITE_BATCH_MAX_DELAY_MS = 200;
276
150
  }
151
+ /** 库结构版本(写入 SQLite 的 `user_version`,不匹配即拒绝打开)。 */
152
+ declare const SCHEMA_VERSION = 3;
153
+ /** SQLite 文件头的 application id(`0x44534850` = "DSHP"),防止误开别的库。 */
154
+ declare const SESSION_PERSISTENCE_SQLITE_APPLICATION_ID = 1146308688;
155
+ /** 事件 `f_data` 的编码(目前只有 JSON)。 */
156
+ declare const EVENT_ENCODING = "json";
157
+ type JournalMode = "wal" | "delete" | "truncate" | "persist";
158
+ /** SQLite 的默认 busy timeout(毫秒)。 */
159
+ declare const DEFAULT_BUSY_TIMEOUT_MS = 5000;
160
+ /** 一份读出来的日志(分支只看这些字段)。 */
161
+ interface BranchLog {
162
+ meta: SessionHeader;
163
+ inheritedEventCount: number;
164
+ events: SessionEvent[];
165
+ tornFrom?: number;
166
+ incarnation: string;
167
+ revision: number;
168
+ storedCount: number;
169
+ migrated: boolean;
170
+ }
171
+ /**
172
+ * 分支能力需要的持久化面(端口)。
173
+ *
174
+ * 为什么不是整个 `SessionPersistenceRdb`:分支只需要「读日志前缀、写截断、认领复用映射」这几件事,
175
+ * 端口里的每个动词都有真实调用方(不是把服务的方法表转抄一遍)。rewind 走直连快路径,
176
+ * 所以这里保留了行级的 `eventRows` / `sessionRow` / `transaction`,而不是只给一个 `readLog`。
177
+ */
178
+ interface BranchPort {
179
+ readonly ready: Promise<void>;
180
+ readLog(id: SessionId, options?: {
181
+ fromSeq?: number;
182
+ }, signal?: AbortSignal): Promise<BranchLog | undefined>;
183
+ create(meta: SessionHeader, options?: {
184
+ inheritedEventCount?: SessionLogOffset;
185
+ }): Promise<SessionHandle>;
186
+ eventRows(id: SessionId, fromSequence?: number): Promise<EventRow[]>;
187
+ eventTypesBefore(id: SessionId, beforeSequence: number, limit: number): Promise<Array<Pick<EventRow, "fSequence" | "fType">>>;
188
+ sessionRow(id: SessionId): Promise<SessionRow | undefined>;
189
+ eventTypeAt(id: SessionId, sequence: number): Promise<string | undefined>;
190
+ transaction<T>(fn: (tx: BackendTx) => Promise<T>): Promise<T>;
191
+ /** head 回退与 revision bump 是同一次行写,确认位点后写路径才允许继续 append。 */
192
+ confirmHead(id: SessionId, sequence: number): void;
193
+ readStoredRevision(id: SessionId): Promise<SessionPersistenceRevision | undefined>;
194
+ /** fork 复用父会话的事件行:子会话落写时按 seq 取回父行 id。 */
195
+ registerReuseEventIds(childId: SessionId, map: ReadonlyMap<number, string>): void;
196
+ dropReuseEventIds(childId: SessionId): void;
197
+ /** rewind 截断后把活跃写句柄的游标与 seed 长度挪到新水位。 */
198
+ resetWriterAfterRewind(id: SessionId, cursor: number, inheritedEventCount?: number): void;
199
+ }
200
+ /**
201
+ * 会话删除的失败语义(叶子模块)。
202
+ *
203
+ * 放成叶子是为了断开 `session-store ↔ deletion` 的运行时环:HTTP 路由只依赖这个错误类型,不再值引入整个服务。
204
+ 现在 `deletion.ts` 对它只剩 `import type`,运行时环为 0。
205
+ */
206
+ type SessionDeletionErrorCode = "SESSION_NOT_FOUND" | "SESSION_NOT_ARCHIVED" | "SESSION_LIVE";
207
+ declare class SessionDeletionError extends Error {
208
+ readonly code: SessionDeletionErrorCode;
209
+ constructor(message: string, code: SessionDeletionErrorCode);
210
+ }
211
+ type Config = {
212
+ type: "sqlite";
213
+ path: string;
214
+ journalMode?: JournalMode | undefined;
215
+ busyTimeout?: number | undefined;
216
+ preparedSessionCacheSize?: number | undefined;
217
+ } | {
218
+ type: "postgres";
219
+ connectionString: string;
220
+ schema?: string | undefined;
221
+ preparedSessionCacheSize?: number | undefined;
222
+ };
223
+ type ResolvedConfig = Volatile<Config>;
277
224
  declare class SessionPersistenceRdb extends SessionPersistence {
278
225
  static inject: string[];
279
226
  static Config: z<Config, ResolvedConfig>;
280
227
  readonly name = "session-rdb";
281
228
  readonly tracker: RdbBackendTracker;
282
- private readonly backend;
229
+ /** 打开后的后端;未打开时访问会 fail loud(装配内部、分支端口与测试共用)。 */
230
+ backend: Backend;
283
231
  private storeIdentity;
284
- private readonly ready;
285
- private readonly writeGuard;
232
+ /** 后端打开完成(分支端口与 live 路由都先等它)。 */
233
+ readonly ready: Promise<void>;
234
+ /** 写者位点守卫(分支的 rewind 与写路径共用)。 */
235
+ readonly writeGuard: WriteGuard;
236
+ private readonly live;
237
+ private readonly readPath;
238
+ private readonly writePath;
286
239
  private readonly reuseEventIds;
287
- private readonly liveBuffers;
288
- private readonly liveReady;
289
240
  readonly config: Config;
290
- constructor(ctx: Context, config: ResolvedConfig, injectedBackend?: Backend);
241
+ constructor(ctx: Context, config: ResolvedConfig);
242
+ /** 打开完成后的 backend(所有 DB 操作的门)。 */
243
+ private database;
291
244
  private init;
292
245
  create(header: SessionHeader, options?: SessionPersistenceCreateOptions): Promise<SessionHandle>;
293
246
  open(id: SessionId, access: SessionAccess, options?: SessionPersistenceOpenOptions): Promise<SessionHandle>;
@@ -295,6 +248,18 @@ declare class SessionPersistenceRdb extends SessionPersistence {
295
248
  stat(id: SessionId, options?: SessionPersistenceStatOptions): Promise<SessionPersistenceSnapshot | undefined>;
296
249
  list(options?: SessionPersistenceListOptions): Promise<readonly SessionPersistenceSnapshot[]>;
297
250
  deleteSession(id: SessionId, signal?: AbortSignal): Promise<void>;
251
+ /**
252
+ * 整理数据:回收孤儿会话与孤儿事件行,然后**整表重算**三张派生统计表,最后 VACUUM。
253
+ *
254
+ * 顺序有依赖:先清孤儿(被删会话独占的事件行才刚成为孤儿),再按事件表重算统计,
255
+ * 否则统计会把刚删掉的引用算回去。
256
+ * @returns 三项计数(孤儿会话 / 孤儿事件行 / 重建涉及的会话数)。
257
+ */
258
+ organize(): Promise<{
259
+ orphanSessions: number;
260
+ orphanEvents: number;
261
+ rebuiltSessions: number;
262
+ }>;
298
263
  collectOrphans(): Promise<number>;
299
264
  collectOrphanSessions(): Promise<number>;
300
265
  usageReport(sinceMs?: number): Promise<UsageAggregate>;
@@ -306,14 +271,6 @@ declare class SessionPersistenceRdb extends SessionPersistence {
306
271
  */
307
272
  archivedSessionIds(): Promise<ReadonlySet<string>>;
308
273
  private unarchiveBeforeDeletion;
309
- readRaw(id: SessionId, signal?: AbortSignal): Promise<{
310
- meta: SessionHeader;
311
- inheritedEventCount: number;
312
- filename: string;
313
- content: string;
314
- } | undefined>;
315
- materializeEmpty(meta: SessionHeader, inheritedEventCount: SessionLogOffset): Promise<void>;
316
- appendBatch(meta: SessionHeader, inheritedEventCount: SessionLogOffset, events: readonly SessionEvent[], tornTruncateTo?: number): Promise<boolean>;
317
274
  readLog(id: SessionId, options?: {
318
275
  fromSeq?: number;
319
276
  }, signal?: AbortSignal): Promise<{
@@ -326,15 +283,19 @@ declare class SessionPersistenceRdb extends SessionPersistence {
326
283
  storedCount: number;
327
284
  migrated: boolean;
328
285
  } | undefined>;
329
- private recordSessionStats;
330
- rebuildSessionStats(id: SessionId): Promise<void>;
331
- private refreshEventUsageFlags;
332
- private dropSessionStats;
333
- private rewriteMigratedLog;
334
- listSnapshots(signal?: AbortSignal): Promise<Array<SessionPersistenceSnapshot & {
286
+ readRaw(id: SessionId, signal?: AbortSignal): Promise<{
287
+ meta: SessionHeader;
288
+ inheritedEventCount: number;
289
+ filename: string;
290
+ content: string;
291
+ } | undefined>;
292
+ listSnapshots(signal?: AbortSignal): Promise<(SessionPersistenceSnapshot & {
335
293
  inheritedEventCount: number;
336
- }>>;
294
+ })[]>;
337
295
  readStoredRevision(id: SessionId, signal?: AbortSignal): Promise<SessionPersistenceRevision | undefined>;
296
+ materializeEmpty(meta: SessionHeader, inheritedEventCount: SessionLogOffset): Promise<void>;
297
+ appendBatch(meta: SessionHeader, inheritedEventCount: SessionLogOffset, events: readonly SessionEvent[], tornTruncateTo?: number): Promise<boolean>;
298
+ close(): Promise<void>;
338
299
  createAndAppend(header: SessionHeader, events: readonly SessionEvent[], inheritedEventCount?: number): Promise<void>;
339
300
  load(id: SessionId, signal?: AbortSignal): Promise<import("@deepseek-ai/dsh-session-persistence").SessionInspection>;
340
301
  append(id: SessionId, events: readonly SessionEvent[]): Promise<void>;
@@ -343,16 +304,11 @@ declare class SessionPersistenceRdb extends SessionPersistence {
343
304
  inheritedEventCount: number;
344
305
  events: readonly SessionEvent[];
345
306
  }>;
346
- close(): Promise<void>;
347
307
  registerReuseEventIds(childId: SessionId, map: ReadonlyMap<number, string>): void;
348
308
  dropReuseEventIds(childId: SessionId): void;
349
- internals(): SessionPersistenceRdbInternals;
309
+ /** 分支能力的端口(见 `branch/port.ts`):每个动词都有真实调用方,不是服务方法表的转抄。 */
310
+ branchPort(): BranchPort;
350
311
  private rowRevision;
351
- private readonly liveFailures;
352
- private readonly liveDropWarned;
353
- private watchLiveReady;
354
- private installLiveRouting;
355
- private ensureLiveHandle;
356
312
  }
357
313
  type UsageRangeKey = "all" | "day" | "week" | "7d" | "30d" | "90d";
358
314
  declare function resolveUsageSince(range: UsageRangeKey, now: number): number | undefined;
@@ -454,6 +410,8 @@ interface BackendTx {
454
410
  fSurfaceOp: string | null;
455
411
  }>): Promise<void>;
456
412
  updateHead(id: SessionId, headEventId: string, headSequence: number): Promise<void>;
413
+ /** 推进 head 并 bump revision:同一行一次 UPDATE(分两次写是纯写放大)。 */
414
+ updateHeadAndRevision(id: SessionId, headEventId: string, headSequence: number, lastEventAt?: number): Promise<void>;
457
415
  bumpRevision(id: SessionId, lastEventAt?: number): Promise<void>;
458
416
  deleteBridgeTail(id: SessionId, fromSequence: number): Promise<readonly string[]>;
459
417
  getPrevBridge(id: SessionId, sequence: number): Promise<{
@@ -495,16 +453,28 @@ interface SessionUsageBucket extends UsageTokenTotals {
495
453
  provider: string | null;
496
454
  model: string | null;
497
455
  }
456
+ /** 会话读的共享实现:写路径之外的所有查询都在这里(两方言共用一套投影查询)。 */
457
+ interface ReadModel {
458
+ getSession(id: string): Promise<SessionRow | undefined>;
459
+ getEventRows(id: string, fromSequence?: number): Promise<EventRow[]>;
460
+ getEventTypeAt(id: string, sequence: number): Promise<string | undefined>;
461
+ getEventTypesBefore(id: string, beforeSequence: number, limit: number): Promise<Array<Pick<EventRow, "fSequence" | "fType">>>;
462
+ listSessions(): Promise<SessionRow[]>;
463
+ /** 最新一条 `session/title` 事件(`refreshTitle` 用)。 */
464
+ latestTitleEvent(id: string): Promise<{
465
+ fSequence: number;
466
+ fData: string;
467
+ } | undefined>;
468
+ /** 父会话已不在表里的 subagent 会话。 */
469
+ listOrphanSubagentSessions(): Promise<string[]>;
470
+ }
498
471
  interface Backend {
499
472
  readonly kind: "sqlite" | "postgres";
500
473
  readonly storeIdentity: string;
501
474
  readonly storage: StorageRepository;
475
+ /** 读面:会话行与事件行的查询(不再是 Backend 自己的 6 个转发方法)。 */
476
+ readonly reads: ReadModel;
502
477
  open(): Promise<void>;
503
- getSession(id: SessionId): Promise<SessionRow | undefined>;
504
- getEventRows(id: SessionId, fromSequence?: number): Promise<EventRow[]>;
505
- getEventTypeAt(id: SessionId, sequence: number): Promise<string | undefined>;
506
- getEventTypesBefore(id: SessionId, beforeSequence: number, limit: number): Promise<Array<Pick<EventRow, "fSequence" | "fType">>>;
507
- listSessions(): Promise<SessionRow[]>;
508
478
  transaction<T>(fn: (tx: BackendTx) => Promise<T>): Promise<T>;
509
479
  collectOrphans(): Promise<number>;
510
480
  listOrphanSubagentSessions(): Promise<SessionId[]>;
@@ -513,81 +483,10 @@ interface Backend {
513
483
  incrementSessionUsage(id: SessionId, buckets: readonly SessionUsageBucket[]): Promise<void>;
514
484
  incrementSessionCounts(id: SessionId, buckets: readonly SessionCountBucket[]): Promise<void>;
515
485
  rebuildSessionStats(id: SessionId): Promise<void>;
486
+ rebuildAllStats(): Promise<number>;
516
487
  refreshEventUsageFlags(eventIds: readonly string[]): Promise<void>;
517
488
  deleteSessionStats(id: SessionId): Promise<void>;
518
489
  vacuum(): Promise<void>;
519
490
  close(): Promise<void>;
520
491
  }
521
- declare function rowToMeta(row: SessionRow): SessionHeader;
522
- declare function sessionInsertRow(storage: SessionStorageMetadata, incarnation: string): {
523
- fSessionId: string;
524
- fHeadEventId: string;
525
- fHeadSequence: number;
526
- fVersion: number;
527
- fCreatedAt: number;
528
- fCwd: string | null;
529
- fParentSession: string | null;
530
- fSeedLength: number | null;
531
- fOrigin: string | null;
532
- fDelegationDepth: number | null;
533
- fAgentPreset: string | null;
534
- fIncarnation: string;
535
- fRevision: number;
536
- };
537
- declare function sessionConflictRow(storage: SessionStorageMetadata): {
538
- fVersion: number;
539
- fCreatedAt: number;
540
- fCwd: string | null;
541
- fParentSession: string | null;
542
- fSeedLength: number | null;
543
- fOrigin: string | null;
544
- fDelegationDepth: number | null;
545
- fAgentPreset: string | null;
546
- };
547
- declare function rowToEvent(row: EventRow): SessionEvent;
548
- declare function recomputeReplaceProvenance(events: SessionEvent[]): void;
549
- declare function findSurfaceRepairs(events: readonly SessionEvent[]): {
550
- degradeToAppend: Set<number>;
551
- addAppendMarker: Set<number>;
552
- clearSurfaceOp: Set<number>;
553
- clampEnd: Map<number, number>;
554
- };
555
- declare function repairSurfaceOps(events: SessionEvent[]): void;
556
- declare function repairAssistantSettlement(events: SessionEvent[]): void;
557
- declare function repairRequestHeaders(events: SessionEvent[]): void;
558
- declare function syncMeteringRanges(events: SessionEvent[]): void;
559
- declare function renameLegacyPtcEvents(events: SessionEvent[]): void;
560
- declare function normalizeToCurrentShape(events: SessionEvent[]): void;
561
- declare function sealOwnEvents(events: readonly SessionEvent[]): void;
562
- declare const OWN_EVENT_TYPES: ReadonlySet<string>;
563
- declare function needsShapeAdoption(events: readonly SessionEvent[]): boolean;
564
- declare function repairReadView(events: SessionEvent[]): void;
565
- declare function orphanInboxSpliceSeqs(events: readonly SessionEvent[]): Set<number>;
566
- declare function repairOrphanInboxSplices(events: SessionEvent[]): void;
567
- declare function scanRows(rows: readonly EventRow[], base?: number): {
568
- preserved: SessionEvent[];
569
- tornFrom?: number;
570
- };
571
- declare function toJsonlArtifact(meta: SessionHeader, inheritedEventCount: number, events: readonly SessionEvent[]): string;
572
- declare function titleOfEventData(data: string): string | undefined;
573
- interface EventUsageRow {
574
- fEventId: string;
575
- fCreatedAt: number;
576
- fDay: string;
577
- fProvider: string | null;
578
- fModel: string | null;
579
- fReferenced: number;
580
- fSubagent: number;
581
- fInputTokens: number;
582
- fOutputTokens: number;
583
- fCacheReadTokens: number;
584
- fReasoningTokens: number;
585
- fTotalTokens: number;
586
- }
587
- declare function usageRowOf(event: {
588
- fEventId: string;
589
- fCreatedAt: number;
590
- fType: string;
591
- fData: string;
592
- }, subagent: boolean): EventUsageRow | undefined;
593
- export { SessionDeletionErrorCode as $, SessionRow as A, tWorkspaceState as At, UsageTotals as B, usageRowOf as C, tSessionCounts as Ct, SessionCountBucket as D, tSessions as Dt, EventRow as E, tSessionUsage as Et, UsageAggregate as F, SESSION_GC_PATH as Ft, emptyTotals as G, addActivityTotals as H, UsageBucket as I, SESSION_IMPORT_PATH as It, resolveUsageSince as J, localDayKey as K, UsageRangeKey as L, SESSION_ROWS_PATH as Lt, COUNTED_EVENT_TYPES as M, WriteGuard as Mt, SessionUsageReport as N, SESSION_DELETE_PATH as Nt, SessionListRowsPage as O, tStorageUnits as Ot, UsageActivityTotals as P, SESSION_EXPORT_PATH as Pt, SessionDeletionError as Q, UsageSessionRow as R, SESSION_USAGE_PATH as Rt, toJsonlArtifact as S, tSchemaMeta as St, BackendTx as T, tSessionProjcacheRows as Tt, addTokenTotals as U, addActivityCount as V, addTotals as W, ProjectionCacheOptions as X, Config as Y, ResolvedConfig as Z, sealOwnEvents as _, eventKind as _t, normalizeToCurrentShape as a, locateTurnEnd as at, syncMeteringRanges as b, tPersistenceState as bt, renameLegacyPtcEvents as c, SessionRowsValue as ct, repairReadView as d, EventKind as dt, SessionPersistenceRdb as et, repairRequestHeaders as f, EventRole as ft, scanRows as g, eventDimensions as gt, rowToMeta as h, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID as ht, needsShapeAdoption as i, liveEventsOf as it, SessionUsageBucket as j, tWorkspaces as jt, SessionListRowsQuery as k, tWorkspaceSessions as kt, repairAssistantSettlement as l, DEFAULT_BUSY_TIMEOUT_MS as lt, rowToEvent as m, SCHEMA_VERSION as mt, OWN_EVENT_TYPES as n, SessionBranchRdb as nt, orphanInboxSpliceSeqs as o, truncateLiveSession as ot, repairSurfaceOps as p, JournalMode as pt, registerSessionUsage as q, findSurfaceRepairs as r, SessionBranchRdbProvider as rt, recomputeReplaceProvenance as s, SessionRowsItem as st, EventUsageRow as t, SessionPersistenceRdbInternals as tt, repairOrphanInboxSplices as u, EVENT_ENCODING as ut, sessionConflictRow as v, tEventUsage as vt, Backend as w, tSessionEvents as wt, titleOfEventData as x, tScheduleTasks as xt, sessionInsertRow as y, tEvents as yt, UsageTokenTotals as z, StorageRepository as zt };
492
+ export { SessionDeletionError as A, SESSION_EXPORT_PATH as B, emptyTotals as C, Config as D, resolveUsageSince as E, JournalMode as F, StorageRepository as G, SESSION_ORGANIZE_PATH as H, SCHEMA_VERSION as I, EventUsageRow as K, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID as L, BranchPort as M, DEFAULT_BUSY_TIMEOUT_MS as N, ResolvedConfig as O, EVENT_ENCODING as P, WriteGuard as R, addTotals as S, registerSessionUsage as T, SESSION_ROWS_PATH as U, SESSION_IMPORT_PATH as V, SESSION_USAGE_PATH as W, UsageTokenTotals as _, SessionCountBucket as a, addActivityTotals as b, SessionRow as c, SessionUsageReport as d, UsageActivityTotals as f, UsageSessionRow as g, UsageRangeKey as h, ReadModel as i, SessionDeletionErrorCode as j, SessionPersistenceRdb as k, SessionUsageBucket as l, UsageBucket as m, BackendTx as n, SessionListRowsPage as o, UsageAggregate as p, usageRowOf as q, EventRow as r, SessionListRowsQuery as s, Backend as t, COUNTED_EVENT_TYPES as u, UsageTotals as v, localDayKey as w, addTokenTotals as x, addActivityCount as y, SESSION_DELETE_PATH as z };