ds4-context-core 0.3.0-alpha.4 → 0.3.0-beta.1

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 (40) hide show
  1. package/README.md +5 -2
  2. package/dist/compaction/segmentation.d.ts +14 -0
  3. package/dist/compaction/segmentation.d.ts.map +1 -0
  4. package/dist/compaction/segmentation.js +81 -0
  5. package/dist/compaction/segmentation.js.map +1 -0
  6. package/dist/index.d.ts +5 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +5 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/manifest/context-manifest-storage.d.ts +63 -0
  11. package/dist/manifest/context-manifest-storage.d.ts.map +1 -0
  12. package/dist/manifest/context-manifest-storage.js +137 -0
  13. package/dist/manifest/context-manifest-storage.js.map +1 -0
  14. package/dist/manifest/context-manifest.d.ts +3 -0
  15. package/dist/manifest/context-manifest.d.ts.map +1 -1
  16. package/dist/persistence/database-client-lease.d.ts +46 -0
  17. package/dist/persistence/database-client-lease.d.ts.map +1 -0
  18. package/dist/persistence/database-client-lease.js +274 -0
  19. package/dist/persistence/database-client-lease.js.map +1 -0
  20. package/dist/persistence/repositories/context-manifest-repository.d.ts +24 -4
  21. package/dist/persistence/repositories/context-manifest-repository.d.ts.map +1 -1
  22. package/dist/persistence/repositories/context-manifest-repository.js +243 -44
  23. package/dist/persistence/repositories/context-manifest-repository.js.map +1 -1
  24. package/dist/persistence/sqlite.d.ts +14 -0
  25. package/dist/persistence/sqlite.d.ts.map +1 -1
  26. package/dist/persistence/sqlite.js +91 -22
  27. package/dist/persistence/sqlite.js.map +1 -1
  28. package/dist/persistence/storage-diagnostics.d.ts +51 -0
  29. package/dist/persistence/storage-diagnostics.d.ts.map +1 -0
  30. package/dist/persistence/storage-diagnostics.js +172 -0
  31. package/dist/persistence/storage-diagnostics.js.map +1 -0
  32. package/dist/persistence/storage-maintenance.d.ts +68 -0
  33. package/dist/persistence/storage-maintenance.d.ts.map +1 -0
  34. package/dist/persistence/storage-maintenance.js +676 -0
  35. package/dist/persistence/storage-maintenance.js.map +1 -0
  36. package/dist/persistence/write-coordinator.d.ts +1 -0
  37. package/dist/persistence/write-coordinator.d.ts.map +1 -1
  38. package/dist/persistence/write-coordinator.js +35 -11
  39. package/dist/persistence/write-coordinator.js.map +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,274 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, unlinkSync, writeFileSync, } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { sha256 } from "../shared/hash.js";
5
+ const LEASE_PROTOCOL = "ds4-context-database-client-v1";
6
+ const MAINTENANCE_PROTOCOL = "ds4-context-database-maintenance-v1";
7
+ export class DatabaseProtocolError extends Error {
8
+ category;
9
+ constructor(category) {
10
+ super(`Database protocol refused the operation (category=${category})`);
11
+ this.category = category;
12
+ this.name = "DatabaseProtocolError";
13
+ }
14
+ }
15
+ export function databaseProtocolPaths(databasePath) {
16
+ return {
17
+ clientsDirectory: `${databasePath}.clients`,
18
+ maintenanceLock: `${databasePath}.maintenance.lock`,
19
+ maintenanceState: `${databasePath}.maintenance-state.json`,
20
+ };
21
+ }
22
+ export function databasePathFingerprint(databasePath) {
23
+ return sha256(resolve(databasePath));
24
+ }
25
+ function bestEffortChmod(path, mode) {
26
+ try {
27
+ chmodSync(path, mode);
28
+ }
29
+ catch (error) {
30
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
31
+ if (code !== "ENOSYS" && code !== "EPERM" && code !== "EINVAL")
32
+ throw error;
33
+ }
34
+ }
35
+ function fsyncDirectory(path) {
36
+ let descriptor;
37
+ try {
38
+ descriptor = openSync(path, "r");
39
+ fsyncSync(descriptor);
40
+ }
41
+ catch (error) {
42
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
43
+ if (code !== "EINVAL" && code !== "ENOTSUP" && code !== "EBADF" && code !== "EPERM")
44
+ throw error;
45
+ }
46
+ finally {
47
+ if (descriptor !== undefined)
48
+ closeSync(descriptor);
49
+ }
50
+ }
51
+ function writeExclusiveJson(path, value) {
52
+ const descriptor = openSync(path, "wx", 0o600);
53
+ try {
54
+ writeFileSync(descriptor, `${JSON.stringify(value)}\n`, "utf8");
55
+ fsyncSync(descriptor);
56
+ }
57
+ finally {
58
+ closeSync(descriptor);
59
+ }
60
+ bestEffortChmod(path, 0o600);
61
+ fsyncDirectory(dirname(path));
62
+ }
63
+ function parseJsonFile(path) {
64
+ return JSON.parse(readFileSync(path, "utf8"));
65
+ }
66
+ function isSafePid(value) {
67
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
68
+ }
69
+ function isBoundedIdentifier(value) {
70
+ return typeof value === "string" && /^[a-z0-9][a-z0-9._-]{0,127}$/iu.test(value);
71
+ }
72
+ function parseClientLease(value) {
73
+ if (!value || typeof value !== "object")
74
+ return undefined;
75
+ const record = value;
76
+ if (record.protocol !== LEASE_PROTOCOL
77
+ || !isBoundedIdentifier(record.clientId)
78
+ || !isSafePid(record.pid)
79
+ || !Number.isSafeInteger(record.createdAt)
80
+ || typeof record.databaseFingerprint !== "string"
81
+ || !/^[a-f0-9]{64}$/u.test(record.databaseFingerprint))
82
+ return undefined;
83
+ return record;
84
+ }
85
+ function parseMaintenanceLock(value) {
86
+ if (!value || typeof value !== "object")
87
+ return undefined;
88
+ const record = value;
89
+ if (record.protocol !== MAINTENANCE_PROTOCOL
90
+ || !isBoundedIdentifier(record.ownerId)
91
+ || !isSafePid(record.pid)
92
+ || !Number.isSafeInteger(record.createdAt)
93
+ || typeof record.databaseFingerprint !== "string"
94
+ || !/^[a-f0-9]{64}$/u.test(record.databaseFingerprint))
95
+ return undefined;
96
+ return record;
97
+ }
98
+ export function probeProcess(pid) {
99
+ try {
100
+ process.kill(pid, 0);
101
+ return "alive";
102
+ }
103
+ catch (error) {
104
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
105
+ if (code === "ESRCH")
106
+ return "dead";
107
+ return "ambiguous";
108
+ }
109
+ }
110
+ function scanClientLeases(databasePath, processProbe) {
111
+ const paths = databaseProtocolPaths(databasePath);
112
+ if (!existsSync(paths.clientsDirectory))
113
+ return { active: 0, staleRemoved: 0, ambiguous: 0 };
114
+ const fingerprint = databasePathFingerprint(databasePath);
115
+ let active = 0;
116
+ let staleRemoved = 0;
117
+ let ambiguous = 0;
118
+ for (const name of readdirSync(paths.clientsDirectory).sort()) {
119
+ if (!name.endsWith(".json")) {
120
+ ambiguous++;
121
+ continue;
122
+ }
123
+ const path = `${paths.clientsDirectory}/${name}`;
124
+ let record;
125
+ try {
126
+ record = parseClientLease(parseJsonFile(path));
127
+ }
128
+ catch {
129
+ record = undefined;
130
+ }
131
+ if (!record || record.databaseFingerprint !== fingerprint) {
132
+ ambiguous++;
133
+ continue;
134
+ }
135
+ const status = processProbe(record.pid);
136
+ if (status === "alive") {
137
+ active++;
138
+ }
139
+ else if (status === "ambiguous") {
140
+ ambiguous++;
141
+ }
142
+ else {
143
+ try {
144
+ unlinkSync(path);
145
+ staleRemoved++;
146
+ }
147
+ catch {
148
+ ambiguous++;
149
+ }
150
+ }
151
+ }
152
+ if (staleRemoved > 0)
153
+ fsyncDirectory(paths.clientsDirectory);
154
+ return { active, staleRemoved, ambiguous };
155
+ }
156
+ export function createDatabaseClientLease(databasePath, options = {}) {
157
+ const paths = databaseProtocolPaths(databasePath);
158
+ if (existsSync(paths.maintenanceLock))
159
+ throw new DatabaseProtocolError("maintenance-active");
160
+ mkdirSync(paths.clientsDirectory, { recursive: true, mode: 0o700 });
161
+ bestEffortChmod(paths.clientsDirectory, 0o700);
162
+ const clientId = options.clientId ?? randomUUID();
163
+ if (!isBoundedIdentifier(clientId))
164
+ throw new DatabaseProtocolError("invalid-client-id");
165
+ const record = {
166
+ protocol: LEASE_PROTOCOL,
167
+ clientId,
168
+ pid: options.pid ?? process.pid,
169
+ createdAt: options.createdAt ?? Date.now(),
170
+ databaseFingerprint: databasePathFingerprint(databasePath),
171
+ };
172
+ if (!isSafePid(record.pid) || !Number.isSafeInteger(record.createdAt)) {
173
+ throw new DatabaseProtocolError("invalid-client-metadata");
174
+ }
175
+ const leasePath = `${paths.clientsDirectory}/${clientId}.json`;
176
+ try {
177
+ writeExclusiveJson(leasePath, record);
178
+ }
179
+ catch (error) {
180
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
181
+ throw new DatabaseProtocolError(code === "EEXIST" ? "client-id-conflict" : "lease-create-failed");
182
+ }
183
+ let released = false;
184
+ const release = () => {
185
+ if (released)
186
+ return;
187
+ released = true;
188
+ try {
189
+ const current = parseClientLease(parseJsonFile(leasePath));
190
+ if (current?.clientId === clientId) {
191
+ unlinkSync(leasePath);
192
+ fsyncDirectory(paths.clientsDirectory);
193
+ }
194
+ }
195
+ catch {
196
+ // Idempotent release never removes an unverified replacement lease.
197
+ }
198
+ };
199
+ if (existsSync(paths.maintenanceLock)) {
200
+ release();
201
+ throw new DatabaseProtocolError("maintenance-active");
202
+ }
203
+ return { clientId, path: leasePath, release };
204
+ }
205
+ function removeVerifiedStaleMaintenanceLock(databasePath, processProbe) {
206
+ const path = databaseProtocolPaths(databasePath).maintenanceLock;
207
+ let record;
208
+ try {
209
+ record = parseMaintenanceLock(parseJsonFile(path));
210
+ }
211
+ catch {
212
+ record = undefined;
213
+ }
214
+ if (!record
215
+ || record.databaseFingerprint !== databasePathFingerprint(databasePath)
216
+ || processProbe(record.pid) !== "dead") {
217
+ throw new DatabaseProtocolError("maintenance-lock-active-or-ambiguous");
218
+ }
219
+ unlinkSync(path);
220
+ fsyncDirectory(dirname(path));
221
+ }
222
+ export function acquireDatabaseMaintenanceLock(databasePath, options = {}) {
223
+ const paths = databaseProtocolPaths(databasePath);
224
+ mkdirSync(dirname(databasePath), { recursive: true, mode: 0o700 });
225
+ const processProbe = options.processProbe ?? probeProcess;
226
+ if (existsSync(paths.maintenanceLock)) {
227
+ if (!options.replaceStaleLock)
228
+ throw new DatabaseProtocolError("maintenance-lock-exists");
229
+ removeVerifiedStaleMaintenanceLock(databasePath, processProbe);
230
+ }
231
+ const ownerId = options.ownerId ?? randomUUID();
232
+ if (!isBoundedIdentifier(ownerId))
233
+ throw new DatabaseProtocolError("invalid-owner-id");
234
+ const record = {
235
+ protocol: MAINTENANCE_PROTOCOL,
236
+ ownerId,
237
+ pid: options.pid ?? process.pid,
238
+ createdAt: options.createdAt ?? Date.now(),
239
+ databaseFingerprint: databasePathFingerprint(databasePath),
240
+ };
241
+ if (!isSafePid(record.pid) || !Number.isSafeInteger(record.createdAt)) {
242
+ throw new DatabaseProtocolError("invalid-owner-metadata");
243
+ }
244
+ try {
245
+ writeExclusiveJson(paths.maintenanceLock, record);
246
+ }
247
+ catch (error) {
248
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
249
+ throw new DatabaseProtocolError(code === "EEXIST" ? "maintenance-lock-exists" : "maintenance-lock-create-failed");
250
+ }
251
+ let released = false;
252
+ const release = () => {
253
+ if (released)
254
+ return;
255
+ released = true;
256
+ try {
257
+ const current = parseMaintenanceLock(parseJsonFile(paths.maintenanceLock));
258
+ if (current?.ownerId === ownerId) {
259
+ unlinkSync(paths.maintenanceLock);
260
+ fsyncDirectory(dirname(paths.maintenanceLock));
261
+ }
262
+ }
263
+ catch {
264
+ // Never unlink an unverified lock owned by another process.
265
+ }
266
+ };
267
+ const clients = scanClientLeases(databasePath, processProbe);
268
+ if (clients.active > 0 || clients.ambiguous > 0) {
269
+ release();
270
+ throw new DatabaseProtocolError(clients.active > 0 ? "active-database-clients" : "ambiguous-database-clients");
271
+ }
272
+ return { ownerId, path: paths.maintenanceLock, clients, release };
273
+ }
274
+ //# sourceMappingURL=database-client-lease.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-client-lease.js","sourceRoot":"","sources":["../../src/persistence/database-client-lease.ts"],"names":[],"mappings":"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"}
@@ -1,21 +1,41 @@
1
1
  import type { DatabaseSync } from "node:sqlite";
2
2
  import type { TokenCalibrationSample } from "../../core/model-awareness.ts";
3
- import { SqliteWriteCoordinator } from "../write-coordinator.ts";
4
3
  import type { ContextManifest } from "../../manifest/context-manifest.ts";
4
+ import { type ManifestSaveResult, type StoredContextManifest } from "../../manifest/context-manifest-storage.ts";
5
+ import { SqliteWriteCoordinator } from "../write-coordinator.ts";
6
+ export declare const MAX_RETAINED_CONTEXT_MANIFESTS = 128;
7
+ export declare const MAX_RETAINED_CALIBRATION_SAMPLES_PER_PROFILE = 200;
8
+ export declare const RETENTION_PRUNE_BATCH_ROWS = 32;
9
+ export declare const RETENTION_PRUNE_BATCH_BYTES: number;
10
+ export declare const CALIBRATION_PRUNE_BATCH_ROWS = 32;
5
11
  export interface ProviderTokenUsage {
6
12
  inputTokens: number;
7
13
  cacheReadTokens: number;
8
14
  cacheWriteTokens: number;
9
15
  }
16
+ export interface ManifestMaintenanceResult {
17
+ prunedManifests: number;
18
+ prunedManifestBytes: number;
19
+ prunedCalibrationSamples: number;
20
+ rewrittenManifests: number;
21
+ rolledUpManifests: number;
22
+ skippedOversizeManifests: number;
23
+ }
10
24
  export declare class ContextManifestRepository {
11
25
  private readonly database;
12
26
  private readonly writes;
13
27
  constructor(database: DatabaseSync, writes?: SqliteWriteCoordinator);
14
- save(manifest: ContextManifest): void;
28
+ save(manifest: ContextManifest): ManifestSaveResult;
15
29
  get(manifestId: string): ContextManifest | undefined;
30
+ getStored(manifestId: string): StoredContextManifest | undefined;
16
31
  getLatest(sessionId: string): ContextManifest | undefined;
17
- recordProviderUsage(manifestId: string, usage: ProviderTokenUsage, createdAt: number): ContextManifest | undefined;
18
- recordActualInput(manifestId: string, actualInputTokens: number, createdAt: number): ContextManifest | undefined;
32
+ getLatestStored(sessionId: string): StoredContextManifest | undefined;
33
+ recordProviderUsage(manifestId: string, usage: ProviderTokenUsage, createdAt: number, estimatorVersion?: string): ContextManifest | undefined;
34
+ recordActualInput(manifestId: string, actualInputTokens: number, createdAt: number, estimatorVersion?: string): ContextManifest | undefined;
35
+ /** Applies unbounded retention only to an explicitly selected offline working copy. */
36
+ applyMaintenanceRetention(): ManifestMaintenanceResult;
19
37
  listCalibrationSamples(provider: string, model: string, limit: number, estimatorVersion?: string): TokenCalibrationSample[];
38
+ private pruneContextManifests;
39
+ private pruneCalibrationSamples;
20
40
  }
21
41
  //# sourceMappingURL=context-manifest-repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-manifest-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,oCAAoC,CAAC;AAgB5C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAiBD,qBAAa,yBAAyB;IAElC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IA2CrC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAOpD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAWzD,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,MAAM,GAChB,eAAe,GAAG,SAAS;IAkE9B,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAQhH,sBAAsB,CACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,gBAAgB,SAAa,GAC5B,sBAAsB,EAAE;CAmB5B"}
1
+ {"version":3,"file":"context-manifest-repository.d.ts","sourceRoot":"","sources":["../../../src/persistence/repositories/context-manifest-repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AA4CjE,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAClD,eAAO,MAAM,4CAA4C,MAAM,CAAC;AAChE,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,eAAO,MAAM,2BAA2B,QAAkB,CAAC;AAC3D,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wBAAwB,EAAE,MAAM,CAAC;IACjC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAoCD,qBAAa,yBAAyB;IAElC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,YAAY,EACtB,MAAM,yBAAuC;IAGhE,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,kBAAkB;IAqEnD,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIpD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAQhE,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIzD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS;IAWrE,mBAAmB,CACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,kBAAkB,EACzB,SAAS,EAAE,MAAM,EACjB,gBAAgB,SAAa,GAC5B,eAAe,GAAG,SAAS;IA6D9B,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,MAAM,EACjB,gBAAgB,SAAa,GAC5B,eAAe,GAAG,SAAS;IAQ9B,uFAAuF;IACvF,yBAAyB,IAAI,yBAAyB;IA4FtD,sBAAsB,CACpB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,gBAAgB,SAAa,GAC5B,sBAAsB,EAAE;IAoB3B,OAAO,CAAC,qBAAqB;IAoC7B,OAAO,CAAC,uBAAuB;CA2BhC"}