@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
|
@@ -36,7 +36,6 @@ import type { LogLevel, Logger, LoggerOptions } from './StructuredLogger.js';
|
|
|
36
36
|
* logger.warn('Or this warning');
|
|
37
37
|
* logger.error('Or even this error');
|
|
38
38
|
*
|
|
39
|
-
* // Methods exist for compatibility but have no effect
|
|
40
39
|
* logger.setLevel('debug');
|
|
41
40
|
* const level = logger.getLevel(); // Returns 'error' (default)
|
|
42
41
|
* ```
|
|
@@ -47,14 +46,14 @@ export declare class NullLogger implements Logger {
|
|
|
47
46
|
*
|
|
48
47
|
* @remarks
|
|
49
48
|
* Since all messages are discarded, the level setting has no practical
|
|
50
|
-
* effect.
|
|
49
|
+
* effect. The value is retained to satisfy the logger contract.
|
|
51
50
|
* @private
|
|
52
51
|
*/
|
|
53
52
|
private _level;
|
|
54
53
|
/**
|
|
55
54
|
* Creates a new NullLogger instance.
|
|
56
55
|
*
|
|
57
|
-
* @param options - Configuration options
|
|
56
|
+
* @param options - Configuration options used to initialize the logger contract
|
|
58
57
|
*
|
|
59
58
|
* @example
|
|
60
59
|
* ```typescript
|
|
@@ -73,7 +72,7 @@ export declare class NullLogger implements Logger {
|
|
|
73
72
|
/**
|
|
74
73
|
* Log a debug message (no-op).
|
|
75
74
|
*
|
|
76
|
-
* This
|
|
75
|
+
* This logger discards the message.
|
|
77
76
|
*
|
|
78
77
|
* @param _message - Ignored
|
|
79
78
|
* @param _meta - Ignored
|
|
@@ -82,7 +81,7 @@ export declare class NullLogger implements Logger {
|
|
|
82
81
|
/**
|
|
83
82
|
* Log an info message (no-op).
|
|
84
83
|
*
|
|
85
|
-
* This
|
|
84
|
+
* This logger discards the message.
|
|
86
85
|
*
|
|
87
86
|
* @param _message - Ignored
|
|
88
87
|
* @param _meta - Ignored
|
|
@@ -91,7 +90,7 @@ export declare class NullLogger implements Logger {
|
|
|
91
90
|
/**
|
|
92
91
|
* Log a warning message (no-op).
|
|
93
92
|
*
|
|
94
|
-
* This
|
|
93
|
+
* This logger discards the message.
|
|
95
94
|
*
|
|
96
95
|
* @param _message - Ignored
|
|
97
96
|
* @param _meta - Ignored
|
|
@@ -100,7 +99,7 @@ export declare class NullLogger implements Logger {
|
|
|
100
99
|
/**
|
|
101
100
|
* Log an error message (no-op).
|
|
102
101
|
*
|
|
103
|
-
* This
|
|
102
|
+
* This logger discards the message.
|
|
104
103
|
*
|
|
105
104
|
* @param _message - Ignored
|
|
106
105
|
* @param _meta - Ignored
|
|
@@ -109,8 +108,8 @@ export declare class NullLogger implements Logger {
|
|
|
109
108
|
/**
|
|
110
109
|
* Sets the minimum log level (no-op).
|
|
111
110
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
111
|
+
* The level is retained for `getLevel` and child loggers, but does not
|
|
112
|
+
* affect output because all messages are discarded.
|
|
114
113
|
*
|
|
115
114
|
* @param level - The new minimum log level (ignored)
|
|
116
115
|
*
|
|
@@ -135,8 +134,7 @@ export declare class NullLogger implements Logger {
|
|
|
135
134
|
/**
|
|
136
135
|
* Creates a child null logger (returns a new NullLogger).
|
|
137
136
|
*
|
|
138
|
-
*
|
|
139
|
-
* `NullLogger` instance (not a child with extended context) since
|
|
137
|
+
* Returns a new `NullLogger` instance (not a child with extended context) since
|
|
140
138
|
* context tracking is not applicable for a no-op logger.
|
|
141
139
|
*
|
|
142
140
|
* @param _context - Additional context (ignored)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NullLogger.d.ts","sourceRoot":"","sources":["../../src/logger/NullLogger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE7E
|
|
1
|
+
{"version":3,"file":"NullLogger.d.ts","sourceRoot":"","sources":["../../src/logger/NullLogger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,UAAW,YAAW,MAAM;IACxC;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAW;IAEzB;;;;;;;;;;;;;;;;;OAiBG;gBACS,OAAO,GAAE,aAAkB;IAIvC;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAE9D;;;;;;;OAOG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAE7D;;;;;;;OAOG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAE7D;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAE9D;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,QAAQ;IAIpB;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU;CAGzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger/NullLogger.js","sources":["../../src/logger/NullLogger.ts"],"sourcesContent":["/**\n * Null logger that discards all log messages.\n *\n * This logger implements the same interface as `StructuredLogger` but\n * silently discards all log messages. It's useful as a default/fallback\n * logger when logging is disabled or when no logger is provided.\n *\n * @module logger\n */\n\nimport type { LogLevel, Logger, LoggerOptions } from './StructuredLogger.js';\n\n/**\n * Null logger that discards all log messages.\n *\n * This class provides a no-op implementation of the logger interface.\n * All method calls are silent and have no effect, making it suitable\n * for use as a default logger when logging is disabled or not needed.\n *\n * @remarks\n * The `NullLogger` implements the same interface as `StructuredLogger`,\n * making them interchangeable. Use `NullLogger` when:\n * - You want to disable logging completely\n * - You need a logger placeholder that can be swapped later\n * - Testing components that don't need output\n * - Reducing overhead in performance-critical sections\n *\n * @example\n * ```typescript\n * import { NullLogger } from './logger/index.js';\n *\n * // Create a null logger\n * const logger = new NullLogger();\n *\n * // All log calls are silently discarded\n * logger.debug('This will not appear');\n * logger.info('Nor will this');\n * logger.warn('Or this warning');\n * logger.error('Or even this error');\n *\n *
|
|
1
|
+
{"version":3,"file":"logger/NullLogger.js","sources":["../../src/logger/NullLogger.ts"],"sourcesContent":["/**\n * Null logger that discards all log messages.\n *\n * This logger implements the same interface as `StructuredLogger` but\n * silently discards all log messages. It's useful as a default/fallback\n * logger when logging is disabled or when no logger is provided.\n *\n * @module logger\n */\n\nimport type { LogLevel, Logger, LoggerOptions } from './StructuredLogger.js';\n\n/**\n * Null logger that discards all log messages.\n *\n * This class provides a no-op implementation of the logger interface.\n * All method calls are silent and have no effect, making it suitable\n * for use as a default logger when logging is disabled or not needed.\n *\n * @remarks\n * The `NullLogger` implements the same interface as `StructuredLogger`,\n * making them interchangeable. Use `NullLogger` when:\n * - You want to disable logging completely\n * - You need a logger placeholder that can be swapped later\n * - Testing components that don't need output\n * - Reducing overhead in performance-critical sections\n *\n * @example\n * ```typescript\n * import { NullLogger } from './logger/index.js';\n *\n * // Create a null logger\n * const logger = new NullLogger();\n *\n * // All log calls are silently discarded\n * logger.debug('This will not appear');\n * logger.info('Nor will this');\n * logger.warn('Or this warning');\n * logger.error('Or even this error');\n *\n * logger.setLevel('debug');\n * const level = logger.getLevel(); // Returns 'error' (default)\n * ```\n */\nexport class NullLogger implements Logger {\n\t/**\n\t * Current minimum log level.\n\t *\n\t * @remarks\n\t * Since all messages are discarded, the level setting has no practical\n\t * effect. The value is retained to satisfy the logger contract.\n\t * @private\n\t */\n\tprivate _level: LogLevel;\n\n\t/**\n\t * Creates a new NullLogger instance.\n\t *\n\t * @param options - Configuration options used to initialize the logger contract\n\t *\n\t * @example\n\t * ```typescript\n\t * // Create a null logger\n\t * const logger1 = new NullLogger();\n\t *\n\t * // With options (ignored)\n\t * const logger2 = new NullLogger({\n\t * level: 'debug',\n\t * context: 'MyApp',\n\t * pretty: true\n\t * });\n\t * ```\n\t */\n\tconstructor(options: LoggerOptions = {}) {\n\t\tthis._level = options.level ?? 'error';\n\t}\n\n\t/**\n\t * Log a debug message (no-op).\n\t *\n\t * This logger discards the message.\n\t *\n\t * @param _message - Ignored\n\t * @param _meta - Ignored\n\t */\n\tdebug(_message: string, _meta?: Record<string, unknown>): void {}\n\n\t/**\n\t * Log an info message (no-op).\n\t *\n\t * This logger discards the message.\n\t *\n\t * @param _message - Ignored\n\t * @param _meta - Ignored\n\t */\n\tinfo(_message: string, _meta?: Record<string, unknown>): void {}\n\n\t/**\n\t * Log a warning message (no-op).\n\t *\n\t * This logger discards the message.\n\t *\n\t * @param _message - Ignored\n\t * @param _meta - Ignored\n\t */\n\twarn(_message: string, _meta?: Record<string, unknown>): void {}\n\n\t/**\n\t * Log an error message (no-op).\n\t *\n\t * This logger discards the message.\n\t *\n\t * @param _message - Ignored\n\t * @param _meta - Ignored\n\t */\n\terror(_message: string, _meta?: Record<string, unknown>): void {}\n\n\t/**\n\t * Sets the minimum log level (no-op).\n\t *\n\t * The level is retained for `getLevel` and child loggers, but does not\n\t * affect output because all messages are discarded.\n\t *\n\t * @param level - The new minimum log level (ignored)\n\t *\n\t * @example\n\t * ```typescript\n\t * logger.setLevel('debug'); // No effect\n\t * ```\n\t */\n\tsetLevel(level: LogLevel): void {\n\t\tthis._level = level;\n\t}\n\n\t/**\n\t * Gets the current minimum log level.\n\t *\n\t * @returns The current log level (stored value, unused)\n\t *\n\t * @example\n\t * ```typescript\n\t * const currentLevel = logger.getLevel();\n\t * console.log(`Current level: ${currentLevel}`); // 'error' by default\n\t * ```\n\t */\n\tgetLevel(): LogLevel {\n\t\treturn this._level;\n\t}\n\n\t/**\n\t * Creates a child null logger (returns a new NullLogger).\n\t *\n\t * Returns a new `NullLogger` instance (not a child with extended context) since\n\t * context tracking is not applicable for a no-op logger.\n\t *\n\t * @param _context - Additional context (ignored)\n\t * @returns A new NullLogger instance\n\t *\n\t * @example\n\t * ```typescript\n\t * const nullLogger = new NullLogger();\n\t * const childLogger = nullLogger.createChild('ChildModule');\n\t * // childLogger is also a NullLogger\n\t * ```\n\t */\n\tcreateChild(_context: string): NullLogger {\n\t\treturn new NullLogger({ level: this._level });\n\t}\n}\n"],"names":["NullLogger","options","_message","_meta","level","_context"],"mappings":"AA4CO,MAAMA;IASJ,OAAiB;IAoBzB,YAAYC,UAAyB,CAAC,CAAC,CAAE;QACxC,IAAI,CAAC,MAAM,GAAGA,QAAQ,KAAK,IAAI;IAChC;IAUA,MAAMC,QAAgB,EAAEC,KAA+B,EAAQ,CAAC;IAUhE,KAAKD,QAAgB,EAAEC,KAA+B,EAAQ,CAAC;IAU/D,KAAKD,QAAgB,EAAEC,KAA+B,EAAQ,CAAC;IAU/D,MAAMD,QAAgB,EAAEC,KAA+B,EAAQ,CAAC;IAehE,SAASC,KAAe,EAAQ;QAC/B,IAAI,CAAC,MAAM,GAAGA;IACf;IAaA,WAAqB;QACpB,OAAO,IAAI,CAAC,MAAM;IACnB;IAkBA,YAAYC,QAAgB,EAAc;QACzC,OAAO,IAAIL,WAAW;YAAE,OAAO,IAAI,CAAC,MAAM;QAAC;IAC5C;AACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IMetrics } from '../contracts/interfaces.js';
|
|
2
|
-
import type { PersistenceConfig,
|
|
2
|
+
import type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
3
3
|
import { type BranchId, type SessionId } from '../contracts/ids.js';
|
|
4
4
|
import type { Summary } from '../core/compression/Summary.js';
|
|
5
5
|
import type { Edge } from '../core/graph/Edge.js';
|
|
@@ -9,7 +9,7 @@ type FilePersistenceOptions = NonNullable<PersistenceConfig['options']> & {
|
|
|
9
9
|
readonly metrics?: IMetrics;
|
|
10
10
|
readonly writerOperations?: FileWriterOperations;
|
|
11
11
|
};
|
|
12
|
-
export declare class FilePersistence implements
|
|
12
|
+
export declare class FilePersistence implements PersistenceBackend {
|
|
13
13
|
private readonly _dataDir;
|
|
14
14
|
private readonly _maxHistorySize;
|
|
15
15
|
private readonly _persistBranches;
|
|
@@ -17,36 +17,27 @@ export declare class FilePersistence implements SessionScopedPersistenceBackend
|
|
|
17
17
|
private readonly _writer;
|
|
18
18
|
constructor(options?: FilePersistenceOptions);
|
|
19
19
|
static create(options?: FilePersistenceOptions): Promise<FilePersistence>;
|
|
20
|
-
saveThought(thought: ThoughtData): Promise<void>;
|
|
21
20
|
saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;
|
|
22
21
|
private _saveThought;
|
|
23
|
-
loadHistory(): Promise<ThoughtData[]>;
|
|
24
22
|
loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;
|
|
25
|
-
saveBranch(branchId: BranchId, thoughts: ThoughtData[]): Promise<void>;
|
|
26
23
|
saveBranchForSession(sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): Promise<void>;
|
|
27
24
|
private _saveBranch;
|
|
28
|
-
deleteBranch(branchId: BranchId): Promise<void>;
|
|
29
25
|
deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void>;
|
|
30
|
-
loadBranch(branchId: BranchId): Promise<ThoughtData[] | undefined>;
|
|
31
26
|
loadBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<ThoughtData[] | undefined>;
|
|
32
|
-
listBranches(): Promise<BranchId[]>;
|
|
33
27
|
listBranchesForSession(sessionId: SessionId): Promise<BranchId[]>;
|
|
34
28
|
listSessions(): Promise<SessionId[]>;
|
|
35
|
-
|
|
29
|
+
clearAll(): Promise<void>;
|
|
36
30
|
clearSession(sessionId: SessionId): Promise<void>;
|
|
37
31
|
saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void>;
|
|
38
32
|
loadEdges(sessionId: SessionId): Promise<Edge[]>;
|
|
39
|
-
listEdgeSessions(): Promise<SessionId[]>;
|
|
40
33
|
saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void>;
|
|
41
34
|
loadSummaries(sessionId: SessionId): Promise<Summary[]>;
|
|
42
35
|
healthy(): Promise<boolean>;
|
|
43
36
|
getDataDir(): string;
|
|
44
|
-
getBranchIds(): Promise<string[]>;
|
|
45
37
|
close(): Promise<void>;
|
|
46
38
|
private _read;
|
|
47
39
|
private _mutate;
|
|
48
40
|
private _loadSnapshot;
|
|
49
|
-
private _legacyArtifacts;
|
|
50
41
|
private _measure;
|
|
51
42
|
}
|
|
52
43
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/FilePersistence.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EACX,iBAAiB,EACjB
|
|
1
|
+
{"version":3,"file":"FilePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/FilePersistence.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EACX,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAStD,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,iBAAiB,CAAC;AAYzB,KAAK,sBAAsB,GAAG,WAAW,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,GAAG;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;CACjD,CAAC;AAIF,qBAAa,eAAgB,YAAW,kBAAkB;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;gBAEzB,OAAO,CAAC,EAAE,sBAAsB;WAWxB,MAAM,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,eAAe,CAAC;IAYzE,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;YAM/E,YAAY;IA2Bb,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQnE,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;YAOF,WAAW;IAwCZ,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/E,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC;IAYxB,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAWjE,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIpC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjD,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtE,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAOhD,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjF,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAQvD,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAUjC,UAAU,IAAI,MAAM;IAId,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAIrB,KAAK;YAQL,OAAO;YAaP,aAAa;YAeb,QAAQ;CAUtB"}
|
|
@@ -2,17 +2,12 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { readFile, readdir } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { asSessionId } from "../contracts/ids.js";
|
|
6
|
+
import { PersistenceCompatibilityError } from "../errors.js";
|
|
7
7
|
import { EMPTY_FILE_SNAPSHOT_V2, parseFileSnapshotV2, serializeFileSnapshotV2, sessionsInSnapshot } from "./FileSnapshotV2.js";
|
|
8
|
-
import {
|
|
8
|
+
import { FILE_WRITER_LOCK_NAME, FileWriter } from "./FileWriter.js";
|
|
9
9
|
import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertPersistableThoughts, assertSummaryScopes, assertThoughtScope, compareCodePoint, parsePersistenceBranchId } from "./PersistenceScope.js";
|
|
10
10
|
const SNAPSHOT_NAME = 'snapshot.json';
|
|
11
|
-
const LEGACY_DIRECTORIES = [
|
|
12
|
-
'branches',
|
|
13
|
-
'edges',
|
|
14
|
-
'summaries'
|
|
15
|
-
];
|
|
16
11
|
class FilePersistence {
|
|
17
12
|
_dataDir;
|
|
18
13
|
_maxHistorySize;
|
|
@@ -38,10 +33,6 @@ class FilePersistence {
|
|
|
38
33
|
throw error;
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
|
-
async saveThought(thought) {
|
|
42
|
-
assertThoughtScope('saveThought', GLOBAL_SESSION_ID, thought);
|
|
43
|
-
await this._saveThought(GLOBAL_SESSION_ID, thought);
|
|
44
|
-
}
|
|
45
36
|
async saveThoughtForSession(sessionId, thought) {
|
|
46
37
|
const validatedSessionId = asSessionId(sessionId);
|
|
47
38
|
assertThoughtScope('saveThoughtForSession', validatedSessionId, thought);
|
|
@@ -80,20 +71,12 @@ class FilePersistence {
|
|
|
80
71
|
};
|
|
81
72
|
});
|
|
82
73
|
}
|
|
83
|
-
async loadHistory() {
|
|
84
|
-
return await this.loadHistoryForSession(GLOBAL_SESSION_ID);
|
|
85
|
-
}
|
|
86
74
|
async loadHistoryForSession(sessionId) {
|
|
87
75
|
const validatedSessionId = asSessionId(sessionId);
|
|
88
76
|
return await this._read('load_history', (snapshot)=>[
|
|
89
77
|
...snapshot.thoughts.find((record)=>record.sessionId === validatedSessionId)?.thoughts ?? []
|
|
90
78
|
]);
|
|
91
79
|
}
|
|
92
|
-
async saveBranch(branchId, thoughts) {
|
|
93
|
-
const validatedBranchId = parsePersistenceBranchId(branchId, 'global/branches');
|
|
94
|
-
assertBranchScope('saveBranch', GLOBAL_SESSION_ID, validatedBranchId, thoughts);
|
|
95
|
-
await this._saveBranch(GLOBAL_SESSION_ID, validatedBranchId, thoughts);
|
|
96
|
-
}
|
|
97
80
|
async saveBranchForSession(sessionId, branchId, thoughts) {
|
|
98
81
|
const validatedSessionId = asSessionId(sessionId);
|
|
99
82
|
const validatedBranchId = parsePersistenceBranchId(branchId, `${validatedSessionId}/branches`);
|
|
@@ -138,9 +121,6 @@ class FilePersistence {
|
|
|
138
121
|
]
|
|
139
122
|
}));
|
|
140
123
|
}
|
|
141
|
-
async deleteBranch(branchId) {
|
|
142
|
-
await this.deleteBranchForSession(GLOBAL_SESSION_ID, branchId);
|
|
143
|
-
}
|
|
144
124
|
async deleteBranchForSession(sessionId, branchId) {
|
|
145
125
|
if (!this._persistBranches) return;
|
|
146
126
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -150,9 +130,6 @@ class FilePersistence {
|
|
|
150
130
|
branches: snapshot.branches.filter((record)=>record.sessionId !== validatedSessionId || record.branchId !== validatedBranchId)
|
|
151
131
|
}));
|
|
152
132
|
}
|
|
153
|
-
async loadBranch(branchId) {
|
|
154
|
-
return await this.loadBranchForSession(GLOBAL_SESSION_ID, branchId);
|
|
155
|
-
}
|
|
156
133
|
async loadBranchForSession(sessionId, branchId) {
|
|
157
134
|
if (!this._persistBranches) return;
|
|
158
135
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -164,9 +141,6 @@ class FilePersistence {
|
|
|
164
141
|
];
|
|
165
142
|
});
|
|
166
143
|
}
|
|
167
|
-
async listBranches() {
|
|
168
|
-
return await this.listBranchesForSession(GLOBAL_SESSION_ID);
|
|
169
|
-
}
|
|
170
144
|
async listBranchesForSession(sessionId) {
|
|
171
145
|
if (!this._persistBranches) return [];
|
|
172
146
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -175,8 +149,8 @@ class FilePersistence {
|
|
|
175
149
|
async listSessions() {
|
|
176
150
|
return await this._read('list_sessions', sessionsInSnapshot);
|
|
177
151
|
}
|
|
178
|
-
async
|
|
179
|
-
await this._mutate('
|
|
152
|
+
async clearAll() {
|
|
153
|
+
await this._mutate('clear_all', ()=>EMPTY_FILE_SNAPSHOT_V2);
|
|
180
154
|
}
|
|
181
155
|
async clearSession(sessionId) {
|
|
182
156
|
const validatedSessionId = asSessionId(sessionId);
|
|
@@ -212,9 +186,6 @@ class FilePersistence {
|
|
|
212
186
|
...snapshot.edges.find((record)=>record.sessionId === validatedSessionId)?.edges ?? []
|
|
213
187
|
]);
|
|
214
188
|
}
|
|
215
|
-
async listEdgeSessions() {
|
|
216
|
-
return await this._read('list_edge_sessions', (snapshot)=>snapshot.edges.map((record)=>record.sessionId).sort(compareCodePoint));
|
|
217
|
-
}
|
|
218
189
|
async saveSummaries(sessionId, summaries) {
|
|
219
190
|
const validatedSessionId = asSessionId(sessionId);
|
|
220
191
|
assertSummaryScopes(validatedSessionId, summaries);
|
|
@@ -251,9 +222,6 @@ class FilePersistence {
|
|
|
251
222
|
getDataDir() {
|
|
252
223
|
return this._dataDir;
|
|
253
224
|
}
|
|
254
|
-
async getBranchIds() {
|
|
255
|
-
return await this.listBranches();
|
|
256
|
-
}
|
|
257
225
|
async close() {
|
|
258
226
|
await this._writer.close();
|
|
259
227
|
}
|
|
@@ -271,30 +239,10 @@ class FilePersistence {
|
|
|
271
239
|
}
|
|
272
240
|
async _loadSnapshot(dataDir) {
|
|
273
241
|
const snapshotPath = join(dataDir, SNAPSHOT_NAME);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
const legacyArtifacts = await this._legacyArtifacts(dataDir);
|
|
280
|
-
if (legacyArtifacts.length > 0) throw new PersistenceImportRequiredError(dataDir, legacyArtifacts);
|
|
281
|
-
return EMPTY_FILE_SNAPSHOT_V2;
|
|
282
|
-
}
|
|
283
|
-
async _legacyArtifacts(dataDir) {
|
|
284
|
-
const artifacts = [];
|
|
285
|
-
try {
|
|
286
|
-
await readFile(join(dataDir, 'history.json'), 'utf-8');
|
|
287
|
-
artifacts.push('history.json');
|
|
288
|
-
} catch (error) {
|
|
289
|
-
if (!isFileNotFound(error)) throw error;
|
|
290
|
-
}
|
|
291
|
-
for (const directory of LEGACY_DIRECTORIES)try {
|
|
292
|
-
const files = await readdir(join(dataDir, directory));
|
|
293
|
-
artifacts.push(...files.filter((file)=>file.endsWith('.json')).map((file)=>`${directory}/${file}`));
|
|
294
|
-
} catch (error) {
|
|
295
|
-
if (!isFileNotFound(error)) throw error;
|
|
296
|
-
}
|
|
297
|
-
return artifacts.sort(compareCodePoint);
|
|
242
|
+
const layoutEntries = (await readdir(dataDir)).filter((entry)=>entry !== FILE_WRITER_LOCK_NAME);
|
|
243
|
+
if (0 === layoutEntries.length) return EMPTY_FILE_SNAPSHOT_V2;
|
|
244
|
+
if (1 !== layoutEntries.length || layoutEntries[0] !== SNAPSHOT_NAME) throw new PersistenceCompatibilityError(dataDir, 'directory does not match File v2 layout');
|
|
245
|
+
return parseFileSnapshotV2(await readFile(snapshotPath, 'utf-8'), snapshotPath);
|
|
298
246
|
}
|
|
299
247
|
async _measure(operation, action) {
|
|
300
248
|
const startTime = Date.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/FilePersistence.js","sources":["../../src/persistence/FilePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { IMetrics } from '../contracts/interfaces.js';\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 { PersistenceImportRequiredError } from '../errors.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\tserializeFileSnapshotV2,\n\tsessionsInSnapshot,\n} from './FileSnapshotV2.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport { FileWriter, isFileNotFound, type FileWriterOperations } from './FileWriter.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\n\ntype FilePersistenceOptions = NonNullable<PersistenceConfig['options']> & {\n\treadonly metrics?: IMetrics;\n\treadonly writerOperations?: FileWriterOperations;\n};\n\nconst SNAPSHOT_NAME = 'snapshot.json';\nconst LEGACY_DIRECTORIES = ['branches', 'edges', 'summaries'] as const;\n\nexport class FilePersistence implements SessionScopedPersistenceBackend {\n\tprivate readonly _dataDir: string;\n\tprivate readonly _maxHistorySize: number;\n\tprivate readonly _persistBranches: boolean;\n\tprivate readonly _metrics: IMetrics | undefined;\n\tprivate readonly _writer: FileWriter;\n\n\tconstructor(options?: FilePersistenceOptions) {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tthis._dataDir = options?.dataDir ?? defaultDataDir;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._metrics = options?.metrics;\n\t\tthis._writer = new FileWriter(this._dataDir, options?.writerOperations);\n\t}\n\n\tpublic static async create(options?: FilePersistenceOptions): Promise<FilePersistence> {\n\t\tconst persistence = new FilePersistence(options);\n\t\ttry {\n\t\t\tawait persistence._writer.ready();\n\t\t\tawait persistence._writer.run(async (dataDir) => await persistence._loadSnapshot(dataDir));\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tawait persistence.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\tawait this._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\tawait this._saveThought(validatedSessionId, thought);\n\t}\n\n\tprivate async _saveThought(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tassertPersistableThoughts([thought], `${sessionId}/thoughts`);\n\t\tawait this._mutate('save_thought', (snapshot) => {\n\t\t\tconst current =\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [];\n\t\t\tconst prospective = [...current, thought];\n\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t[\n\t\t\t\t\t{ sessionId, thoughts: prospective },\n\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t],\n\t\t\t\t`${sessionId}/thoughts`\n\t\t\t);\n\t\t\tconst retained =\n\t\t\t\tthis._maxHistorySize > 0 ? prospective.slice(-this._maxHistorySize) : prospective;\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== sessionId),\n\t\t\t\t\t{ sessionId, thoughts: retained },\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 await this._read('load_history', (snapshot) => [\n\t\t\t...(snapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async saveBranch(branchId: BranchId, thoughts: ThoughtData[]): Promise<void> {\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, 'global/branches');\n\t\tassertBranchScope('saveBranch', GLOBAL_SESSION_ID, validatedBranchId, thoughts);\n\t\tawait this._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, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tawait this._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate async _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tassertPersistableThoughtCollections(\n\t\t\t[{ sessionId, thoughts }],\n\t\t\t`${sessionId}/branches/${branchId}`\n\t\t);\n\t\tif (!this._persistBranches) {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshot = await this._loadSnapshot(dataDir);\n\t\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tthoughts:\n\t\t\t\t\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t\t\t{ sessionId, thoughts },\n\t\t\t\t\t],\n\t\t\t\t\t`${sessionId}/branches/${branchId}`\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tawait this._mutate('save_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: [\n\t\t\t\t...snapshot.branches.filter(\n\t\t\t\t\t(record) => record.sessionId !== sessionId || record.branchId !== branchId\n\t\t\t\t),\n\t\t\t\t{ sessionId, branchId, thoughts: [...thoughts] },\n\t\t\t],\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, `${validatedSessionId}/branches`);\n\t\tawait this._mutate('delete_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: snapshot.branches.filter(\n\t\t\t\t(record) => record.sessionId !== validatedSessionId || record.branchId !== validatedBranchId\n\t\t\t),\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, `${validatedSessionId}/branches`);\n\t\treturn await this._read('load_branch', (snapshot) => {\n\t\t\tconst thoughts = snapshot.branches.find(\n\t\t\t\t(record) => record.sessionId === validatedSessionId && record.branchId === validatedBranchId\n\t\t\t)?.thoughts;\n\t\t\treturn thoughts === undefined ? undefined : [...thoughts];\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\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('list_branches', (snapshot) =>\n\t\t\tsnapshot.branches\n\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t.map((record) => record.branchId)\n\t\t\t\t.sort(compareCodePoint)\n\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn await this._read('list_sessions', sessionsInSnapshot);\n\t}\n\n\tpublic async clear(): Promise<void> {\n\t\tawait this._mutate('clear', () => EMPTY_FILE_SNAPSHOT_V2);\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('clear_session', (snapshot) => ({\n\t\t\tversion: 2,\n\t\t\tthoughts: snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tbranches: snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tedges: snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tsummaries: snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\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\tawait this._mutate('save_edges', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tedges: [\n\t\t\t\t...snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(edges.length === 0 ? [] : [{ sessionId: validatedSessionId, edges: [...edges] }]),\n\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 await this._read('load_edges', (snapshot) => [\n\t\t\t...(snapshot.edges.find((record) => record.sessionId === validatedSessionId)?.edges ?? []),\n\t\t]);\n\t}\n\n\tpublic async listEdgeSessions(): Promise<SessionId[]> {\n\t\treturn await this._read('list_edge_sessions', (snapshot) =>\n\t\t\tsnapshot.edges.map((record) => record.sessionId).sort(compareCodePoint)\n\t\t);\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\tawait this._mutate('save_summaries', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tsummaries: [\n\t\t\t\t...snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(summaries.length === 0\n\t\t\t\t\t? []\n\t\t\t\t\t: [{ sessionId: validatedSessionId, summaries: [...summaries] }]),\n\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 await this._read('load_summaries', (snapshot) => [\n\t\t\t...(snapshot.summaries.find((record) => record.sessionId === validatedSessionId)?.summaries ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tawait this._writer.run(async (dataDir) => await this._loadSnapshot(dataDir));\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 getDataDir(): string {\n\t\treturn this._dataDir;\n\t}\n\n\tpublic async getBranchIds(): Promise<string[]> {\n\t\treturn await this.listBranches();\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tawait this._writer.close();\n\t}\n\n\tprivate async _read<T>(operation: string, select: (snapshot: FileSnapshotV2) => T): Promise<T> {\n\t\treturn await this._measure(\n\t\t\toperation,\n\t\t\tasync () =>\n\t\t\t\tawait this._writer.run(async (dataDir) => select(await this._loadSnapshot(dataDir)))\n\t\t);\n\t}\n\n\tprivate async _mutate(\n\t\toperation: string,\n\t\tmutate: (snapshot: FileSnapshotV2) => FileSnapshotV2\n\t): Promise<void> {\n\t\tawait this._measure(operation, async () => {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\t\t\tconst updated = mutate(await this._loadSnapshot(dataDir));\n\t\t\t\tawait this._writer.publish(snapshotPath, serializeFileSnapshotV2(updated, snapshotPath));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async _loadSnapshot(dataDir: string): Promise<FileSnapshotV2> {\n\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\ttry {\n\t\t\treturn parseFileSnapshotV2(await readFile(snapshotPath, 'utf-8'), snapshotPath);\n\t\t} catch (error) {\n\t\t\tif (!isFileNotFound(error)) throw error;\n\t\t}\n\t\tconst legacyArtifacts = await this._legacyArtifacts(dataDir);\n\t\tif (legacyArtifacts.length > 0) {\n\t\t\tthrow new PersistenceImportRequiredError(dataDir, legacyArtifacts);\n\t\t}\n\t\treturn EMPTY_FILE_SNAPSHOT_V2;\n\t}\n\n\tprivate async _legacyArtifacts(dataDir: string): Promise<string[]> {\n\t\tconst artifacts: string[] = [];\n\t\ttry {\n\t\t\tawait readFile(join(dataDir, 'history.json'), 'utf-8');\n\t\t\tartifacts.push('history.json');\n\t\t} catch (error) {\n\t\t\tif (!isFileNotFound(error)) throw error;\n\t\t}\n\t\tfor (const directory of LEGACY_DIRECTORIES) {\n\t\t\ttry {\n\t\t\t\tconst files = await readdir(join(dataDir, directory));\n\t\t\t\tartifacts.push(\n\t\t\t\t\t...files.filter((file) => file.endsWith('.json')).map((file) => `${directory}/${file}`)\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tif (!isFileNotFound(error)) throw error;\n\t\t\t}\n\t\t}\n\t\treturn artifacts.sort(compareCodePoint);\n\t}\n\n\tprivate async _measure<T>(operation: string, action: () => Promise<T>): Promise<T> {\n\t\tconst startTime = Date.now();\n\t\ttry {\n\t\t\treturn await action();\n\t\t} finally {\n\t\t\tthis._metrics?.histogram('persistence_op_duration_seconds', (Date.now() - startTime) / 1000, {\n\t\t\t\toperation,\n\t\t\t});\n\t\t}\n\t}\n}\n"],"names":["SNAPSHOT_NAME","LEGACY_DIRECTORIES","FilePersistence","options","defaultDataDir","existsSync","join","homedir","FileWriter","persistence","dataDir","error","thought","assertThoughtScope","GLOBAL_SESSION_ID","sessionId","validatedSessionId","asSessionId","assertPersistableThoughts","snapshot","current","record","prospective","assertPersistableThoughtCollections","retained","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","undefined","compareCodePoint","sessionsInSnapshot","EMPTY_FILE_SNAPSHOT_V2","edges","assertEdgeScopes","summaries","assertSummaryScopes","Error","operation","select","mutate","snapshotPath","updated","serializeFileSnapshotV2","parseFileSnapshotV2","readFile","isFileNotFound","legacyArtifacts","PersistenceImportRequiredError","artifacts","directory","files","readdir","file","action","startTime","Date"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistence/FilePersistence.js","sources":["../../src/persistence/FilePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { IMetrics } from '../contracts/interfaces.js';\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 } from '../errors.js';\nimport {\n\tEMPTY_FILE_SNAPSHOT_V2,\n\tparseFileSnapshotV2,\n\tserializeFileSnapshotV2,\n\tsessionsInSnapshot,\n} from './FileSnapshotV2.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport {\n\tFILE_WRITER_LOCK_NAME,\n\tFileWriter,\n\ttype FileWriterOperations,\n} from './FileWriter.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\n\ntype FilePersistenceOptions = NonNullable<PersistenceConfig['options']> & {\n\treadonly metrics?: IMetrics;\n\treadonly writerOperations?: FileWriterOperations;\n};\n\nconst SNAPSHOT_NAME = 'snapshot.json';\n\nexport class FilePersistence implements PersistenceBackend {\n\tprivate readonly _dataDir: string;\n\tprivate readonly _maxHistorySize: number;\n\tprivate readonly _persistBranches: boolean;\n\tprivate readonly _metrics: IMetrics | undefined;\n\tprivate readonly _writer: FileWriter;\n\n\tconstructor(options?: FilePersistenceOptions) {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tthis._dataDir = options?.dataDir ?? defaultDataDir;\n\t\tthis._maxHistorySize = options?.maxHistorySize ?? 10000;\n\t\tthis._persistBranches = options?.persistBranches ?? true;\n\t\tthis._metrics = options?.metrics;\n\t\tthis._writer = new FileWriter(this._dataDir, options?.writerOperations);\n\t}\n\n\tpublic static async create(options?: FilePersistenceOptions): Promise<FilePersistence> {\n\t\tconst persistence = new FilePersistence(options);\n\t\ttry {\n\t\t\tawait persistence._writer.ready();\n\t\t\tawait persistence._writer.run(async (dataDir) => await persistence._loadSnapshot(dataDir));\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tawait persistence.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\tawait this._saveThought(validatedSessionId, thought);\n\t}\n\n\tprivate async _saveThought(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tassertPersistableThoughts([thought], `${sessionId}/thoughts`);\n\t\tawait this._mutate('save_thought', (snapshot) => {\n\t\t\tconst current =\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [];\n\t\t\tconst prospective = [...current, thought];\n\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t[\n\t\t\t\t\t{ sessionId, thoughts: prospective },\n\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t],\n\t\t\t\t`${sessionId}/thoughts`\n\t\t\t);\n\t\t\tconst retained =\n\t\t\t\tthis._maxHistorySize > 0 ? prospective.slice(-this._maxHistorySize) : prospective;\n\t\t\treturn {\n\t\t\t\t...snapshot,\n\t\t\t\tthoughts: [\n\t\t\t\t\t...snapshot.thoughts.filter((record) => record.sessionId !== sessionId),\n\t\t\t\t\t{ sessionId, thoughts: retained },\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 await this._read('load_history', (snapshot) => [\n\t\t\t...(snapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ??\n\t\t\t\t[]),\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, `${validatedSessionId}/branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tawait this._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate async _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tassertPersistableThoughtCollections(\n\t\t\t[{ sessionId, thoughts }],\n\t\t\t`${sessionId}/branches/${branchId}`\n\t\t);\n\t\tif (!this._persistBranches) {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshot = await this._loadSnapshot(dataDir);\n\t\t\t\tassertPersistableThoughtCollections(\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsessionId,\n\t\t\t\t\t\t\tthoughts:\n\t\t\t\t\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === sessionId)?.thoughts ?? [],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...snapshot.branches\n\t\t\t\t\t\t\t.filter((record) => record.sessionId === sessionId)\n\t\t\t\t\t\t\t.map((record) => ({ sessionId, thoughts: record.thoughts })),\n\t\t\t\t\t\t{ sessionId, thoughts },\n\t\t\t\t\t],\n\t\t\t\t\t`${sessionId}/branches/${branchId}`\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tawait this._mutate('save_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: [\n\t\t\t\t...snapshot.branches.filter(\n\t\t\t\t\t(record) => record.sessionId !== sessionId || record.branchId !== branchId\n\t\t\t\t),\n\t\t\t\t{ sessionId, branchId, thoughts: [...thoughts] },\n\t\t\t],\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, `${validatedSessionId}/branches`);\n\t\tawait this._mutate('delete_branch', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tbranches: snapshot.branches.filter(\n\t\t\t\t(record) => record.sessionId !== validatedSessionId || record.branchId !== validatedBranchId\n\t\t\t),\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, `${validatedSessionId}/branches`);\n\t\treturn await this._read('load_branch', (snapshot) => {\n\t\t\tconst thoughts = snapshot.branches.find(\n\t\t\t\t(record) => record.sessionId === validatedSessionId && record.branchId === validatedBranchId\n\t\t\t)?.thoughts;\n\t\t\treturn thoughts === undefined ? undefined : [...thoughts];\n\t\t});\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn await this._read('list_branches', (snapshot) =>\n\t\t\tsnapshot.branches\n\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t.map((record) => record.branchId)\n\t\t\t\t.sort(compareCodePoint)\n\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn await this._read('list_sessions', sessionsInSnapshot);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\tawait this._mutate('clear_all', () => EMPTY_FILE_SNAPSHOT_V2);\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('clear_session', (snapshot) => ({\n\t\t\tversion: 2,\n\t\t\tthoughts: snapshot.thoughts.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tbranches: snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tedges: snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\tsummaries: snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\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\tawait this._mutate('save_edges', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tedges: [\n\t\t\t\t...snapshot.edges.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(edges.length === 0 ? [] : [{ sessionId: validatedSessionId, edges: [...edges] }]),\n\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 await this._read('load_edges', (snapshot) => [\n\t\t\t...(snapshot.edges.find((record) => record.sessionId === validatedSessionId)?.edges ?? []),\n\t\t]);\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\tawait this._mutate('save_summaries', (snapshot) => ({\n\t\t\t...snapshot,\n\t\t\tsummaries: [\n\t\t\t\t...snapshot.summaries.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t...(summaries.length === 0\n\t\t\t\t\t? []\n\t\t\t\t\t: [{ sessionId: validatedSessionId, summaries: [...summaries] }]),\n\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 await this._read('load_summaries', (snapshot) => [\n\t\t\t...(snapshot.summaries.find((record) => record.sessionId === validatedSessionId)?.summaries ??\n\t\t\t\t[]),\n\t\t]);\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tawait this._writer.run(async (dataDir) => await this._loadSnapshot(dataDir));\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 getDataDir(): string {\n\t\treturn this._dataDir;\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tawait this._writer.close();\n\t}\n\n\tprivate async _read<T>(operation: string, select: (snapshot: FileSnapshotV2) => T): Promise<T> {\n\t\treturn await this._measure(\n\t\t\toperation,\n\t\t\tasync () =>\n\t\t\t\tawait this._writer.run(async (dataDir) => select(await this._loadSnapshot(dataDir)))\n\t\t);\n\t}\n\n\tprivate async _mutate(\n\t\toperation: string,\n\t\tmutate: (snapshot: FileSnapshotV2) => FileSnapshotV2\n\t): Promise<void> {\n\t\tawait this._measure(operation, async () => {\n\t\t\tawait this._writer.run(async (dataDir) => {\n\t\t\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\t\t\tconst updated = mutate(await this._loadSnapshot(dataDir));\n\t\t\t\tawait this._writer.publish(snapshotPath, serializeFileSnapshotV2(updated, snapshotPath));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate async _loadSnapshot(dataDir: string): Promise<FileSnapshotV2> {\n\t\tconst snapshotPath = join(dataDir, SNAPSHOT_NAME);\n\t\tconst layoutEntries = (await readdir(dataDir)).filter(\n\t\t\t(entry) => entry !== FILE_WRITER_LOCK_NAME\n\t\t);\n\t\tif (layoutEntries.length === 0) return EMPTY_FILE_SNAPSHOT_V2;\n\t\tif (layoutEntries.length !== 1 || layoutEntries[0] !== SNAPSHOT_NAME) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tdataDir,\n\t\t\t\t'directory does not match File v2 layout'\n\t\t\t);\n\t\t}\n\t\treturn parseFileSnapshotV2(await readFile(snapshotPath, 'utf-8'), snapshotPath);\n\t}\n\n\tprivate async _measure<T>(operation: string, action: () => Promise<T>): Promise<T> {\n\t\tconst startTime = Date.now();\n\t\ttry {\n\t\t\treturn await action();\n\t\t} finally {\n\t\t\tthis._metrics?.histogram('persistence_op_duration_seconds', (Date.now() - startTime) / 1000, {\n\t\t\t\toperation,\n\t\t\t});\n\t\t}\n\t}\n}\n"],"names":["SNAPSHOT_NAME","FilePersistence","options","defaultDataDir","existsSync","join","homedir","FileWriter","persistence","dataDir","error","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","assertPersistableThoughts","snapshot","current","record","prospective","assertPersistableThoughtCollections","retained","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","undefined","compareCodePoint","sessionsInSnapshot","EMPTY_FILE_SNAPSHOT_V2","edges","assertEdgeScopes","summaries","assertSummaryScopes","Error","operation","select","mutate","snapshotPath","updated","serializeFileSnapshotV2","layoutEntries","readdir","entry","FILE_WRITER_LOCK_NAME","PersistenceCompatibilityError","parseFileSnapshotV2","readFile","action","startTime","Date"],"mappings":"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"}
|
|
@@ -159,7 +159,7 @@ export declare const FileSnapshotV2Schema: v.StrictObjectSchema<{
|
|
|
159
159
|
readonly merge_branch_ids: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>, v.MaxLengthAction<string, 50, undefined>]>, undefined>, v.DescriptionAction<string[], "Branch IDs being merged into current context">]>, undefined>;
|
|
160
160
|
readonly meta_observation: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.DescriptionAction<string, "Metacognitive observation about reasoning process">]>, undefined>;
|
|
161
161
|
readonly reasoning_depth: v.OptionalSchema<v.SchemaWithPipe<readonly [v.PicklistSchema<["shallow", "moderate", "deep"], undefined>, v.DescriptionAction<"shallow" | "moderate" | "deep", "Effort signal: how deep reasoning should go">]>, undefined>;
|
|
162
|
-
readonly session_id: v.
|
|
162
|
+
readonly session_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "Session ID must contain only letters, numbers, hyphens, and underscores">, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.NotValueAction<string, "__global__", "Session ID '__global__' is retired; use an explicit named session">, v.DescriptionAction<string, "Required session identifier for state isolation. Thought history, branches, and statistics are scoped to this explicit named session.">]>;
|
|
163
163
|
readonly reset_state: v.OptionalSchema<v.SchemaWithPipe<readonly [v.BooleanSchema<undefined>, v.DescriptionAction<boolean, "When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.">]>, undefined>;
|
|
164
164
|
readonly tool_name: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.DescriptionAction<string, "Name of the tool being invoked (for tool_call thoughts)">]>, undefined>;
|
|
165
165
|
readonly tool_arguments: v.OptionalSchema<v.SchemaWithPipe<readonly [v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, v.DescriptionAction<{
|
|
@@ -328,7 +328,7 @@ export declare const FileSnapshotV2Schema: v.StrictObjectSchema<{
|
|
|
328
328
|
readonly merge_branch_ids: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>, v.MaxLengthAction<string, 50, undefined>]>, undefined>, v.DescriptionAction<string[], "Branch IDs being merged into current context">]>, undefined>;
|
|
329
329
|
readonly meta_observation: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.DescriptionAction<string, "Metacognitive observation about reasoning process">]>, undefined>;
|
|
330
330
|
readonly reasoning_depth: v.OptionalSchema<v.SchemaWithPipe<readonly [v.PicklistSchema<["shallow", "moderate", "deep"], undefined>, v.DescriptionAction<"shallow" | "moderate" | "deep", "Effort signal: how deep reasoning should go">]>, undefined>;
|
|
331
|
-
readonly session_id: v.
|
|
331
|
+
readonly session_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "Session ID must contain only letters, numbers, hyphens, and underscores">, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.NotValueAction<string, "__global__", "Session ID '__global__' is retired; use an explicit named session">, v.DescriptionAction<string, "Required session identifier for state isolation. Thought history, branches, and statistics are scoped to this explicit named session.">]>;
|
|
332
332
|
readonly reset_state: v.OptionalSchema<v.SchemaWithPipe<readonly [v.BooleanSchema<undefined>, v.DescriptionAction<boolean, "When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.">]>, undefined>;
|
|
333
333
|
readonly tool_name: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.DescriptionAction<string, "Name of the tool being invoked (for tool_call thoughts)">]>, undefined>;
|
|
334
334
|
readonly tool_arguments: v.OptionalSchema<v.SchemaWithPipe<readonly [v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, v.DescriptionAction<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { asSessionId } from "../contracts/ids.js";
|
|
2
2
|
import { SummarySchema } from "../core/compression/Summary.js";
|
|
3
3
|
import { PersistenceCompatibilityError, PersistenceCorruptionError } from "../errors.js";
|
|
4
4
|
import { EdgeSchema, SequentialThinkingSchema } from "../schema.js";
|
|
@@ -117,7 +117,7 @@ function sessionsInSnapshot(snapshot) {
|
|
|
117
117
|
].sort(compareCodePoint);
|
|
118
118
|
}
|
|
119
119
|
function sessionForThought(thought) {
|
|
120
|
-
return thought.session_id
|
|
120
|
+
return asSessionId(thought.session_id);
|
|
121
121
|
}
|
|
122
122
|
export { EMPTY_FILE_SNAPSHOT_V2, FileSnapshotV2Schema, parseFileSnapshotV2, serializeFileSnapshotV2, sessionForThought, sessionsInSnapshot };
|
|
123
123
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence/FileSnapshotV2.js","sources":["../../src/persistence/FileSnapshotV2.ts"],"sourcesContent":["import * as v from 'valibot';\nimport type { SessionId } from '../contracts/ids.js';\nimport { asSessionId
|
|
1
|
+
{"version":3,"file":"persistence/FileSnapshotV2.js","sources":["../../src/persistence/FileSnapshotV2.ts"],"sourcesContent":["import * as v from 'valibot';\nimport type { SessionId } from '../contracts/ids.js';\nimport { asSessionId } from '../contracts/ids.js';\nimport { SummarySchema } from '../core/compression/Summary.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport { EdgeSchema, SequentialThinkingSchema } from '../schema.js';\nimport { parseEdge, parseSummary, parseThoughtData } from './PersistenceCodec.js';\nimport type { FileSnapshotV2 } from './FileSnapshotTypes.js';\nimport {\n\tcompareCodePoint,\n\tcompareCreatedThenId,\n\tparsePersistenceBranchId,\n} from './PersistenceScope.js';\nimport { validateFileSnapshotV2 } from './FileSnapshotValidation.js';\n\nconst SessionIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,100}$/));\nconst BranchIdStringSchema = v.pipe(v.string(), v.regex(/^[A-Za-z0-9_-]{1,50}$/));\nconst ThoughtSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tthoughts: v.array(SequentialThinkingSchema),\n});\nconst BranchRecordV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tbranchId: BranchIdStringSchema,\n\tthoughts: v.array(SequentialThinkingSchema),\n});\nconst EdgeSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tedges: v.array(EdgeSchema),\n});\nconst SummarySessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tsummaries: v.array(SummarySchema),\n});\n\nexport const FileSnapshotV2Schema = v.strictObject({\n\tversion: v.literal(2),\n\tthoughts: v.array(ThoughtSessionV2Schema),\n\tbranches: v.array(BranchRecordV2Schema),\n\tedges: v.array(EdgeSessionV2Schema),\n\tsummaries: v.array(SummarySessionV2Schema),\n});\n\nexport const EMPTY_FILE_SNAPSHOT_V2: FileSnapshotV2 = {\n\tversion: 2,\n\tthoughts: [],\n\tbranches: [],\n\tedges: [],\n\tsummaries: [],\n};\n\nexport function parseFileSnapshotV2(content: string, sourcePath: string): FileSnapshotV2 {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new PersistenceCorruptionError(sourcePath, error);\n\t}\n\ttry {\n\t\tconst parsed = v.parse(FileSnapshotV2Schema, raw);\n\t\tconst snapshot: FileSnapshotV2 = {\n\t\t\tversion: 2,\n\t\t\tthoughts: parsed.thoughts.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tbranches: parsed.branches.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tbranchId: parsePersistenceBranchId(record.branchId, sourcePath),\n\t\t\t\tthoughts: record.thoughts.map((thought) => parseThoughtData(thought, sourcePath)),\n\t\t\t})),\n\t\t\tedges: parsed.edges.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tedges: record.edges.map(parseEdge),\n\t\t\t})),\n\t\t\tsummaries: parsed.summaries.map((record) => ({\n\t\t\t\tsessionId: asSessionId(record.sessionId),\n\t\t\t\tsummaries: record.summaries.map((summary) => parseSummary(summary, sourcePath)),\n\t\t\t})),\n\t\t};\n\t\tvalidateFileSnapshotV2(snapshot, sourcePath);\n\t\treturn snapshot;\n\t} catch (error) {\n\t\tif (error instanceof PersistenceCompatibilityError) throw error;\n\t\tthrow new PersistenceCompatibilityError(sourcePath, 'document does not match File v2', error);\n\t}\n}\n\nexport function serializeFileSnapshotV2(snapshot: FileSnapshotV2, sourcePath: string): string {\n\tconst canonical: FileSnapshotV2 = {\n\t\tversion: 2,\n\t\tthoughts: [...snapshot.thoughts].sort((left, right) =>\n\t\t\tcompareCodePoint(left.sessionId, right.sessionId)\n\t\t),\n\t\tbranches: [...snapshot.branches].sort(\n\t\t\t(left, right) =>\n\t\t\t\tcompareCodePoint(left.sessionId, right.sessionId) ||\n\t\t\t\tcompareCodePoint(left.branchId, right.branchId)\n\t\t),\n\t\tedges: [...snapshot.edges]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({ ...record, edges: [...record.edges].sort(compareCreatedThenId) })),\n\t\tsummaries: [...snapshot.summaries]\n\t\t\t.sort((left, right) => compareCodePoint(left.sessionId, right.sessionId))\n\t\t\t.map((record) => ({\n\t\t\t\t...record,\n\t\t\t\tsummaries: [...record.summaries].sort(compareCreatedThenId),\n\t\t\t})),\n\t};\n\tvalidateFileSnapshotV2(canonical, sourcePath);\n\treturn `${JSON.stringify(canonical, null, 2)}\\n`;\n}\n\nexport function sessionsInSnapshot(snapshot: FileSnapshotV2): SessionId[] {\n\tconst sessions = new Set<SessionId>();\n\tfor (const records of [\n\t\tsnapshot.thoughts,\n\t\tsnapshot.branches,\n\t\tsnapshot.edges,\n\t\tsnapshot.summaries,\n\t]) {\n\t\tfor (const record of records) sessions.add(record.sessionId);\n\t}\n\treturn [...sessions].sort(compareCodePoint);\n}\n\nexport function sessionForThought(thought: ThoughtData): SessionId {\n\treturn asSessionId(thought.session_id);\n}\n"],"names":["SessionIdStringSchema","v","BranchIdStringSchema","ThoughtSessionV2Schema","SequentialThinkingSchema","BranchRecordV2Schema","EdgeSessionV2Schema","EdgeSchema","SummarySessionV2Schema","SummarySchema","FileSnapshotV2Schema","EMPTY_FILE_SNAPSHOT_V2","parseFileSnapshotV2","content","sourcePath","raw","JSON","error","PersistenceCorruptionError","parsed","snapshot","record","asSessionId","thought","parseThoughtData","parsePersistenceBranchId","parseEdge","summary","parseSummary","validateFileSnapshotV2","PersistenceCompatibilityError","serializeFileSnapshotV2","canonical","left","right","compareCodePoint","compareCreatedThenId","sessionsInSnapshot","sessions","Set","records","sessionForThought"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileWriter.d.ts","sourceRoot":"","sources":["../../src/persistence/FileWriter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FileWriter.d.ts","sourceRoot":"","sources":["../../src/persistence/FileWriter.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAEjE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,QAAQ,CAAC,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9E;AAED,eAAO,MAAM,wBAAwB,EAAE,oBAYtC,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAkBD,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAuB;IACnD,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,MAAM,CAAuB;gBAEzB,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,oBAA+C;IAK3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgBjE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BjE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB7B,OAAO,CAAC,aAAa;YAKP,iBAAiB;YA2BjB,yBAAyB;YAuBzB,iBAAiB;CAwB/B"}
|
|
@@ -2,7 +2,7 @@ import { mkdir, realpath, rename, rmdir, unlink, writeFile } from "node:fs/promi
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { basename, dirname, join } from "node:path";
|
|
4
4
|
import { PersistenceClosedError, PersistenceOwnershipError, PersistencePublicationError } from "../errors.js";
|
|
5
|
-
const
|
|
5
|
+
const FILE_WRITER_LOCK_NAME = '.tracelattice-writer.lock';
|
|
6
6
|
const nodeFileWriterOperations = {
|
|
7
7
|
mkdir: async (path)=>{
|
|
8
8
|
await mkdir(path, {
|
|
@@ -95,7 +95,7 @@ class FileWriter {
|
|
|
95
95
|
async _acquireOwnership() {
|
|
96
96
|
await this._operations.mkdir(this._configuredDataDir);
|
|
97
97
|
const canonicalDataDir = await this._operations.realpath(this._configuredDataDir);
|
|
98
|
-
const lockPath = join(canonicalDataDir,
|
|
98
|
+
const lockPath = join(canonicalDataDir, FILE_WRITER_LOCK_NAME);
|
|
99
99
|
const markerName = `${process.pid}-${randomUUID()}.owner`;
|
|
100
100
|
const markerPath = join(lockPath, markerName);
|
|
101
101
|
try {
|
|
@@ -150,6 +150,6 @@ class FileWriter {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
export { FileWriter, isFileNotFound, nodeFileWriterOperations };
|
|
153
|
+
export { FILE_WRITER_LOCK_NAME, FileWriter, isFileNotFound, nodeFileWriterOperations };
|
|
154
154
|
|
|
155
155
|
//# sourceMappingURL=FileWriter.js.map
|