@iworkforces/tracelattice 2.0.8 → 2.1.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.
- package/README.md +88 -64
- package/dist/ServerConfig.d.ts +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/cli.js +18 -73
- package/dist/cli.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +29 -26
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +40 -36
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +7 -108
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/PersistenceBackend.js +1 -6
- package/dist/contracts/calibrator.d.ts +6 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/ids.d.ts +1 -8
- package/dist/contracts/ids.d.ts.map +1 -1
- package/dist/contracts/ids.js +2 -3
- package/dist/contracts/ids.js.map +1 -1
- package/dist/contracts/interfaces.d.ts +4 -6
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +2 -3
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/core/HistoryManager.d.ts +12 -16
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +19 -40
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +22 -30
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/InputNormalizer.d.ts +7 -24
- package/dist/core/InputNormalizer.d.ts.map +1 -1
- package/dist/core/InputNormalizer.js +3 -9
- package/dist/core/InputNormalizer.js.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +3 -20
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +1 -4
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +4 -10
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -12
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/SessionErrors.d.ts +0 -11
- package/dist/core/SessionErrors.d.ts.map +1 -1
- package/dist/core/SessionErrors.js +1 -14
- package/dist/core/SessionErrors.js.map +1 -1
- package/dist/core/SessionLock.d.ts +4 -5
- package/dist/core/SessionLock.d.ts.map +1 -1
- package/dist/core/SessionLock.js +5 -10
- package/dist/core/SessionLock.js.map +1 -1
- package/dist/core/SessionManager.d.ts +0 -2
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +3 -5
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SessionResetCoordinator.d.ts +10 -7
- package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
- package/dist/core/SessionResetCoordinator.js +10 -28
- package/dist/core/SessionResetCoordinator.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +5 -5
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +4 -40
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +10 -3
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +34 -38
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js +5 -7
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +1 -1
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +2 -5
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/internals.d.ts +0 -4
- package/dist/core/evaluator/internals.d.ts.map +1 -1
- package/dist/core/evaluator/internals.js +1 -3
- package/dist/core/evaluator/internals.js.map +1 -1
- package/dist/core/graph/Edge.d.ts +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts +2 -4
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -4
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
- package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
- package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
- package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
- package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
- package/dist/core/thought.d.ts +2 -1
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/errors.d.ts +4 -20
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -28
- package/dist/errors.js.map +1 -1
- package/dist/lib.d.ts +13 -20
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +4 -7
- package/dist/lib.js.map +1 -1
- package/dist/logger/NullLogger.d.ts +9 -11
- package/dist/logger/NullLogger.d.ts.map +1 -1
- package/dist/logger/NullLogger.js.map +1 -1
- package/dist/persistence/FilePersistence.d.ts +3 -12
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +9 -61
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -2
- package/dist/persistence/FileSnapshotV2.js +2 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/FileWriter.d.ts +1 -0
- package/dist/persistence/FileWriter.d.ts.map +1 -1
- package/dist/persistence/FileWriter.js +3 -3
- package/dist/persistence/FileWriter.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +5 -15
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +6 -40
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.js +1 -3
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +0 -6
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js +1 -9
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js +2 -2
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +3 -10
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +2 -26
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
- package/dist/persistence/SqliteSchemaV2.js +3 -12
- package/dist/persistence/SqliteSchemaV2.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts +3 -12
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js +5 -8
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/pool/IConnectionPool.d.ts +3 -9
- package/dist/pool/IConnectionPool.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.d.ts +1 -7
- package/dist/registry/SkillRegistry.d.ts.map +1 -1
- package/dist/registry/SkillRegistry.js +0 -15
- package/dist/registry/SkillRegistry.js.map +1 -1
- package/dist/registry/ToolRegistry.d.ts +1 -9
- package/dist/registry/ToolRegistry.d.ts.map +1 -1
- package/dist/registry/ToolRegistry.js +0 -21
- package/dist/registry/ToolRegistry.js.map +1 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/schema.js.map +1 -1
- package/dist/transport/BaseTransport.d.ts +0 -9
- package/dist/transport/BaseTransport.d.ts.map +1 -1
- package/dist/transport/BaseTransport.js +0 -11
- package/dist/transport/BaseTransport.js.map +1 -1
- package/dist/watchers/SkillWatcher.d.ts.map +1 -1
- package/dist/watchers/SkillWatcher.js +1 -1
- package/dist/watchers/SkillWatcher.js.map +1 -1
- package/package.json +1 -1
- package/dist/contracts/PersistenceBackend.js.map +0 -1
- package/dist/persistence/FileLegacyImport.d.ts +0 -2
- package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
- package/dist/persistence/FileLegacyImport.js +0 -183
- package/dist/persistence/FileLegacyImport.js.map +0 -1
- package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
- package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
- package/dist/persistence/SessionScopedPersistence.js +0 -9
- package/dist/persistence/SessionScopedPersistence.js.map +0 -1
- package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
- package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacyImport.js +0 -136
- package/dist/persistence/SqliteLegacyImport.js.map +0 -1
- package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
- package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
- package/dist/persistence/SqliteLegacySchema.js +0 -72
- package/dist/persistence/SqliteLegacySchema.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { asSessionId } from "../contracts/ids.js";
|
|
5
5
|
import { PersistenceCompatibilityError, PersistenceCorruptionError } from "../errors.js";
|
|
6
6
|
import { runSqliteReadTransaction, runSqliteTransaction } from "./SqliteDriver.js";
|
|
7
7
|
import { decodeEdgeRow, decodeSummaryRow, decodeThoughtRow, numberField, stringField } from "./SqlitePayload.js";
|
|
@@ -47,10 +47,6 @@ class SqlitePersistence {
|
|
|
47
47
|
throw error;
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
async saveThought(thought) {
|
|
51
|
-
assertThoughtScope('saveThought', GLOBAL_SESSION_ID, thought);
|
|
52
|
-
this._saveThought(GLOBAL_SESSION_ID, thought);
|
|
53
|
-
}
|
|
54
50
|
async saveThoughtForSession(sessionId, thought) {
|
|
55
51
|
const validatedSessionId = asSessionId(sessionId);
|
|
56
52
|
assertThoughtScope('saveThoughtForSession', validatedSessionId, thought);
|
|
@@ -69,18 +65,10 @@ class SqlitePersistence {
|
|
|
69
65
|
}
|
|
70
66
|
});
|
|
71
67
|
}
|
|
72
|
-
async loadHistory() {
|
|
73
|
-
return await this.loadHistoryForSession(GLOBAL_SESSION_ID);
|
|
74
|
-
}
|
|
75
68
|
async loadHistoryForSession(sessionId) {
|
|
76
69
|
const validatedSessionId = asSessionId(sessionId);
|
|
77
70
|
return runSqliteReadTransaction(this._db, ()=>this._loadValidatedThoughtState(validatedSessionId).history);
|
|
78
71
|
}
|
|
79
|
-
async saveBranch(branchId, thoughts) {
|
|
80
|
-
const validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);
|
|
81
|
-
assertBranchScope('saveBranch', GLOBAL_SESSION_ID, validatedBranchId, thoughts);
|
|
82
|
-
this._saveBranch(GLOBAL_SESSION_ID, validatedBranchId, thoughts);
|
|
83
|
-
}
|
|
84
72
|
async saveBranchForSession(sessionId, branchId, thoughts) {
|
|
85
73
|
const validatedSessionId = asSessionId(sessionId);
|
|
86
74
|
const validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);
|
|
@@ -95,9 +83,6 @@ class SqlitePersistence {
|
|
|
95
83
|
this._db.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)').run(sessionId, branchId, JSON.stringify(thoughts));
|
|
96
84
|
});
|
|
97
85
|
}
|
|
98
|
-
async deleteBranch(branchId) {
|
|
99
|
-
await this.deleteBranchForSession(GLOBAL_SESSION_ID, branchId);
|
|
100
|
-
}
|
|
101
86
|
async deleteBranchForSession(sessionId, branchId) {
|
|
102
87
|
if (!this._persistBranches) return;
|
|
103
88
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -106,18 +91,12 @@ class SqlitePersistence {
|
|
|
106
91
|
this._db.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?').run(validatedSessionId, validatedBranchId);
|
|
107
92
|
});
|
|
108
93
|
}
|
|
109
|
-
async loadBranch(branchId) {
|
|
110
|
-
return await this.loadBranchForSession(GLOBAL_SESSION_ID, branchId);
|
|
111
|
-
}
|
|
112
94
|
async loadBranchForSession(sessionId, branchId) {
|
|
113
95
|
if (!this._persistBranches) return;
|
|
114
96
|
const validatedSessionId = asSessionId(sessionId);
|
|
115
97
|
const validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);
|
|
116
98
|
return runSqliteReadTransaction(this._db, ()=>this._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId));
|
|
117
99
|
}
|
|
118
|
-
async listBranches() {
|
|
119
|
-
return await this.listBranchesForSession(GLOBAL_SESSION_ID);
|
|
120
|
-
}
|
|
121
100
|
async listBranchesForSession(sessionId) {
|
|
122
101
|
if (!this._persistBranches) return [];
|
|
123
102
|
return this._db.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC').all(asSessionId(sessionId)).map((row)=>parsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath));
|
|
@@ -125,7 +104,7 @@ class SqlitePersistence {
|
|
|
125
104
|
async listSessions() {
|
|
126
105
|
return this._db.prepare('SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries').all().map((row)=>asSessionId(stringField(row, 'session_id', this._sourcePath))).sort(compareCodePoint);
|
|
127
106
|
}
|
|
128
|
-
async
|
|
107
|
+
async clearAll() {
|
|
129
108
|
runSqliteTransaction(this._db, ()=>{
|
|
130
109
|
for (const table of [
|
|
131
110
|
'thoughts',
|
|
@@ -159,9 +138,6 @@ class SqlitePersistence {
|
|
|
159
138
|
const validatedSessionId = asSessionId(sessionId);
|
|
160
139
|
return this._db.prepare('SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC').all(validatedSessionId).map((row, index)=>decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));
|
|
161
140
|
}
|
|
162
|
-
async listEdgeSessions() {
|
|
163
|
-
return this._db.prepare('SELECT DISTINCT session_id FROM edges ORDER BY session_id ASC').all().map((row)=>asSessionId(stringField(row, 'session_id', this._sourcePath)));
|
|
164
|
-
}
|
|
165
141
|
async saveSummaries(sessionId, summaries) {
|
|
166
142
|
const validatedSessionId = asSessionId(sessionId);
|
|
167
143
|
assertSummaryScopes(validatedSessionId, summaries);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n\tPersistenceConfig,\n\tSessionScopedPersistenceBackend,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, GLOBAL_SESSION_ID, type BranchId, type SessionId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements SessionScopedPersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(options?: SqliteOptions): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tlet Database: SqliteDatabaseConstructor;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch (error) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tdbPath,\n\t\t\t\t\"SQLite persistence requires the optional 'better-sqlite3' package\",\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThought(thought: ThoughtData): Promise<void> {\n\t\tassertThoughtScope('saveThought', GLOBAL_SESSION_ID, thought);\n\t\tthis._saveThought(GLOBAL_SESSION_ID, thought);\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistory(): Promise<ThoughtData[]> {\n\t\treturn await this.loadHistoryForSession(GLOBAL_SESSION_ID);\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranch(branchId: BranchId, thoughts: ThoughtData[]): Promise<void> {\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranch', GLOBAL_SESSION_ID, validatedBranchId, thoughts);\n\t\tthis._saveBranch(GLOBAL_SESSION_ID, validatedBranchId, thoughts);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranch(branchId: BranchId): Promise<void> {\n\t\tawait this.deleteBranchForSession(GLOBAL_SESSION_ID, branchId);\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranch(branchId: BranchId): Promise<ThoughtData[] | undefined> {\n\t\treturn await this.loadBranchForSession(GLOBAL_SESSION_ID, branchId);\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranches(): Promise<BranchId[]> {\n\t\treturn await this.listBranchesForSession(GLOBAL_SESSION_ID);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tpublic async clear(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async listEdgeSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare('SELECT DISTINCT session_id FROM edges ORDER BY session_id ASC')\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","error","PersistenceCompatibilityError","persistence","thought","assertThoughtScope","GLOBAL_SESSION_ID","sessionId","validatedSessionId","asSessionId","runSqliteTransaction","JSON","countRow","excess","numberField","runSqliteReadTransaction","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":";;;;;;;;;AAyCO,MAAMA;;;;;IACZ,YACkBC,GAAmB,EACnBC,WAAmB,EACnBC,eAAuB,EACvBC,gBAAyB,CACzC;aAJgBH,GAAG,GAAHA;aACAC,WAAW,GAAXA;aACAC,eAAe,GAAfA;aACAC,gBAAgB,GAAhBA;IACf;IAEH,OAAc,mBACbC,QAAwB,EACxBC,UAAyB,CAAC,CAAC,EAC3BC,aAAa,qBAAqB,EACd;QACpBC,6BAA6BH,UAAUE;QACvC,OAAO,IAAIP,kBACVK,UACAE,YACAD,SAAS,kBAAkB,OAC3BA,SAAS,mBAAmB;IAE9B;IAEA,aAAoB,OAAOA,OAAuB,EAA8B;QAC/E,MAAMG,iBAAiBC,WAAW,kBAC/B,iBACAC,KAAKC,WAAW;QACnB,MAAMC,SAASP,SAAS,UAAUK,KAAKF,gBAAgB;QACvD,IAAIK;QACJ,IAAI;YACH,MAAMC,SAAS,MAAM,MAAM,CAAC;YAC5BD,WAAWC,OAAO,OAAO;QAC1B,EAAE,OAAOC,OAAO;YACf,MAAM,IAAIC,8BACTJ,QACA,qEACAG;QAEF;QACA,MAAMX,WAAW,IAAIS,SAASD;QAC9B,IAAI;YACH,MAAMK,cAAclB,kBAAkB,kBAAkB,CAACK,UAAUC,SAASO;YAC5E,IAAIP,SAAS,cAAc,OAAOD,SAAS,MAAM,CAAC;YAClDA,SAAS,MAAM,CAAC;YAChBA,SAAS,MAAM,CAAC;YAChBA,SAAS,MAAM,CAAC;YAChBA,SAAS,MAAM,CAAC;YAChBA,SAAS,MAAM,CAAC;YAChB,OAAOa;QACR,EAAE,OAAOF,OAAO;YACfX,SAAS,KAAK;YACd,MAAMW;QACP;IACD;IAEA,MAAa,YAAYG,OAAoB,EAAiB;QAC7DC,mBAAmB,eAAeC,mBAAmBF;QACrD,IAAI,CAAC,YAAY,CAACE,mBAAmBF;IACtC;IAEA,MAAa,sBAAsBG,SAAoB,EAAEH,OAAoB,EAAiB;QAC7F,MAAMI,qBAAqBC,YAAYF;QACvCF,mBAAmB,yBAAyBG,oBAAoBJ;QAChE,IAAI,CAAC,YAAY,CAACI,oBAAoBJ;IACvC;IAEQ,aAAaG,SAAoB,EAAEH,OAAoB,EAAQ;QACtEM,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,0BAA0B,CAACH,WAAW;gBAACH;aAAQ;YACpD,IAAI,CAAC,GAAG,CACN,OAAO,CAAC,yDACR,GAAG,CAACG,WAAWI,KAAK,SAAS,CAACP;YAChC,IAAI,IAAI,CAAC,eAAe,GAAG,GAAG;gBAC7B,MAAMQ,WAAW,IAAI,CAAC,GAAG,CACvB,OAAO,CAAC,+DACR,GAAG,CAACL;gBACN,MAAMM,SACLC,YAAYF,UAAU,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,IAClE,IAAI,CAAC,eAAe;gBACrB,IAAIC,SAAS,GACZ,IAAI,CAAC,GAAG,CACN,OAAO,CACP,2GAEA,GAAG,CAACN,WAAWM;YAEnB;QACD;IACD;IAEA,MAAa,cAAsC;QAClD,OAAO,MAAM,IAAI,CAAC,qBAAqB,CAACP;IACzC;IAEA,MAAa,sBAAsBC,SAAoB,EAA0B;QAChF,MAAMC,qBAAqBC,YAAYF;QACvC,OAAOQ,yBACN,IAAI,CAAC,GAAG,EACR,IAAM,IAAI,CAAC,0BAA0B,CAACP,oBAAoB,OAAO;IAEnE;IAEA,MAAa,WAAWQ,QAAkB,EAAEC,QAAuB,EAAiB;QACnF,MAAMC,oBAAoBC,yBAAyBH,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAC3FI,kBAAkB,cAAcd,mBAAmBY,mBAAmBD;QACtE,IAAI,CAAC,WAAW,CAACX,mBAAmBY,mBAAmBD;IACxD;IAEA,MAAa,qBACZV,SAAoB,EACpBS,QAAkB,EAClBC,QAAgC,EAChB;QAChB,MAAMT,qBAAqBC,YAAYF;QACvC,MAAMW,oBAAoBC,yBAAyBH,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAC3FI,kBAAkB,wBAAwBZ,oBAAoBU,mBAAmBD;QACjF,IAAI,CAAC,WAAW,CAACT,oBAAoBU,mBAAmBD;IACzD;IAEQ,YACPV,SAAoB,EACpBS,QAAkB,EAClBC,QAAgC,EACzB;QACPI,0BAA0BJ,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAED,UAAU;QAC5E,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,YAC3BD,yBAAyB,IAAI,CAAC,GAAG,EAAE,IAClC,IAAI,CAAC,0BAA0B,CAACR,WAAWU,UAAUD;QAIvDN,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,0BAA0B,CAACH,WAAWU,UAAUD;YACrD,IAAI,CAAC,GAAG,CACN,OAAO,CAAC,kFACR,GAAG,CAACT,WAAWS,UAAUL,KAAK,SAAS,CAACM;QAC3C;IACD;IAEA,MAAa,aAAaD,QAAkB,EAAiB;QAC5D,MAAM,IAAI,CAAC,sBAAsB,CAACV,mBAAmBU;IACtD;IAEA,MAAa,uBAAuBT,SAAoB,EAAES,QAAkB,EAAiB;QAC5F,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;QAC5B,MAAMR,qBAAqBC,YAAYF;QACvC,MAAMW,oBAAoBC,yBAAyBH,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAC3FN,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,GAAG,CACN,OAAO,CAAC,+DACR,GAAG,CAACF,oBAAoBU;QAC3B;IACD;IAEA,MAAa,WAAWF,QAAkB,EAAsC;QAC/E,OAAO,MAAM,IAAI,CAAC,oBAAoB,CAACV,mBAAmBU;IAC3D;IAEA,MAAa,qBACZT,SAAoB,EACpBS,QAAkB,EACmB;QACrC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;QAC5B,MAAMR,qBAAqBC,YAAYF;QACvC,MAAMW,oBAAoBC,yBAAyBH,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;QAC3F,OAAOD,yBAAyB,IAAI,CAAC,GAAG,EAAE,IACzC,IAAI,CAAC,0BAA0B,CAACP,oBAAoB,QAAQ,CAAC,GAAG,CAACU;IAEnE;IAEA,MAAa,eAAoC;QAChD,OAAO,MAAM,IAAI,CAAC,sBAAsB,CAACZ;IAC1C;IAEA,MAAa,uBAAuBC,SAAoB,EAAuB;QAC9E,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,EAAE;QACrC,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CAAC,8EACR,GAAG,CAACE,YAAYF,YAChB,GAAG,CAAC,CAACe,MACLH,yBAAyBI,YAAYD,KAAK,aAAa,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW;IAE7F;IAEA,MAAa,eAAqC;QACjD,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CACP,mJAEA,GAAG,GACH,GAAG,CAAC,CAACA,MAAQb,YAAYc,YAAYD,KAAK,cAAc,IAAI,CAAC,WAAW,IACxE,IAAI,CAACE;IACR;IAEA,MAAa,QAAuB;QACnCd,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,KAAK,MAAMe,SAAS;gBAAC;gBAAY;gBAAY;gBAAS;aAAY,CACjE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,YAAY,EAAEA,OAAO;QACtC;IACD;IAEA,MAAa,aAAalB,SAAoB,EAAiB;QAC9D,MAAMC,qBAAqBC,YAAYF;QACvCG,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,KAAK,MAAMe,SAAS;gBAAC;gBAAY;gBAAY;gBAAS;aAAY,CACjE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,YAAY,EAAEA,MAAM,qBAAqB,CAAC,EAAE,GAAG,CAACjB;QAEpE;IACD;IAEA,MAAa,UAAUD,SAAoB,EAAEmB,KAAsB,EAAiB;QACnF,MAAMlB,qBAAqBC,YAAYF;QACvCoB,iBAAiBnB,oBAAoBkB;QACrChB,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,0CAA0C,GAAG,CAACF;YAC/D,MAAMoB,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,CAC9B;YAED,KAAK,MAAMC,QAAQH,MAClBE,OAAO,GAAG,CACTC,KAAK,EAAE,EACPA,KAAK,SAAS,EACdA,KAAK,IAAI,EACTA,KAAK,EAAE,EACPA,KAAK,IAAI,EACTA,KAAK,SAAS,EACdA,AAAkBC,WAAlBD,KAAK,QAAQ,GAAiB,OAAOlB,KAAK,SAAS,CAACkB,KAAK,QAAQ;QAEpE;IACD;IAEA,MAAa,UAAUtB,SAAoB,EAAmB;QAC7D,MAAMC,qBAAqBC,YAAYF;QACvC,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CACP,qIAEA,GAAG,CAACC,oBACJ,GAAG,CAAC,CAACc,KAAKS,QAAUC,cAAcV,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAES,OAAO;IAC9E;IAEA,MAAa,mBAAyC;QACrD,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CAAC,iEACR,GAAG,GACH,GAAG,CAAC,CAACT,MAAQb,YAAYc,YAAYD,KAAK,cAAc,IAAI,CAAC,WAAW;IAC3E;IAEA,MAAa,cAAcf,SAAoB,EAAE0B,SAA6B,EAAiB;QAC9F,MAAMzB,qBAAqBC,YAAYF;QACvC2B,oBAAoB1B,oBAAoByB;QACxCvB,qBAAqB,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,8CAA8C,GAAG,CAACF;YACnE,MAAMoB,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,CAC9B;YAED,KAAK,MAAMO,WAAWF,UACrBL,OAAO,GAAG,CACTO,QAAQ,EAAE,EACVA,QAAQ,SAAS,EACjBA,QAAQ,QAAQ,IAAI,MACpBA,QAAQ,aAAa,EACrBxB,KAAK,SAAS,CAACwB,QAAQ,UAAU,GACjCA,QAAQ,YAAY,CAAC,EAAE,EACvBA,QAAQ,YAAY,CAAC,EAAE,EACvBxB,KAAK,SAAS,CAACwB,QAAQ,MAAM,GAC7BA,QAAQ,mBAAmB,EAC3BA,QAAQ,SAAS,EACjBA,AAAiBL,WAAjBK,QAAQ,IAAI,GAAiB,OAAOxB,KAAK,SAAS,CAACwB,QAAQ,IAAI;QAElE;IACD;IAEA,MAAa,cAAc5B,SAAoB,EAAsB;QACpE,MAAMC,qBAAqBC,YAAYF;QACvC,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CACP,8NAEA,GAAG,CAACC,oBACJ,GAAG,CAAC,CAACc,KAAKS,QAAUK,iBAAiBd,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAES,OAAO;IACrF;IAEA,MAAa,UAA4B;QACxC,IAAI;YACH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,GAAG;YAChC,OAAO;QACR,EAAE,OAAO9B,OAAO;YACf,IAAIA,iBAAiBoC,OAAO,OAAO;YACnC,MAAMpC;QACP;IACD;IAEA,MAAa,QAAuB;QACnC,IAAI,CAAC,GAAG,CAAC,KAAK;IACf;IAEO,WAIL;QACD,MAAMqC,eAAexB,YACpB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,0CAA0C,GAAG,IAC9D,SACA,IAAI,CAAC,WAAW;QAEjB,MAAMyB,cAAczB,YACnB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,0CAA0C,GAAG,IAC9D,SACA,IAAI,CAAC,WAAW;QAEjB,OAAO;YAAEwB;YAAc,aAAa,IAAI,CAAC,gBAAgB,GAAGC,cAAc;YAAG,QAAQ;QAAE;IACxF;IAEQ,2BACPhC,SAAoB,EACpBiC,aAAqC,EAAE,EACvCC,eAA0B,EACF;QACxB,MAAMC,UAAU,IAAI,CAAC,eAAe,CAACnC;QACrC,KAAK,MAAMH,WAAWsC,QACrBrC,mBAAmB,yBAAyBE,WAAWH;QAExD,MAAMuC,cAA4C;YACjD;gBACCpC;gBACA,UAAUkC,AAAoBX,WAApBW,kBAAgC;uBAAIC;uBAAYF;iBAAW,GAAGE;YACzE;SACA;QACD,MAAME,WAAW,IAAIC;QACrB,KAAK,MAAMvB,OAAO,IAAI,CAAC,GAAG,CACxB,OAAO,CAAC,6DACR,GAAG,CAACf,WAAY;YACjB,MAAMS,WAAWG,yBAChBI,YAAYD,KAAK,aAAa,IAAI,CAAC,WAAW,GAC9C,IAAI,CAAC,WAAW;YAEjB,MAAMwB,OAAOvB,YAAYD,KAAK,QAAQ,IAAI,CAAC,WAAW;YACtD,IAAIyB;YACJ,IAAI;gBACHA,SAASpC,KAAK,KAAK,CAACmC;YACrB,EAAE,OAAO7C,OAAO;gBACf,MAAM,IAAI+C,2BAA2B,IAAI,CAAC,WAAW,EAAE/C;YACxD;YACA,IAAI,CAACgD,MAAM,OAAO,CAACF,SAClB,MAAM,IAAIC,2BACT,IAAI,CAAC,WAAW,EAChB,IAAIE,UAAU;YAEhB,MAAMjC,WAAW8B,OAAO,GAAG,CAAC,CAACI,OAAOpB,QACnCqB,iBACC;oBAAE,MAAMzC,KAAK,SAAS,CAACwC;gBAAO,GAC9B,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE5C,UAAU,CAAC,EAAES,SAAS,CAAC,EAAEe,OAAO;YAGhEX,kBAAkB,wBAAwBb,WAAWS,UAAUC;YAC/D2B,SAAS,GAAG,CAAC5B,UAAUC;YACvB,IAAID,aAAayB,iBAAiBE,YAAY,IAAI,CAAC;gBAAEpC;gBAAWU;YAAS;QAC1E;QACA,IAAIwB,AAAoBX,WAApBW,iBACHE,YAAY,IAAI,CAAC;YAAEpC;YAAW,UAAUiC;QAAW;QAEpDa,oCAAoCV,aAAa,IAAI,CAAC,WAAW;QACjE,OAAO;YAAED;YAASE;QAAS;IAC5B;IAEQ,gBAAgBrC,SAAoB,EAAiB;QAC5D,OAAO,IAAI,CAAC,GAAG,CACb,OAAO,CAAC,kEACR,GAAG,CAACA,WACJ,GAAG,CAAC,CAACe,MAAQ8B,iBAAiB9B,KAAK,IAAI,CAAC,WAAW;IACtD;AACD"}
|
|
1
|
+
{"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n\tPersistenceConfig,\n\tPersistenceBackend,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(options?: SqliteOptions): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tlet Database: SqliteDatabaseConstructor;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch (error) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tdbPath,\n\t\t\t\t\"SQLite persistence requires the optional 'better-sqlite3' package\",\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","error","PersistenceCompatibilityError","persistence","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","runSqliteTransaction","JSON","countRow","excess","numberField","runSqliteReadTransaction","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SqliteSchemaV2.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteSchemaV2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,eAAO,MAAM,oBAAoB,4tEAiEhC,CAAC;AAEF,eAAO,MAAM,wBAAwB,mEAC4B,CAAC;AAElE,KAAK,YAAY,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB,CAAC;AAuCF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,EAAE,CAOhG;
|
|
1
|
+
{"version":3,"file":"SqliteSchemaV2.d.ts","sourceRoot":"","sources":["../../src/persistence/SqliteSchemaV2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,eAAO,MAAM,oBAAoB,4tEAiEhC,CAAC;AAEF,eAAO,MAAM,wBAAwB,mEAC4B,CAAC;AAElE,KAAK,YAAY,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACrB,CAAC;AAuCF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,EAAE,CAOhG;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CA2BzF;AAED,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAS/F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PersistenceCompatibilityError
|
|
1
|
+
import { PersistenceCompatibilityError } from "../errors.js";
|
|
2
2
|
import { runSqliteTransaction } from "./SqliteDriver.js";
|
|
3
3
|
const SQLITE_V2_SCHEMA_DDL = `
|
|
4
4
|
CREATE TABLE schema_version (
|
|
@@ -96,21 +96,12 @@ function readSchemaObject(row, sourcePath) {
|
|
|
96
96
|
function sqliteSchemaObjects(database, sourcePath) {
|
|
97
97
|
return database.prepare("SELECT type, name, tbl_name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name").all().map((row)=>readSchemaObject(row, sourcePath));
|
|
98
98
|
}
|
|
99
|
-
function hasLegacyShape(objects) {
|
|
100
|
-
const names = new Set(objects.map(({ type, name })=>`${type}:${name}`));
|
|
101
|
-
return names.has('table:thoughts') && names.has('table:edges') && names.has('table:summaries') && !names.has('table:schema_version');
|
|
102
|
-
}
|
|
103
99
|
function validateSqliteV2Schema(database, sourcePath) {
|
|
104
100
|
const objects = sqliteSchemaObjects(database, sourcePath);
|
|
105
|
-
if (objects.length !== V2_OBJECTS.size)
|
|
106
|
-
if (hasLegacyShape(objects)) throw new PersistenceImportRequiredError(sourcePath, [
|
|
107
|
-
'unversioned SQLite v1 schema'
|
|
108
|
-
]);
|
|
109
|
-
throw new PersistenceCompatibilityError(sourcePath, 'SQLite v2 object set does not match');
|
|
110
|
-
}
|
|
101
|
+
if (objects.length !== V2_OBJECTS.size) throw new PersistenceCompatibilityError(sourcePath, 'database does not match SQLite v2 schema');
|
|
111
102
|
for (const object of objects){
|
|
112
103
|
const expected = V2_OBJECTS.get(`${object.type}:${object.name}`);
|
|
113
|
-
if (void 0 === expected || normalizeSql(object.sql) !== expected) throw new PersistenceCompatibilityError(sourcePath,
|
|
104
|
+
if (void 0 === expected || normalizeSql(object.sql) !== expected) throw new PersistenceCompatibilityError(sourcePath, 'database does not match SQLite v2 schema');
|
|
114
105
|
}
|
|
115
106
|
const versionRows = database.prepare('SELECT singleton, version FROM schema_version').all();
|
|
116
107
|
const versionRow = versionRows[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/SqliteSchemaV2.js","sources":["../../src/persistence/SqliteSchemaV2.ts"],"sourcesContent":["import { PersistenceCompatibilityError
|
|
1
|
+
{"version":3,"file":"persistence/SqliteSchemaV2.js","sources":["../../src/persistence/SqliteSchemaV2.ts"],"sourcesContent":["import { PersistenceCompatibilityError } from '../errors.js';\nimport type { SqliteDatabase } from './SqliteDriver.js';\nimport { runSqliteTransaction } from './SqliteDriver.js';\n\nexport const SQLITE_V2_SCHEMA_DDL = `\nCREATE TABLE schema_version (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 2)\n);\nCREATE TABLE thoughts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id TEXT NOT NULL,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n CHECK (length(session_id) BETWEEN 1 AND 100),\n CHECK (session_id NOT GLOB '*[^A-Za-z0-9_-]*')\n);\nCREATE INDEX idx_thoughts_session_id ON thoughts(session_id, id);\nCREATE TABLE branches (\n session_id TEXT NOT NULL,\n branch_id TEXT NOT NULL,\n data TEXT NOT NULL,\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n PRIMARY KEY (session_id, branch_id),\n CHECK (length(session_id) BETWEEN 1 AND 100),\n CHECK (session_id NOT GLOB '*[^A-Za-z0-9_-]*'),\n CHECK (length(branch_id) BETWEEN 1 AND 50),\n CHECK (branch_id NOT GLOB '*[^A-Za-z0-9_-]*')\n);\nCREATE TABLE edges (\n id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n metadata TEXT,\n PRIMARY KEY (session_id, id),\n CHECK (length(session_id) BETWEEN 1 AND 100),\n CHECK (session_id NOT GLOB '*[^A-Za-z0-9_-]*')\n);\nCREATE INDEX idx_edges_session_created ON edges(session_id, created_at, id);\nCREATE INDEX idx_edges_from ON edges(session_id, from_id);\nCREATE INDEX idx_edges_to ON edges(session_id, to_id);\nCREATE TABLE summaries (\n id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n branch_id TEXT,\n root_thought_id TEXT NOT NULL,\n covered_ids TEXT NOT NULL,\n covered_range_start INTEGER NOT NULL,\n covered_range_end INTEGER NOT NULL,\n topics TEXT NOT NULL,\n aggregate_confidence REAL NOT NULL,\n created_at INTEGER NOT NULL,\n meta TEXT,\n PRIMARY KEY (session_id, id),\n CHECK (length(session_id) BETWEEN 1 AND 100),\n CHECK (session_id NOT GLOB '*[^A-Za-z0-9_-]*'),\n CHECK (branch_id IS NULL OR (\n length(branch_id) BETWEEN 1 AND 50\n AND branch_id NOT GLOB '*[^A-Za-z0-9_-]*'\n )),\n CHECK (aggregate_confidence >= 0.0 AND aggregate_confidence <= 1.0)\n);\nCREATE INDEX idx_summaries_session_created\n ON summaries(session_id, created_at, id);\nCREATE INDEX idx_summaries_session_branch\n ON summaries(session_id, branch_id);\n`;\n\nexport const SQLITE_V2_VERSION_INSERT =\n\t'INSERT INTO schema_version (singleton, version) VALUES (1, 2);';\n\ntype SchemaObject = {\n\treadonly type: string;\n\treadonly name: string;\n\treadonly tableName: string;\n\treadonly sql: string;\n};\n\nfunction normalizeSql(sql: string): string {\n\treturn sql.replace(/\\s+/g, ' ').replace(/;$/, '').trim().toLowerCase();\n}\n\nfunction expectedV2Objects(): Map<string, string> {\n\tconst objects = new Map<string, string>();\n\tfor (const statement of SQLITE_V2_SCHEMA_DDL.split(';')\n\t\t.map((sql) => sql.trim())\n\t\t.filter(Boolean)) {\n\t\tconst match = /^CREATE\\s+(TABLE|INDEX)\\s+([^\\s(]+)/i.exec(statement);\n\t\tif (match?.[1] === undefined || match[2] === undefined) continue;\n\t\tobjects.set(`${match[1].toLowerCase()}:${match[2]}`, normalizeSql(statement));\n\t}\n\treturn objects;\n}\n\nconst V2_OBJECTS = expectedV2Objects();\n\nfunction readSchemaObject(row: unknown, sourcePath: string): SchemaObject {\n\tif (typeof row !== 'object' || row === null) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master row');\n\t}\n\tconst type = 'type' in row ? row.type : undefined;\n\tconst name = 'name' in row ? row.name : undefined;\n\tconst tableName = 'tbl_name' in row ? row.tbl_name : undefined;\n\tconst sql = 'sql' in row ? row.sql : undefined;\n\tif (\n\t\ttypeof type !== 'string' ||\n\t\ttypeof name !== 'string' ||\n\t\ttypeof tableName !== 'string' ||\n\t\ttypeof sql !== 'string'\n\t) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'invalid sqlite_master fields');\n\t}\n\treturn { type, name, tableName, sql };\n}\n\nexport function sqliteSchemaObjects(database: SqliteDatabase, sourcePath: string): SchemaObject[] {\n\treturn database\n\t\t.prepare(\n\t\t\t\"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE name NOT LIKE 'sqlite_%' ORDER BY type, name\"\n\t\t)\n\t\t.all()\n\t\t.map((row) => readSchemaObject(row, sourcePath));\n}\n\nexport function validateSqliteV2Schema(database: SqliteDatabase, sourcePath: string): void {\n\tconst objects = sqliteSchemaObjects(database, sourcePath);\n\tif (objects.length !== V2_OBJECTS.size) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'database does not match SQLite v2 schema');\n\t}\n\tfor (const object of objects) {\n\t\tconst expected = V2_OBJECTS.get(`${object.type}:${object.name}`);\n\t\tif (expected === undefined || normalizeSql(object.sql) !== expected) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, 'database does not match SQLite v2 schema');\n\t\t}\n\t}\n\tconst versionRows = database.prepare('SELECT singleton, version FROM schema_version').all();\n\tconst versionRow = versionRows[0];\n\tif (\n\t\tversionRows.length !== 1 ||\n\t\ttypeof versionRow !== 'object' ||\n\t\tversionRow === null ||\n\t\t!('singleton' in versionRow) ||\n\t\tversionRow.singleton !== 1 ||\n\t\t!('version' in versionRow) ||\n\t\tversionRow.version !== 2\n\t) {\n\t\tthrow new PersistenceCompatibilityError(\n\t\t\tsourcePath,\n\t\t\t'schema_version must contain exactly (1, 2)'\n\t\t);\n\t}\n}\n\nexport function initializeOrValidateSqliteV2(database: SqliteDatabase, sourcePath: string): void {\n\tconst objects = sqliteSchemaObjects(database, sourcePath);\n\tif (objects.length === 0) {\n\t\trunSqliteTransaction(database, () => {\n\t\t\tdatabase.exec(SQLITE_V2_SCHEMA_DDL);\n\t\t\tdatabase.exec(SQLITE_V2_VERSION_INSERT);\n\t\t});\n\t}\n\tvalidateSqliteV2Schema(database, sourcePath);\n}\n"],"names":["SQLITE_V2_SCHEMA_DDL","SQLITE_V2_VERSION_INSERT","normalizeSql","sql","expectedV2Objects","objects","Map","statement","Boolean","match","undefined","V2_OBJECTS","readSchemaObject","row","sourcePath","PersistenceCompatibilityError","type","name","tableName","sqliteSchemaObjects","database","validateSqliteV2Schema","object","expected","versionRows","versionRow","initializeOrValidateSqliteV2","runSqliteTransaction"],"mappings":"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"}
|
|
@@ -131,12 +131,12 @@ export declare class ConnectionPool implements IConnectionPool {
|
|
|
131
131
|
/**
|
|
132
132
|
* Process a thought in the specified session.
|
|
133
133
|
*
|
|
134
|
-
* @param
|
|
134
|
+
* @param poolSessionId - The pool slot ID, distinct from `input.session_id`
|
|
135
135
|
* @param input - The thought data to process
|
|
136
136
|
* @returns Promise with the processing result
|
|
137
137
|
* @throws Error if session not found
|
|
138
138
|
*/
|
|
139
|
-
process(
|
|
139
|
+
process(poolSessionId: SessionId, input: SessionThoughtInput): Promise<ProcessResult>;
|
|
140
140
|
runWithSession<T>(sessionId: SessionId, operation: (session: SessionServer) => Promise<T>): Promise<SessionRunResult<T>>;
|
|
141
141
|
private _runWithSession;
|
|
142
142
|
/**
|
|
@@ -173,17 +173,8 @@ export declare class ConnectionPool implements IConnectionPool {
|
|
|
173
173
|
* Remove timed-out sessions.
|
|
174
174
|
*/
|
|
175
175
|
private _cleanupTimedOutSessions;
|
|
176
|
-
/**
|
|
177
|
-
* Close all sessions and stop the cleanup timer.
|
|
178
|
-
*/
|
|
179
|
-
terminate(): Promise<void>;
|
|
180
|
-
private _completeTerminationGeneration;
|
|
181
|
-
/**
|
|
182
|
-
* Dispose of the connection pool, releasing all resources.
|
|
183
|
-
* Implements the IDisposable interface.
|
|
184
|
-
* Delegates to terminate() for backward compatibility.
|
|
185
|
-
*/
|
|
186
176
|
dispose(): Promise<void>;
|
|
177
|
+
private _completeTerminationGeneration;
|
|
187
178
|
/**
|
|
188
179
|
* Check if the connection pool is active.
|
|
189
180
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/ConnectionPool.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/ConnectionPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -177,15 +177,15 @@ class ConnectionPool {
|
|
|
177
177
|
this._createSessionLock = null;
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
async process(
|
|
181
|
-
const result = await this._runWithSession(
|
|
180
|
+
async process(poolSessionId, input) {
|
|
181
|
+
const result = await this._runWithSession(poolSessionId, (session)=>session.processAdmitted(input));
|
|
182
182
|
switch(result.status){
|
|
183
183
|
case 'completed':
|
|
184
184
|
return result.value;
|
|
185
185
|
case 'inactive':
|
|
186
|
-
throw new SessionNotActiveError(
|
|
186
|
+
throw new SessionNotActiveError(poolSessionId);
|
|
187
187
|
case 'missing':
|
|
188
|
-
throw new SessionNotFoundError(
|
|
188
|
+
throw new SessionNotFoundError(poolSessionId);
|
|
189
189
|
default:
|
|
190
190
|
return assertNever(result);
|
|
191
191
|
}
|
|
@@ -283,7 +283,7 @@ class ConnectionPool {
|
|
|
283
283
|
}
|
|
284
284
|
if (cleaned > 0) this._logger.info(`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`);
|
|
285
285
|
}
|
|
286
|
-
|
|
286
|
+
dispose() {
|
|
287
287
|
if (this._terminationGeneration) return this._terminationGeneration.completion.promise;
|
|
288
288
|
const completion = Promise.withResolvers();
|
|
289
289
|
const generation = {
|
|
@@ -313,9 +313,6 @@ class ConnectionPool {
|
|
|
313
313
|
this._logger.info('ConnectionPool terminated');
|
|
314
314
|
generation.completion.resolve();
|
|
315
315
|
}
|
|
316
|
-
dispose() {
|
|
317
|
-
return this.terminate();
|
|
318
|
-
}
|
|
319
316
|
isRunning() {
|
|
320
317
|
return !this._terminated;
|
|
321
318
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool/ConnectionPool.js","sources":["../../src/pool/ConnectionPool.ts"],"sourcesContent":["/**\n * Connection Pool for managing concurrent user sessions.\n *\n * This module provides session management for multi-user scenarios,\n * allowing multiple concurrent clients to each have isolated state.\n *\n * @example\n * ```typescript\n * const pool = new ConnectionPool({\n * maxSessions: 100,\n * sessionTimeout: 300000 // 5 minutes\n * });\n *\n * const sessionId = await pool.createSession();\n * await pool.process(sessionId, thought);\n * await pool.closeSession(sessionId);\n * ```\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { MaxSessionsReachedError, PoolTerminatedError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { asSessionId, type SessionId } from '../contracts/ids.js';\nimport { assertNever } from '../utils.js';\nimport { SessionNotActiveError, SessionNotFoundError } from './PoolErrors.js';\nimport type {\n\tConnectionPoolStats,\n\tIConnectionPool,\n\tProcessResult,\n\tSessionInfo,\n\tSessionRunResult,\n\tSessionServer,\n\tSessionThoughtInput,\n} from './IConnectionPool.js';\n\nexport interface SessionOptions {\n\t/**\n\t * Maximum number of concurrent sessions\n\t * @default 100\n\t */\n\tmaxSessions?: number;\n\n\t/**\n\t * Logger instance\n\t */\n\tlogger?: Logger;\n\n\tserverFactory?: () => Promise<SessionServer>;\n\n\t/**\n\t * Session timeout in milliseconds\n\t * @default 300000 (5 minutes)\n\t */\n\tsessionTimeout?: number;\n\n\t/**\n\t * Whether to enable automatic session cleanup\n\t * @default true\n\t */\n\tautoCleanup?: boolean;\n\n\t/**\n\t * Cleanup interval in milliseconds\n\t * @default 60000 (1 minute)\n\t */\n\tcleanupInterval?: number;\n}\n\n/**\n * Represents a user session with its own server instance.\n */\nexport class Session {\n\tprivate _server: SessionServer;\n\tprivate _id: SessionId;\n\tprivate _createdAt: number;\n\tprivate _lastActivityAt: number;\n\tprivate _isActiveValue: boolean;\n\tprivate _timeout: number;\n\tprivate _cleanupTimer: NodeJS.Timeout | null = null;\n\tprivate _logger: Logger;\n\tprivate _closePromise: Promise<void> | null = null;\n\tprivate _activeOperationCount = 0;\n\tprivate _operationDrain: PromiseWithResolvers<void> | null = null;\n\tprivate readonly _onTimeout: ((sessionId: SessionId) => void) | null;\n\n\tconstructor(\n\t\tid: SessionId,\n\t\tserver: SessionServer,\n\t\ttimeout: number,\n\t\tlogger: Logger,\n\t\tonTimeout: ((sessionId: SessionId) => void) | null = null\n\t) {\n\t\tthis._server = server;\n\t\tthis._id = id;\n\t\tthis._createdAt = Date.now();\n\t\tthis._lastActivityAt = this._createdAt;\n\t\tthis._isActiveValue = true;\n\t\tthis._timeout = timeout;\n\t\tthis._logger = logger;\n\t\tthis._onTimeout = onTimeout;\n\n\t\t// Start session timeout timer\n\t\tthis._startTimeout();\n\t}\n\n\t/**\n\t * Check if the session is active.\n\t */\n\tget isActive(): boolean {\n\t\treturn this._isActiveValue;\n\t}\n\n\t/**\n\t * Process a thought through this session's server instance.\n\t */\n\tasync process(input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tif (!this.isActive) {\n\t\t\tthrow new SessionNotActiveError(this._id);\n\t\t}\n\n\t\t// Update last activity\n\t\tthis._lastActivityAt = Date.now();\n\n\t\t// Reset timeout timer\n\t\tthis._resetTimeout();\n\n\t\t// Process the thought\n\t\treturn this._server.processThought(input);\n\t}\n\n\tprocessAdmitted(input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tthis._lastActivityAt = Date.now();\n\t\tif (this.isActive) this._resetTimeout();\n\t\treturn this._server.processThought(input);\n\t}\n\n\trunWhileActive<T>(operation: (session: Session) => Promise<T>): Promise<SessionRunResult<T>> {\n\t\tif (!this.isActive) return Promise.resolve({ status: 'inactive' });\n\t\tthis._activeOperationCount++;\n\t\treturn (async () => {\n\t\t\ttry {\n\t\t\t\treturn { status: 'completed', value: await operation(this) };\n\t\t\t} finally {\n\t\t\t\tthis._activeOperationCount--;\n\t\t\t\tif (this._activeOperationCount === 0) this._operationDrain?.resolve();\n\t\t\t}\n\t\t})();\n\t}\n\n\t/**\n\t * Get session information.\n\t */\n\tgetInfo(): SessionInfo {\n\t\treturn {\n\t\t\tid: this._id,\n\t\t\tserver: this._server,\n\t\t\tcreatedAt: this._createdAt,\n\t\t\tlastActivityAt: this._lastActivityAt,\n\t\t\tisActive: this.isActive,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the session has timed out.\n\t */\n\tisTimedOut(): boolean {\n\t\treturn Date.now() - this._lastActivityAt > this._timeout;\n\t}\n\n\t/**\n\t * Close the session and stop the server.\n\t */\n\tclose(): Promise<void> {\n\t\tif (this._closePromise) {\n\t\t\treturn this._closePromise;\n\t\t}\n\n\t\tconst completion = Promise.withResolvers<void>();\n\t\tthis._closePromise = completion.promise;\n\t\tvoid completion.promise.then(undefined, () => {\n\t\t\tif (this._closePromise === completion.promise) this._closePromise = null;\n\t\t});\n\t\tthis._isActiveValue = false;\n\n\t\t// Stop timeout timer\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t\tthis._cleanupTimer = null;\n\t\t}\n\n\t\tif (this._activeOperationCount === 0) {\n\t\t\tthis._stopServer(completion);\n\t\t} else {\n\t\t\tthis._operationDrain = Promise.withResolvers<void>();\n\t\t\tvoid this._operationDrain.promise.then(() => this._stopServer(completion));\n\t\t}\n\n\t\treturn completion.promise;\n\t}\n\n\tprivate _stopServer(completion: PromiseWithResolvers<void>): void {\n\t\ttry {\n\t\t\tPromise.resolve(this._server.stop()).then(completion.resolve, completion.reject);\n\t\t} catch (error) {\n\t\t\tcompletion.reject(\n\t\t\t\terror instanceof Error ? error : new AggregateError([error], 'Session stop failed')\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Start the session timeout timer.\n\t */\n\tprivate _startTimeout(): void {\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t}\n\n\t\tthis._cleanupTimer = setTimeout(() => {\n\t\t\tif (this.isTimedOut()) {\n\t\t\t\tthis._logger.warn(`Session ${this._id} timed out, closing`);\n\t\t\t\tif (this._onTimeout) {\n\t\t\t\t\tthis._onTimeout(this._id);\n\t\t\t\t} else {\n\t\t\t\t\tthis.close().catch((err) => {\n\t\t\t\t\t\tthis._logger.error(`Error closing timed out session ${this._id}:`, err);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}, this._timeout);\n\t}\n\n\t/**\n\t * Reset the timeout timer after activity.\n\t */\n\tprivate _resetTimeout(): void {\n\t\tthis._startTimeout();\n\t}\n}\n\ninterface TerminationGeneration {\n\treadonly attempts: Map<SessionId, Promise<void>>;\n\treadonly completion: PromiseWithResolvers<void>;\n}\n\n/**\n * ConnectionPool manages multiple concurrent user sessions.\n *\n * Each session has its own server instance with isolated state,\n * allowing multiple users to interact with the system simultaneously.\n */\nexport class ConnectionPool implements IConnectionPool {\n\tprivate _sessions: Map<SessionId, Session> = new Map();\n\tprivate readonly _ownedSessions = new Map<SessionId, Session>();\n\tprivate readonly _closingSessions = new Map<SessionId, Promise<void>>();\n\tprivate _createSessionLock: Promise<void> | null = null;\n\tprivate _maxSessions: number;\n\tprivate _sessionTimeout: number;\n\tprivate _autoCleanup: boolean;\n\tprivate _cleanupInterval: number;\n\tprivate _cleanupTimerId: ReturnType<typeof setInterval> | null = null;\n\tprivate _terminated: boolean = false;\n\tprivate _logger: Logger;\n\tprivate _serverFactory: (() => Promise<SessionServer>) | null;\n\tprivate _terminationGeneration: TerminationGeneration | null = null;\n\tprivate readonly _admissionContext = new AsyncLocalStorage<{\n\t\treadonly sessionId: SessionId;\n\t\treadonly session: Session;\n\t\topen: boolean;\n\t}>();\n\n\tconstructor(options: SessionOptions = {}) {\n\t\tthis._maxSessions = options.maxSessions ?? 100;\n\t\tthis._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes\n\t\tthis._autoCleanup = options.autoCleanup ?? true;\n\t\tthis._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute\n\t\tthis._serverFactory = options.serverFactory ?? null;\n\t\tthis._logger = options.logger ?? this._createNoopLogger();\n\n\t\tif (this._autoCleanup) {\n\t\t\tthis._startCleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Create a no-op logger when none is provided.\n\t */\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: (): void => {},\n\t\t\twarn: (): void => {},\n\t\t\terror: (): void => {},\n\t\t\tdebug: (): void => {},\n\t\t\tsetLevel: (): void => {},\n\t\t\tgetLevel: (): 'info' => 'info',\n\t\t};\n\t}\n\n\t/**\n\t * Create a new session.\n\t *\n\t * @returns The session ID\n\t * @throws Error if max sessions reached\n\t */\n\tasync createSession(): Promise<SessionId> {\n\t\twhile (this._createSessionLock) {\n\t\t\tawait this._createSessionLock;\n\t\t}\n\n\t\tif (this._terminated) {\n\t\t\tthrow new PoolTerminatedError();\n\t\t}\n\n\t\tif (this._ownedSessions.size >= this._maxSessions) {\n\t\t\tthrow new MaxSessionsReachedError(this._maxSessions);\n\t\t}\n\n\t\tif (!this._serverFactory) {\n\t\t\tthrow new Error('ConnectionPool requires a serverFactory option to create sessions');\n\t\t}\n\n\t\tlet resolveLock!: () => void;\n\t\tthis._createSessionLock = new Promise<void>((resolve) => {\n\t\t\tresolveLock = resolve;\n\t\t});\n\n\t\ttry {\n\t\t\t// Generate unique session ID\n\t\t\tconst sessionId = asSessionId(\n\t\t\t\t`session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`\n\t\t\t);\n\t\t\tif (this._ownedSessions.has(sessionId)) {\n\t\t\t\tthrow new Error(`Session ID collision: ${sessionId}`);\n\t\t\t}\n\n\t\t\t// Create a new server instance for this session\n\t\t\tconst server = await this._serverFactory();\n\t\t\tconst session = new Session(\n\t\t\t\tsessionId,\n\t\t\t\tserver,\n\t\t\t\tthis._sessionTimeout,\n\t\t\t\tthis._logger,\n\t\t\t\t(timedOutSessionId) => this._handleSessionTimeout(timedOutSessionId)\n\t\t\t);\n\t\t\tthis._ownedSessions.set(sessionId, session);\n\t\t\tif (this._terminated) {\n\t\t\t\tconst generation = this._terminationGeneration;\n\t\t\t\tif (generation) {\n\t\t\t\t\tawait this._coordinateCleanup(sessionId, generation);\n\t\t\t\t} else {\n\t\t\t\t\tawait this._coordinateCleanup(sessionId);\n\t\t\t\t}\n\t\t\t\tthrow new PoolTerminatedError();\n\t\t\t}\n\n\t\t\tthis._sessions.set(sessionId, session);\n\n\t\t\tthis._logger.info(\n\t\t\t\t`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t\treturn sessionId;\n\t\t} finally {\n\t\t\tresolveLock();\n\t\t\tthis._createSessionLock = null;\n\t\t}\n\t}\n\n\t/**\n\t * Process a thought in the specified session.\n\t *\n\t * @param sessionId - The session ID\n\t * @param input - The thought data to process\n\t * @returns Promise with the processing result\n\t * @throws Error if session not found\n\t */\n\tasync process(sessionId: SessionId, input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tconst result = await this._runWithSession(sessionId, (session) =>\n\t\t\tsession.processAdmitted(input)\n\t\t);\n\t\tswitch (result.status) {\n\t\t\tcase 'completed':\n\t\t\t\treturn result.value;\n\t\t\tcase 'inactive':\n\t\t\t\tthrow new SessionNotActiveError(sessionId);\n\t\t\tcase 'missing':\n\t\t\t\tthrow new SessionNotFoundError(sessionId);\n\t\t\tdefault:\n\t\t\t\treturn assertNever(result);\n\t\t}\n\t}\n\n\trunWithSession<T>(\n\t\tsessionId: SessionId,\n\t\toperation: (session: SessionServer) => Promise<T>\n\t): Promise<SessionRunResult<T>> {\n\t\treturn this._runWithSession(sessionId, (session) => operation(session.getInfo().server));\n\t}\n\n\tprivate _runWithSession<T>(\n\t\tsessionId: SessionId,\n\t\toperation: (session: Session) => Promise<T>\n\t): Promise<SessionRunResult<T>> {\n\t\tconst activeFrame = this._admissionContext.getStore();\n\t\tif (activeFrame?.open === true && activeFrame.sessionId === sessionId) {\n\t\t\treturn (async () => ({ status: 'completed', value: await operation(activeFrame.session) }))();\n\t\t}\n\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis._ownedSessions.has(sessionId) ? { status: 'inactive' } : { status: 'missing' }\n\t\t\t);\n\t\t}\n\n\t\treturn session.runWhileActive((capturedSession) => {\n\t\t\tconst frame = { sessionId, session: capturedSession, open: true };\n\t\t\treturn this._admissionContext.run(frame, async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await operation(capturedSession);\n\t\t\t\t} finally {\n\t\t\t\t\tframe.open = false;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Close a session and release resources.\n\t *\n\t * @param sessionId - The session ID to close\n\t * @throws Error if session not found\n\t */\n\tcloseSession(sessionId: SessionId): Promise<void> {\n\t\tif (!this._ownedSessions.has(sessionId)) {\n\t\t\treturn Promise.reject(new SessionNotFoundError(sessionId));\n\t\t}\n\n\t\tconst generation = this._terminationGeneration;\n\t\treturn generation\n\t\t\t? this._coordinateCleanup(sessionId, generation)\n\t\t\t: this._coordinateCleanup(sessionId);\n\t}\n\n\tprivate _coordinateCleanup(\n\t\tsessionId: SessionId,\n\t\tgeneration?: TerminationGeneration\n\t): Promise<void> {\n\t\tconst generationAttempt = generation?.attempts.get(sessionId);\n\t\tif (generationAttempt) return generationAttempt;\n\n\t\tconst session = this._ownedSessions.get(sessionId);\n\t\tif (!session) return Promise.reject(new SessionNotFoundError(sessionId));\n\n\t\tthis._sessions.delete(sessionId);\n\t\tconst currentAttempt = this._closingSessions.get(sessionId);\n\t\tconst attempt = currentAttempt ?? session.close();\n\t\tif (!currentAttempt) this._closingSessions.set(sessionId, attempt);\n\t\tgeneration?.attempts.set(sessionId, attempt);\n\n\t\tif (!currentAttempt)\n\t\t\tvoid attempt.then(\n\t\t\t\t() => {\n\t\t\t\t\tif (this._closingSessions.get(sessionId) === attempt) {\n\t\t\t\t\t\tthis._closingSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tif (this._ownedSessions.get(sessionId) === session) {\n\t\t\t\t\t\tthis._ownedSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tthis._logger.info(\n\t\t\t\t\t\t`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tif (this._closingSessions.get(sessionId) === attempt) {\n\t\t\t\t\t\tthis._closingSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\treturn attempt;\n\t}\n\n\tprivate _handleSessionTimeout(sessionId: SessionId): void {\n\t\tconst generation = this._terminationGeneration;\n\t\tconst attempt = generation\n\t\t\t? this._coordinateCleanup(sessionId, generation)\n\t\t\t: this._coordinateCleanup(sessionId);\n\t\tvoid attempt.catch((err) => {\n\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t});\n\t}\n\n\t/**\n\t * Get information about a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @returns Session info or undefined if not found\n\t */\n\tgetSessionInfo(sessionId: SessionId): SessionInfo | undefined {\n\t\treturn this._sessions.get(sessionId)?.getInfo();\n\t}\n\n\t/**\n\t * Get all active sessions.\n\t *\n\t * @returns Array of session information\n\t */\n\tgetActiveSessions(): SessionInfo[] {\n\t\treturn Array.from(this._sessions.values())\n\t\t\t.filter((s) => s.isActive)\n\t\t\t.map((s) => s.getInfo());\n\t}\n\n\t/**\n\t * Get connection pool statistics.\n\t */\n\tgetStats(): ConnectionPoolStats {\n\t\tconst activeSessions = this.getActiveSessions();\n\n\t\treturn {\n\t\t\ttotalSessions: this._sessions.size,\n\t\t\tactiveSessions: activeSessions.length,\n\t\t\tmaxSessions: this._maxSessions,\n\t\t\tcleanupEnabled: this._autoCleanup,\n\t\t\tsessionTimeout: this._sessionTimeout,\n\t\t};\n\t}\n\n\t/**\n\t * Start the automatic cleanup timer.\n\t */\n\tprivate _startCleanup(): void {\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t}\n\n\t\tthis._cleanupTimerId = setInterval(() => {\n\t\t\tthis._cleanupTimedOutSessions();\n\t\t}, this._cleanupInterval);\n\t}\n\n\t/**\n\t * Remove timed-out sessions.\n\t */\n\tprivate _cleanupTimedOutSessions(): void {\n\t\tlet cleaned = 0;\n\n\t\tfor (const [sessionId, session] of this._ownedSessions.entries()) {\n\t\t\tif (session.isTimedOut()) {\n\t\t\t\tthis._coordinateCleanup(sessionId).catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t\t\t});\n\t\t\t\tcleaned++;\n\t\t\t}\n\t\t}\n\n\t\tif (cleaned > 0) {\n\t\t\tthis._logger.info(\n\t\t\t\t`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Close all sessions and stop the cleanup timer.\n\t */\n\tterminate(): Promise<void> {\n\t\tif (this._terminationGeneration) {\n\t\t\treturn this._terminationGeneration.completion.promise;\n\t\t}\n\n\t\tconst completion = Promise.withResolvers<void>();\n\t\tconst generation: TerminationGeneration = { attempts: new Map(), completion };\n\t\tthis._terminationGeneration = generation;\n\t\tthis._terminated = true;\n\n\t\t// Stop cleanup timer\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t\tthis._cleanupTimerId = null;\n\t\t}\n\n\t\tconst pendingCreate = this._createSessionLock;\n\t\tfor (const sessionId of this._ownedSessions.keys()) {\n\t\t\tthis._coordinateCleanup(sessionId, generation);\n\t\t}\n\n\t\tvoid this._completeTerminationGeneration(generation, pendingCreate);\n\n\t\treturn completion.promise;\n\t}\n\n\tprivate async _completeTerminationGeneration(\n\t\tgeneration: TerminationGeneration,\n\t\tpendingCreate: Promise<void> | null\n\t): Promise<void> {\n\t\tif (pendingCreate) await pendingCreate;\n\t\tconst outcomes = await Promise.allSettled(generation.attempts.values());\n\t\tconst failures = outcomes\n\t\t\t.filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n\t\t\t.map((outcome) => outcome.reason);\n\t\tif (failures.length > 0) {\n\t\t\tif (this._terminationGeneration === generation) this._terminationGeneration = null;\n\t\t\tgeneration.completion.reject(\n\t\t\t\tnew AggregateError(failures, 'ConnectionPool termination failed')\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tthis._logger.info('ConnectionPool terminated');\n\t\tgeneration.completion.resolve();\n\t}\n\n\t/**\n\t * Dispose of the connection pool, releasing all resources.\n\t * Implements the IDisposable interface.\n\t * Delegates to terminate() for backward compatibility.\n\t */\n\tdispose(): Promise<void> {\n\t\treturn this.terminate();\n\t}\n\n\t/**\n\t * Check if the connection pool is active.\n\t */\n\tisRunning(): boolean {\n\t\treturn !this._terminated;\n\t}\n}\n\n/**\n * Create a connection pool with the given options.\n *\n * @param options - Connection pool configuration\n * @returns A configured connection pool\n *\n * @example\n * ```typescript\n * const pool = createConnectionPool({\n * maxSessions: 50,\n * sessionTimeout: 300000\n * });\n * ```\n */\nexport function createConnectionPool(options?: SessionOptions): ConnectionPool {\n\treturn new ConnectionPool(options);\n}\n"],"names":["Session","id","server","timeout","logger","onTimeout","Date","input","SessionNotActiveError","operation","Promise","completion","undefined","clearTimeout","error","Error","AggregateError","setTimeout","err","ConnectionPool","Map","AsyncLocalStorage","options","PoolTerminatedError","MaxSessionsReachedError","resolveLock","resolve","sessionId","asSessionId","Math","session","timedOutSessionId","generation","result","SessionNotFoundError","assertNever","activeFrame","capturedSession","frame","generationAttempt","currentAttempt","attempt","Array","s","activeSessions","clearInterval","setInterval","cleaned","pendingCreate","outcomes","failures","outcome","createConnectionPool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pool/ConnectionPool.js","sources":["../../src/pool/ConnectionPool.ts"],"sourcesContent":["/**\n * Connection Pool for managing concurrent user sessions.\n *\n * This module provides session management for multi-user scenarios,\n * allowing multiple concurrent clients to each have isolated state.\n *\n * @example\n * ```typescript\n * const pool = new ConnectionPool({\n * maxSessions: 100,\n * sessionTimeout: 300000 // 5 minutes\n * });\n *\n * const sessionId = await pool.createSession();\n * await pool.process(sessionId, thought);\n * await pool.closeSession(sessionId);\n * ```\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { MaxSessionsReachedError, PoolTerminatedError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { asSessionId, type SessionId } from '../contracts/ids.js';\nimport { assertNever } from '../utils.js';\nimport { SessionNotActiveError, SessionNotFoundError } from './PoolErrors.js';\nimport type {\n\tConnectionPoolStats,\n\tIConnectionPool,\n\tProcessResult,\n\tSessionInfo,\n\tSessionRunResult,\n\tSessionServer,\n\tSessionThoughtInput,\n} from './IConnectionPool.js';\n\nexport interface SessionOptions {\n\t/**\n\t * Maximum number of concurrent sessions\n\t * @default 100\n\t */\n\tmaxSessions?: number;\n\n\t/**\n\t * Logger instance\n\t */\n\tlogger?: Logger;\n\n\tserverFactory?: () => Promise<SessionServer>;\n\n\t/**\n\t * Session timeout in milliseconds\n\t * @default 300000 (5 minutes)\n\t */\n\tsessionTimeout?: number;\n\n\t/**\n\t * Whether to enable automatic session cleanup\n\t * @default true\n\t */\n\tautoCleanup?: boolean;\n\n\t/**\n\t * Cleanup interval in milliseconds\n\t * @default 60000 (1 minute)\n\t */\n\tcleanupInterval?: number;\n}\n\n/**\n * Represents a user session with its own server instance.\n */\nexport class Session {\n\tprivate _server: SessionServer;\n\tprivate _id: SessionId;\n\tprivate _createdAt: number;\n\tprivate _lastActivityAt: number;\n\tprivate _isActiveValue: boolean;\n\tprivate _timeout: number;\n\tprivate _cleanupTimer: NodeJS.Timeout | null = null;\n\tprivate _logger: Logger;\n\tprivate _closePromise: Promise<void> | null = null;\n\tprivate _activeOperationCount = 0;\n\tprivate _operationDrain: PromiseWithResolvers<void> | null = null;\n\tprivate readonly _onTimeout: ((sessionId: SessionId) => void) | null;\n\n\tconstructor(\n\t\tid: SessionId,\n\t\tserver: SessionServer,\n\t\ttimeout: number,\n\t\tlogger: Logger,\n\t\tonTimeout: ((sessionId: SessionId) => void) | null = null\n\t) {\n\t\tthis._server = server;\n\t\tthis._id = id;\n\t\tthis._createdAt = Date.now();\n\t\tthis._lastActivityAt = this._createdAt;\n\t\tthis._isActiveValue = true;\n\t\tthis._timeout = timeout;\n\t\tthis._logger = logger;\n\t\tthis._onTimeout = onTimeout;\n\n\t\t// Start session timeout timer\n\t\tthis._startTimeout();\n\t}\n\n\t/**\n\t * Check if the session is active.\n\t */\n\tget isActive(): boolean {\n\t\treturn this._isActiveValue;\n\t}\n\n\t/**\n\t * Process a thought through this session's server instance.\n\t */\n\tasync process(input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tif (!this.isActive) {\n\t\t\tthrow new SessionNotActiveError(this._id);\n\t\t}\n\n\t\t// Update last activity\n\t\tthis._lastActivityAt = Date.now();\n\n\t\t// Reset timeout timer\n\t\tthis._resetTimeout();\n\n\t\t// Process the thought\n\t\treturn this._server.processThought(input);\n\t}\n\n\tprocessAdmitted(input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tthis._lastActivityAt = Date.now();\n\t\tif (this.isActive) this._resetTimeout();\n\t\treturn this._server.processThought(input);\n\t}\n\n\trunWhileActive<T>(operation: (session: Session) => Promise<T>): Promise<SessionRunResult<T>> {\n\t\tif (!this.isActive) return Promise.resolve({ status: 'inactive' });\n\t\tthis._activeOperationCount++;\n\t\treturn (async () => {\n\t\t\ttry {\n\t\t\t\treturn { status: 'completed', value: await operation(this) };\n\t\t\t} finally {\n\t\t\t\tthis._activeOperationCount--;\n\t\t\t\tif (this._activeOperationCount === 0) this._operationDrain?.resolve();\n\t\t\t}\n\t\t})();\n\t}\n\n\t/**\n\t * Get session information.\n\t */\n\tgetInfo(): SessionInfo {\n\t\treturn {\n\t\t\tid: this._id,\n\t\t\tserver: this._server,\n\t\t\tcreatedAt: this._createdAt,\n\t\t\tlastActivityAt: this._lastActivityAt,\n\t\t\tisActive: this.isActive,\n\t\t};\n\t}\n\n\t/**\n\t * Check if the session has timed out.\n\t */\n\tisTimedOut(): boolean {\n\t\treturn Date.now() - this._lastActivityAt > this._timeout;\n\t}\n\n\t/**\n\t * Close the session and stop the server.\n\t */\n\tclose(): Promise<void> {\n\t\tif (this._closePromise) {\n\t\t\treturn this._closePromise;\n\t\t}\n\n\t\tconst completion = Promise.withResolvers<void>();\n\t\tthis._closePromise = completion.promise;\n\t\tvoid completion.promise.then(undefined, () => {\n\t\t\tif (this._closePromise === completion.promise) this._closePromise = null;\n\t\t});\n\t\tthis._isActiveValue = false;\n\n\t\t// Stop timeout timer\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t\tthis._cleanupTimer = null;\n\t\t}\n\n\t\tif (this._activeOperationCount === 0) {\n\t\t\tthis._stopServer(completion);\n\t\t} else {\n\t\t\tthis._operationDrain = Promise.withResolvers<void>();\n\t\t\tvoid this._operationDrain.promise.then(() => this._stopServer(completion));\n\t\t}\n\n\t\treturn completion.promise;\n\t}\n\n\tprivate _stopServer(completion: PromiseWithResolvers<void>): void {\n\t\ttry {\n\t\t\tPromise.resolve(this._server.stop()).then(completion.resolve, completion.reject);\n\t\t} catch (error) {\n\t\t\tcompletion.reject(\n\t\t\t\terror instanceof Error ? error : new AggregateError([error], 'Session stop failed')\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Start the session timeout timer.\n\t */\n\tprivate _startTimeout(): void {\n\t\tif (this._cleanupTimer) {\n\t\t\tclearTimeout(this._cleanupTimer);\n\t\t}\n\n\t\tthis._cleanupTimer = setTimeout(() => {\n\t\t\tif (this.isTimedOut()) {\n\t\t\t\tthis._logger.warn(`Session ${this._id} timed out, closing`);\n\t\t\t\tif (this._onTimeout) {\n\t\t\t\t\tthis._onTimeout(this._id);\n\t\t\t\t} else {\n\t\t\t\t\tthis.close().catch((err) => {\n\t\t\t\t\t\tthis._logger.error(`Error closing timed out session ${this._id}:`, err);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}, this._timeout);\n\t}\n\n\t/**\n\t * Reset the timeout timer after activity.\n\t */\n\tprivate _resetTimeout(): void {\n\t\tthis._startTimeout();\n\t}\n}\n\ninterface TerminationGeneration {\n\treadonly attempts: Map<SessionId, Promise<void>>;\n\treadonly completion: PromiseWithResolvers<void>;\n}\n\n/**\n * ConnectionPool manages multiple concurrent user sessions.\n *\n * Each session has its own server instance with isolated state,\n * allowing multiple users to interact with the system simultaneously.\n */\nexport class ConnectionPool implements IConnectionPool {\n\tprivate _sessions: Map<SessionId, Session> = new Map();\n\tprivate readonly _ownedSessions = new Map<SessionId, Session>();\n\tprivate readonly _closingSessions = new Map<SessionId, Promise<void>>();\n\tprivate _createSessionLock: Promise<void> | null = null;\n\tprivate _maxSessions: number;\n\tprivate _sessionTimeout: number;\n\tprivate _autoCleanup: boolean;\n\tprivate _cleanupInterval: number;\n\tprivate _cleanupTimerId: ReturnType<typeof setInterval> | null = null;\n\tprivate _terminated: boolean = false;\n\tprivate _logger: Logger;\n\tprivate _serverFactory: (() => Promise<SessionServer>) | null;\n\tprivate _terminationGeneration: TerminationGeneration | null = null;\n\tprivate readonly _admissionContext = new AsyncLocalStorage<{\n\t\treadonly sessionId: SessionId;\n\t\treadonly session: Session;\n\t\topen: boolean;\n\t}>();\n\n\tconstructor(options: SessionOptions = {}) {\n\t\tthis._maxSessions = options.maxSessions ?? 100;\n\t\tthis._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes\n\t\tthis._autoCleanup = options.autoCleanup ?? true;\n\t\tthis._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute\n\t\tthis._serverFactory = options.serverFactory ?? null;\n\t\tthis._logger = options.logger ?? this._createNoopLogger();\n\n\t\tif (this._autoCleanup) {\n\t\t\tthis._startCleanup();\n\t\t}\n\t}\n\n\t/**\n\t * Create a no-op logger when none is provided.\n\t */\n\tprivate _createNoopLogger(): Logger {\n\t\treturn {\n\t\t\tinfo: (): void => {},\n\t\t\twarn: (): void => {},\n\t\t\terror: (): void => {},\n\t\t\tdebug: (): void => {},\n\t\t\tsetLevel: (): void => {},\n\t\t\tgetLevel: (): 'info' => 'info',\n\t\t};\n\t}\n\n\t/**\n\t * Create a new session.\n\t *\n\t * @returns The session ID\n\t * @throws Error if max sessions reached\n\t */\n\tasync createSession(): Promise<SessionId> {\n\t\twhile (this._createSessionLock) {\n\t\t\tawait this._createSessionLock;\n\t\t}\n\n\t\tif (this._terminated) {\n\t\t\tthrow new PoolTerminatedError();\n\t\t}\n\n\t\tif (this._ownedSessions.size >= this._maxSessions) {\n\t\t\tthrow new MaxSessionsReachedError(this._maxSessions);\n\t\t}\n\n\t\tif (!this._serverFactory) {\n\t\t\tthrow new Error('ConnectionPool requires a serverFactory option to create sessions');\n\t\t}\n\n\t\tlet resolveLock!: () => void;\n\t\tthis._createSessionLock = new Promise<void>((resolve) => {\n\t\t\tresolveLock = resolve;\n\t\t});\n\n\t\ttry {\n\t\t\t// Generate unique session ID\n\t\t\tconst sessionId = asSessionId(\n\t\t\t\t`session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`\n\t\t\t);\n\t\t\tif (this._ownedSessions.has(sessionId)) {\n\t\t\t\tthrow new Error(`Session ID collision: ${sessionId}`);\n\t\t\t}\n\n\t\t\t// Create a new server instance for this session\n\t\t\tconst server = await this._serverFactory();\n\t\t\tconst session = new Session(\n\t\t\t\tsessionId,\n\t\t\t\tserver,\n\t\t\t\tthis._sessionTimeout,\n\t\t\t\tthis._logger,\n\t\t\t\t(timedOutSessionId) => this._handleSessionTimeout(timedOutSessionId)\n\t\t\t);\n\t\t\tthis._ownedSessions.set(sessionId, session);\n\t\t\tif (this._terminated) {\n\t\t\t\tconst generation = this._terminationGeneration;\n\t\t\t\tif (generation) {\n\t\t\t\t\tawait this._coordinateCleanup(sessionId, generation);\n\t\t\t\t} else {\n\t\t\t\t\tawait this._coordinateCleanup(sessionId);\n\t\t\t\t}\n\t\t\t\tthrow new PoolTerminatedError();\n\t\t\t}\n\n\t\t\tthis._sessions.set(sessionId, session);\n\n\t\t\tthis._logger.info(\n\t\t\t\t`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t\treturn sessionId;\n\t\t} finally {\n\t\t\tresolveLock();\n\t\t\tthis._createSessionLock = null;\n\t\t}\n\t}\n\n\t/**\n\t * Process a thought in the specified session.\n\t *\n\t * @param poolSessionId - The pool slot ID, distinct from `input.session_id`\n\t * @param input - The thought data to process\n\t * @returns Promise with the processing result\n\t * @throws Error if session not found\n\t */\n\tasync process(poolSessionId: SessionId, input: SessionThoughtInput): Promise<ProcessResult> {\n\t\tconst result = await this._runWithSession(poolSessionId, (session) =>\n\t\t\tsession.processAdmitted(input)\n\t\t);\n\t\tswitch (result.status) {\n\t\t\tcase 'completed':\n\t\t\t\treturn result.value;\n\t\t\tcase 'inactive':\n\t\t\t\tthrow new SessionNotActiveError(poolSessionId);\n\t\t\tcase 'missing':\n\t\t\t\tthrow new SessionNotFoundError(poolSessionId);\n\t\t\tdefault:\n\t\t\t\treturn assertNever(result);\n\t\t}\n\t}\n\n\trunWithSession<T>(\n\t\tsessionId: SessionId,\n\t\toperation: (session: SessionServer) => Promise<T>\n\t): Promise<SessionRunResult<T>> {\n\t\treturn this._runWithSession(sessionId, (session) => operation(session.getInfo().server));\n\t}\n\n\tprivate _runWithSession<T>(\n\t\tsessionId: SessionId,\n\t\toperation: (session: Session) => Promise<T>\n\t): Promise<SessionRunResult<T>> {\n\t\tconst activeFrame = this._admissionContext.getStore();\n\t\tif (activeFrame?.open === true && activeFrame.sessionId === sessionId) {\n\t\t\treturn (async () => ({ status: 'completed', value: await operation(activeFrame.session) }))();\n\t\t}\n\n\t\tconst session = this._sessions.get(sessionId);\n\t\tif (!session) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis._ownedSessions.has(sessionId) ? { status: 'inactive' } : { status: 'missing' }\n\t\t\t);\n\t\t}\n\n\t\treturn session.runWhileActive((capturedSession) => {\n\t\t\tconst frame = { sessionId, session: capturedSession, open: true };\n\t\t\treturn this._admissionContext.run(frame, async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await operation(capturedSession);\n\t\t\t\t} finally {\n\t\t\t\t\tframe.open = false;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Close a session and release resources.\n\t *\n\t * @param sessionId - The session ID to close\n\t * @throws Error if session not found\n\t */\n\tcloseSession(sessionId: SessionId): Promise<void> {\n\t\tif (!this._ownedSessions.has(sessionId)) {\n\t\t\treturn Promise.reject(new SessionNotFoundError(sessionId));\n\t\t}\n\n\t\tconst generation = this._terminationGeneration;\n\t\treturn generation\n\t\t\t? this._coordinateCleanup(sessionId, generation)\n\t\t\t: this._coordinateCleanup(sessionId);\n\t}\n\n\tprivate _coordinateCleanup(\n\t\tsessionId: SessionId,\n\t\tgeneration?: TerminationGeneration\n\t): Promise<void> {\n\t\tconst generationAttempt = generation?.attempts.get(sessionId);\n\t\tif (generationAttempt) return generationAttempt;\n\n\t\tconst session = this._ownedSessions.get(sessionId);\n\t\tif (!session) return Promise.reject(new SessionNotFoundError(sessionId));\n\n\t\tthis._sessions.delete(sessionId);\n\t\tconst currentAttempt = this._closingSessions.get(sessionId);\n\t\tconst attempt = currentAttempt ?? session.close();\n\t\tif (!currentAttempt) this._closingSessions.set(sessionId, attempt);\n\t\tgeneration?.attempts.set(sessionId, attempt);\n\n\t\tif (!currentAttempt)\n\t\t\tvoid attempt.then(\n\t\t\t\t() => {\n\t\t\t\t\tif (this._closingSessions.get(sessionId) === attempt) {\n\t\t\t\t\t\tthis._closingSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tif (this._ownedSessions.get(sessionId) === session) {\n\t\t\t\t\t\tthis._ownedSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t\tthis._logger.info(\n\t\t\t\t\t\t`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tif (this._closingSessions.get(sessionId) === attempt) {\n\t\t\t\t\t\tthis._closingSessions.delete(sessionId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t);\n\t\treturn attempt;\n\t}\n\n\tprivate _handleSessionTimeout(sessionId: SessionId): void {\n\t\tconst generation = this._terminationGeneration;\n\t\tconst attempt = generation\n\t\t\t? this._coordinateCleanup(sessionId, generation)\n\t\t\t: this._coordinateCleanup(sessionId);\n\t\tvoid attempt.catch((err) => {\n\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t});\n\t}\n\n\t/**\n\t * Get information about a session.\n\t *\n\t * @param sessionId - The session ID\n\t * @returns Session info or undefined if not found\n\t */\n\tgetSessionInfo(sessionId: SessionId): SessionInfo | undefined {\n\t\treturn this._sessions.get(sessionId)?.getInfo();\n\t}\n\n\t/**\n\t * Get all active sessions.\n\t *\n\t * @returns Array of session information\n\t */\n\tgetActiveSessions(): SessionInfo[] {\n\t\treturn Array.from(this._sessions.values())\n\t\t\t.filter((s) => s.isActive)\n\t\t\t.map((s) => s.getInfo());\n\t}\n\n\t/**\n\t * Get connection pool statistics.\n\t */\n\tgetStats(): ConnectionPoolStats {\n\t\tconst activeSessions = this.getActiveSessions();\n\n\t\treturn {\n\t\t\ttotalSessions: this._sessions.size,\n\t\t\tactiveSessions: activeSessions.length,\n\t\t\tmaxSessions: this._maxSessions,\n\t\t\tcleanupEnabled: this._autoCleanup,\n\t\t\tsessionTimeout: this._sessionTimeout,\n\t\t};\n\t}\n\n\t/**\n\t * Start the automatic cleanup timer.\n\t */\n\tprivate _startCleanup(): void {\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t}\n\n\t\tthis._cleanupTimerId = setInterval(() => {\n\t\t\tthis._cleanupTimedOutSessions();\n\t\t}, this._cleanupInterval);\n\t}\n\n\t/**\n\t * Remove timed-out sessions.\n\t */\n\tprivate _cleanupTimedOutSessions(): void {\n\t\tlet cleaned = 0;\n\n\t\tfor (const [sessionId, session] of this._ownedSessions.entries()) {\n\t\t\tif (session.isTimedOut()) {\n\t\t\t\tthis._coordinateCleanup(sessionId).catch((err) => {\n\t\t\t\t\tthis._logger.error(`Error closing timed out session ${sessionId}:`, err);\n\t\t\t\t});\n\t\t\t\tcleaned++;\n\t\t\t}\n\t\t}\n\n\t\tif (cleaned > 0) {\n\t\t\tthis._logger.info(\n\t\t\t\t`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`\n\t\t\t);\n\t\t}\n\t}\n\n\tdispose(): Promise<void> {\n\t\tif (this._terminationGeneration) {\n\t\t\treturn this._terminationGeneration.completion.promise;\n\t\t}\n\n\t\tconst completion = Promise.withResolvers<void>();\n\t\tconst generation: TerminationGeneration = { attempts: new Map(), completion };\n\t\tthis._terminationGeneration = generation;\n\t\tthis._terminated = true;\n\n\t\t// Stop cleanup timer\n\t\tif (this._cleanupTimerId !== null) {\n\t\t\tclearInterval(this._cleanupTimerId);\n\t\t\tthis._cleanupTimerId = null;\n\t\t}\n\n\t\tconst pendingCreate = this._createSessionLock;\n\t\tfor (const sessionId of this._ownedSessions.keys()) {\n\t\t\tthis._coordinateCleanup(sessionId, generation);\n\t\t}\n\n\t\tvoid this._completeTerminationGeneration(generation, pendingCreate);\n\n\t\treturn completion.promise;\n\t}\n\n\tprivate async _completeTerminationGeneration(\n\t\tgeneration: TerminationGeneration,\n\t\tpendingCreate: Promise<void> | null\n\t): Promise<void> {\n\t\tif (pendingCreate) await pendingCreate;\n\t\tconst outcomes = await Promise.allSettled(generation.attempts.values());\n\t\tconst failures = outcomes\n\t\t\t.filter((outcome): outcome is PromiseRejectedResult => outcome.status === 'rejected')\n\t\t\t.map((outcome) => outcome.reason);\n\t\tif (failures.length > 0) {\n\t\t\tif (this._terminationGeneration === generation) this._terminationGeneration = null;\n\t\t\tgeneration.completion.reject(\n\t\t\t\tnew AggregateError(failures, 'ConnectionPool termination failed')\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tthis._logger.info('ConnectionPool terminated');\n\t\tgeneration.completion.resolve();\n\t}\n\n\t/**\n\t * Check if the connection pool is active.\n\t */\n\tisRunning(): boolean {\n\t\treturn !this._terminated;\n\t}\n}\n\n/**\n * Create a connection pool with the given options.\n *\n * @param options - Connection pool configuration\n * @returns A configured connection pool\n *\n * @example\n * ```typescript\n * const pool = createConnectionPool({\n * maxSessions: 50,\n * sessionTimeout: 300000\n * });\n * ```\n */\nexport function createConnectionPool(options?: SessionOptions): ConnectionPool {\n\treturn new ConnectionPool(options);\n}\n"],"names":["Session","id","server","timeout","logger","onTimeout","Date","input","SessionNotActiveError","operation","Promise","completion","undefined","clearTimeout","error","Error","AggregateError","setTimeout","err","ConnectionPool","Map","AsyncLocalStorage","options","PoolTerminatedError","MaxSessionsReachedError","resolveLock","resolve","sessionId","asSessionId","Math","session","timedOutSessionId","generation","poolSessionId","result","SessionNotFoundError","assertNever","activeFrame","capturedSession","frame","generationAttempt","currentAttempt","attempt","Array","s","activeSessions","clearInterval","setInterval","cleaned","pendingCreate","outcomes","failures","outcome","createConnectionPool"],"mappings":"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"}
|
|
@@ -82,12 +82,12 @@ export interface IConnectionPool extends IDisposable {
|
|
|
82
82
|
/**
|
|
83
83
|
* Process a thought in the specified session.
|
|
84
84
|
*
|
|
85
|
-
* @param
|
|
85
|
+
* @param poolSessionId - The pool slot ID, distinct from `input.session_id`
|
|
86
86
|
* @param input - The thought data to process
|
|
87
87
|
* @returns The processing result
|
|
88
88
|
* @throws SessionNotFoundError if the session does not exist
|
|
89
89
|
*/
|
|
90
|
-
process(
|
|
90
|
+
process(poolSessionId: SessionId, input: SessionThoughtInput): Promise<ProcessResult>;
|
|
91
91
|
/**
|
|
92
92
|
* Run an operation while atomically holding an active session open.
|
|
93
93
|
*
|
|
@@ -122,15 +122,9 @@ export interface IConnectionPool extends IDisposable {
|
|
|
122
122
|
* @returns A snapshot of the pool's statistics
|
|
123
123
|
*/
|
|
124
124
|
getStats(): ConnectionPoolStats;
|
|
125
|
-
/**
|
|
126
|
-
* Close all sessions and stop the cleanup timer.
|
|
127
|
-
*/
|
|
128
|
-
terminate(): Promise<void>;
|
|
129
125
|
/**
|
|
130
126
|
* Dispose of the connection pool, releasing all resources.
|
|
131
|
-
*
|
|
132
|
-
* Implements the {@link IDisposable} interface. Typically delegates
|
|
133
|
-
* to {@link IConnectionPool.terminate}.
|
|
127
|
+
* Implements the {@link IDisposable} interface.
|
|
134
128
|
*/
|
|
135
129
|
dispose(): Promise<void>;
|
|
136
130
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/IConnectionPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD;;;;;;OAMG;IACH,aAAa,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAEpC;;;;;;;OAOG;IACH,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"IConnectionPool.d.ts","sourceRoot":"","sources":["../../src/pool/IConnectionPool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD;;;;;;OAMG;IACH,aAAa,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAEpC;;;;;;;OAOG;IACH,OAAO,CAAC,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEtF;;;;;;OAMG;IACH,cAAc,CAAC,CAAC,EACf,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhC;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElD;;;;;OAKG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;IAE9D;;;;OAIG;IACH,iBAAiB,IAAI,WAAW,EAAE,CAAC;IAEnC;;;;OAIG;IACH,QAAQ,IAAI,mBAAmB,CAAC;IAEhC;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;;OAIG;IACH,SAAS,IAAI,OAAO,CAAC;CACrB"}
|
|
@@ -43,8 +43,7 @@ export interface SkillRegistryOptions {
|
|
|
43
43
|
/**
|
|
44
44
|
* Registry for managing Claude Code skill operations.
|
|
45
45
|
*
|
|
46
|
-
* Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing
|
|
47
|
-
* and backward-compatible aliases (`addSkill`, etc.).
|
|
46
|
+
* Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing.
|
|
48
47
|
*/
|
|
49
48
|
export declare class SkillRegistry extends BaseRegistry<Skill> {
|
|
50
49
|
protected readonly _fileExtensions: string[];
|
|
@@ -58,10 +57,5 @@ export declare class SkillRegistry extends BaseRegistry<Skill> {
|
|
|
58
57
|
_error?: string;
|
|
59
58
|
};
|
|
60
59
|
protected _buildItem(parsed: Partial<Skill>): Skill | null;
|
|
61
|
-
addSkill(skill: Skill): void;
|
|
62
|
-
updateSkill(name: string, updates: Partial<Skill>): void;
|
|
63
|
-
hasSkill(name: string): boolean;
|
|
64
|
-
getSkill(name: string): Skill | undefined;
|
|
65
|
-
setSkills(skills: Skill[]): void;
|
|
66
60
|
}
|
|
67
61
|
//# sourceMappingURL=SkillRegistry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkillRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/SkillRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACpC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAE9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED
|
|
1
|
+
{"version":3,"file":"SkillRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/SkillRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACpC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAE9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,YAAY,CAAC,KAAK,CAAC;IACrD,mBAA4B,eAAe,WAA4B;IACvE,mBAA4B,WAAW,WAAW;gBAEtC,OAAO,GAAE,oBAAyB;cAgB3B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;cAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;cAI1C,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;cAMzD,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAI1C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;cA6BxE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI;CAWnE"}
|