@iworkforces/tracelattice 2.1.2 → 2.2.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 +45 -10
- package/dist/ServerConfig.d.ts +9 -5
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +20 -7
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +10 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/calibrator.d.ts +9 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/interfaces.d.ts +6 -0
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +13 -1
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +14 -9
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/core/DurableThoughtIdentityIndex.d.ts +35 -0
- package/dist/core/DurableThoughtIdentityIndex.d.ts.map +1 -0
- package/dist/core/DurableThoughtIdentityIndex.js +94 -0
- package/dist/core/DurableThoughtIdentityIndex.js.map +1 -0
- package/dist/core/HistoryManager.d.ts +5 -0
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +37 -4
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +2 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +7 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +13 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +11 -3
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWorkQueue.d.ts +13 -1
- package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
- package/dist/core/PersistenceWorkQueue.js +86 -11
- package/dist/core/PersistenceWorkQueue.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -0
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +7 -4
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +15 -7
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +19 -7
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/ThoughtReferenceIndex.d.ts +4 -0
- package/dist/core/ThoughtReferenceIndex.d.ts.map +1 -1
- package/dist/core/ThoughtReferenceIndex.js +28 -1
- package/dist/core/ThoughtReferenceIndex.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts +8 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/VerificationTargetRestore.d.ts +5 -0
- package/dist/core/VerificationTargetRestore.d.ts.map +1 -0
- package/dist/core/VerificationTargetRestore.js +61 -0
- package/dist/core/VerificationTargetRestore.js.map +1 -0
- package/dist/core/evaluator/Aggregator.d.ts +2 -1
- package/dist/core/evaluator/Aggregator.d.ts.map +1 -1
- package/dist/core/evaluator/Aggregator.js +4 -12
- package/dist/core/evaluator/Aggregator.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +13 -9
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +25 -11
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/PatternDetector.d.ts +2 -1
- package/dist/core/evaluator/PatternDetector.d.ts.map +1 -1
- package/dist/core/evaluator/PatternDetector.js +13 -12
- package/dist/core/evaluator/PatternDetector.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +3 -2
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js +4 -9
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/VerificationLinks.d.ts +19 -0
- package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -0
- package/dist/core/evaluator/VerificationLinks.js +113 -0
- package/dist/core/evaluator/VerificationLinks.js.map +1 -0
- package/dist/core/evaluator/calibration-math.d.ts +12 -2
- package/dist/core/evaluator/calibration-math.d.ts.map +1 -1
- package/dist/core/evaluator/calibration-math.js +11 -2
- package/dist/core/evaluator/calibration-math.js.map +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -1
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +5 -5
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +11 -11
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts +20 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js +100 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +5 -4
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +24 -14
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -1
- package/dist/lib.js.map +1 -1
- package/dist/metrics/metrics.impl.d.ts.map +1 -1
- package/dist/metrics/metrics.impl.js +19 -7
- package/dist/metrics/metrics.impl.js.map +1 -1
- package/dist/persistence/BacktrackPersistence.d.ts +13 -0
- package/dist/persistence/BacktrackPersistence.d.ts.map +1 -0
- package/dist/persistence/BacktrackPersistence.js +90 -0
- package/dist/persistence/BacktrackPersistence.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +2 -1
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +28 -0
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -0
- package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
- package/dist/persistence/FileSnapshotV2.js +6 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +2 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +21 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.d.ts.map +1 -1
- package/dist/persistence/PersistenceCodec.js +5 -0
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +1 -1
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +2 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +18 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/package.json +12 -11
|
@@ -80,12 +80,16 @@ class Metrics {
|
|
|
80
80
|
};
|
|
81
81
|
const key = this._metricKey(fullName, allLabels);
|
|
82
82
|
const histogram = this._histograms.get(key);
|
|
83
|
+
let previousBoundary = -1 / 0;
|
|
84
|
+
for (const boundary of buckets){
|
|
85
|
+
if (!Number.isFinite(boundary) || boundary <= previousBoundary) throw new RangeError('Histogram boundaries must be finite and strictly increasing');
|
|
86
|
+
previousBoundary = boundary;
|
|
87
|
+
}
|
|
88
|
+
if (histogram && (histogram.boundaries.length !== buckets.length || histogram.boundaries.some((boundary, index)=>boundary !== buckets[index]))) throw new RangeError('Histogram bucket layout differs from the existing series');
|
|
83
89
|
if (histogram) {
|
|
84
90
|
histogram.sum += value;
|
|
85
91
|
histogram.count += 1;
|
|
86
|
-
for (const boundary of
|
|
87
|
-
else histogram.buckets.set(boundary, histogram.buckets.get(boundary) ?? 0);
|
|
88
|
-
histogram.buckets.set(1 / 0, (histogram.buckets.get(1 / 0) ?? 0) + 1);
|
|
92
|
+
for (const boundary of histogram.boundaries)if (value <= boundary) histogram.buckets.set(boundary, (histogram.buckets.get(boundary) ?? 0) + 1);
|
|
89
93
|
} else {
|
|
90
94
|
const histogramData = {
|
|
91
95
|
name: fullName,
|
|
@@ -94,10 +98,12 @@ class Metrics {
|
|
|
94
98
|
},
|
|
95
99
|
sum: value,
|
|
96
100
|
count: 1,
|
|
101
|
+
boundaries: [
|
|
102
|
+
...buckets
|
|
103
|
+
],
|
|
97
104
|
buckets: new Map()
|
|
98
105
|
};
|
|
99
106
|
for (const boundary of buckets)histogramData.buckets.set(boundary, value <= boundary ? 1 : 0);
|
|
100
|
-
histogramData.buckets.set(1 / 0, 1);
|
|
101
107
|
this._histograms.set(key, histogramData);
|
|
102
108
|
}
|
|
103
109
|
this._operationsCounter++;
|
|
@@ -135,7 +141,7 @@ class Metrics {
|
|
|
135
141
|
for (const metric of metrics){
|
|
136
142
|
if (!helpEntries.has(metric.name)) {
|
|
137
143
|
const helpText = metric.help ?? `${metric.name} metric`;
|
|
138
|
-
lines.push(`# HELP ${metric.name} ${helpText}`);
|
|
144
|
+
lines.push(`# HELP ${metric.name} ${helpText.replaceAll('\\', '\\\\').replaceAll('\n', '\\n')}`);
|
|
139
145
|
helpEntries.set(metric.name, helpText);
|
|
140
146
|
}
|
|
141
147
|
if (!typeEntries.has(metric.name)) {
|
|
@@ -159,14 +165,20 @@ class Metrics {
|
|
|
159
165
|
};
|
|
160
166
|
lines.push(formatMetricLine('_sum', histogram.sum));
|
|
161
167
|
lines.push(formatMetricLine('_count', histogram.count));
|
|
162
|
-
for (const
|
|
163
|
-
const
|
|
168
|
+
for (const boundary of histogram.boundaries){
|
|
169
|
+
const count = histogram.buckets.get(boundary);
|
|
170
|
+
const boundaryLabel = String(boundary);
|
|
164
171
|
const boundaryLabelStr = this._formatLabels({
|
|
165
172
|
le: boundaryLabel
|
|
166
173
|
});
|
|
167
174
|
const bucketLabels = 0 === labelStr.length ? boundaryLabelStr : `${labelStr},${boundaryLabelStr}`;
|
|
168
175
|
lines.push(`${fullName}_bucket{${bucketLabels}} ${count}`);
|
|
169
176
|
}
|
|
177
|
+
const infLabelStr = this._formatLabels({
|
|
178
|
+
le: '+Inf'
|
|
179
|
+
});
|
|
180
|
+
const infLabels = 0 === labelStr.length ? infLabelStr : `${labelStr},${infLabelStr}`;
|
|
181
|
+
lines.push(`${fullName}_bucket{${infLabels}} ${histogram.count}`);
|
|
170
182
|
}
|
|
171
183
|
}
|
|
172
184
|
return lines.join('\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics/metrics.impl.js","sources":["../../src/metrics/metrics.impl.ts"],"sourcesContent":["/**\n * Prometheus-compatible metrics collection.\n *\n * This module provides metrics collection and export in Prometheus text format.\n * Supports counters, gauges, and histograms for observability.\n *\n * @module metrics\n */\n\n/**\n * Metric types supported by the metrics collector.\n */\nexport enum MetricType {\n\t/** Counter - a cumulative metric that only increases */\n\tCounter = 'counter',\n\n\t/** Gauge - a metric that can go up and down */\n\tGauge = 'gauge',\n\n\t/** Histogram - a metric for sampling observations */\n\tHistogram = 'histogram',\n}\n\n/**\n * A collected metric with its value and labels.\n */\nexport interface Metric {\n\t/** Name of the metric */\n\tname: string;\n\n\t/** Type of metric (counter, gauge, histogram) */\n\ttype: MetricType;\n\n\t/** Current value */\n\tvalue: number;\n\n\t/** Labels for the metric */\n\tlabels: Record<string, string>;\n\n\t/** Help text describing the metric */\n\thelp?: string;\n\n\t/** Timestamp when metric was recorded (Unix epoch) */\n\ttimestamp?: number;\n}\n\ninterface HistogramMetric {\n\tname: string;\n\tlabels: Record<string, string>;\n\tsum: number;\n\tcount: number;\n\tbuckets: Map<number, number>;\n}\n\n/**\n * Histogram bucket boundaries for latency tracking.\n */\nconst DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];\n\n/**\n * Prometheus-compatible metrics collector.\n *\n * Collects and exports metrics in Prometheus text format for scraping.\n * Thread-safe and supports counters, gauges, and histograms.\n *\n * @remarks\n * **Metric Types:**\n * - **Counter**: Cumulative value that only increases (e.g., request counts)\n * - **Gauge**: Value that can go up or down (e.g., active connections)\n * - **Histogram**: Sampling observations (e.g., request latency)\n *\n * **Labels:**\n * Metrics can have labels for dimensional data:\n * ```typescript\n * counter('http_requests_total', { method: 'GET', status: '200' });\n * ```\n *\n * **Export Format:**\n * Metrics are exported in Prometheus text format:\n * ```\n * # HELP http_requests_total Total HTTP requests\n * # TYPE http_requests_total counter\n * http_requests_total{method=\"GET\",status=\"200\"} 1234\n * ```\n *\n * @example\n * ```typescript\n * const metrics = new Metrics({ prefix: 'mcp_server' });\n *\n * // Count requests\n * metrics.counter('requests_total', { method: 'GET' }).inc();\n *\n * // Track active connections\n * const activeConnections = metrics.gauge('active_connections');\n * activeConnections.set(5);\n * activeConnections.dec();\n *\n * // Record latency\n * metrics.histogram('request_duration_seconds').observe(0.023);\n *\n * // Export for Prometheus\n * const prometheusText = metrics.export();\n * ```\n */\nexport class Metrics {\n\t/** Metrics storage indexed by name and label hash */\n\tprivate _metrics: Map<string, Metric>;\n\n\t/** Histogram samples */\n\tprivate _histograms: Map<string, HistogramMetric>;\n\n\t/** Prefix for all metric names */\n\tprivate _prefix: string;\n\n\t/** Default labels to apply to all metrics */\n\tprivate _defaultLabels: Record<string, string>;\n\n\t/** Counter for metric collection operations */\n\tprivate _operationsCounter: number = 0;\n\n\t/**\n\t * Creates a new Metrics instance.\n\t *\n\t * @param options - Configuration options\n\t *\n\t * @example\n\t * ```typescript\n\t * const metrics = new Metrics({ prefix: 'mcp_server' });\n\t * ```\n\t */\n\tconstructor(options: { prefix?: string; defaultLabels?: Record<string, string> } = {}) {\n\t\tthis._metrics = new Map();\n\t\tthis._histograms = new Map();\n\t\tthis._prefix = options.prefix ?? '';\n\t\tthis._defaultLabels = { ...options.defaultLabels };\n\t}\n\n\t/**\n\t * Creates a counter metric.\n\t *\n\t * @param name - Metric name\n\t * @param value - Increment value (default: 1)\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.counter('requests_total', 1, { method: 'GET' });\n\t * metrics.counter('errors_total', 1, { type: 'timeout' });\n\t * ```\n\t */\n\tcounter(name: string, value = 1, labels: Record<string, string> = {}, help?: string): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst existing = this._metrics.get(key);\n\n\t\tif (existing) {\n\t\t\texisting.value += value;\n\t\t\tif (help && !existing.help) {\n\t\t\t\texisting.help = help;\n\t\t\t}\n\t\t} else {\n\t\t\tthis._metrics.set(key, {\n\t\t\t\tname: fullName,\n\t\t\t\ttype: MetricType.Counter,\n\t\t\t\tvalue,\n\t\t\t\tlabels: { ...allLabels },\n\t\t\t\thelp,\n\t\t\t});\n\t\t}\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Creates a gauge metric.\n\t *\n\t * @param name - Metric name\n\t * @param value - Current value\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t *\n\t * @example\n\t * ```typescript\n\t * const activeConnections = metrics.gauge('active_connections');\n\t * activeConnections.set(5);\n\t * activeConnections.dec();\n\t * ```\n\t */\n\tgauge(name: string, value: number, labels: Record<string, string> = {}, help?: string): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst existing = this._metrics.get(key);\n\t\tthis._metrics.set(key, {\n\t\t\tname: fullName,\n\t\t\ttype: MetricType.Gauge,\n\t\t\tvalue,\n\t\t\tlabels: { ...allLabels },\n\t\t\thelp: help ?? existing?.help,\n\t\t});\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Records a histogram observation.\n\t *\n\t * @param name - Histogram name\n\t * @param value - Observed value\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t * @param buckets - Custom bucket boundaries\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.histogram('request_duration_seconds').observe(0.023);\n\t * metrics.histogram('thought_processing_ms').observe(45);\n\t * ```\n\t */\n\thistogram(\n\t\tname: string,\n\t\tvalue: number,\n\t\tlabels: Record<string, string> = {},\n\t\tbuckets = DEFAULT_BUCKETS\n\t): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst histogram = this._histograms.get(key);\n\n\t\tif (histogram) {\n\t\t\thistogram.sum += value;\n\t\t\thistogram.count += 1;\n\t\t\tfor (const boundary of buckets) {\n\t\t\t\tif (value <= boundary) {\n\t\t\t\t\thistogram.buckets.set(boundary, (histogram.buckets.get(boundary) ?? 0) + 1);\n\t\t\t\t} else {\n\t\t\t\t\thistogram.buckets.set(boundary, histogram.buckets.get(boundary) ?? 0);\n\t\t\t\t}\n\t\t\t}\n\t\t\thistogram.buckets.set(Infinity, (histogram.buckets.get(Infinity) ?? 0) + 1);\n\t\t} else {\n\t\t\tconst histogramData = {\n\t\t\t\tname: fullName,\n\t\t\t\tlabels: { ...allLabels },\n\t\t\t\tsum: value,\n\t\t\t\tcount: 1,\n\t\t\t\tbuckets: new Map<number, number>(),\n\t\t\t};\n\t\t\tfor (const boundary of buckets) {\n\t\t\t\thistogramData.buckets.set(boundary, value <= boundary ? 1 : 0);\n\t\t\t}\n\t\t\thistogramData.buckets.set(Infinity, 1);\n\t\t\tthis._histograms.set(key, histogramData);\n\t\t}\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Gets the current value of a metric.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Labels\n\t * @returns Current value or undefined if not found\n\t *\n\t * @example\n\t * ```typescript\n\t * const count = metrics.get('requests_total', { method: 'GET' });\n\t * ```\n\t */\n\tget(name: string, labels: Record<string, string> = {}): number | undefined {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\treturn this._metrics.get(key)?.value;\n\t}\n\n\t/**\n\t * Increments a counter by 1.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Optional labels\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.inc('requests_total', { method: 'GET' });\n\t * ```\n\t */\n\tinc(name: string, labels?: Record<string, string>): void {\n\t\tthis.counter(name, 1, labels);\n\t}\n\n\t/**\n\t * Decrements a gauge by 1.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Optional labels\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.dec('active_connections');\n\t * ```\n\t */\n\tdec(name: string, labels?: Record<string, string>): void {\n\t\tconst value = this.get(name, labels) ?? 0;\n\t\tthis.gauge(name, value - 1, labels);\n\t}\n\n\t/**\n\t * Resets all metrics to zero.\n\t * Useful for testing or on server restart.\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.reset();\n\t * ```\n\t */\n\treset(): void {\n\t\tthis._metrics.clear();\n\t\tthis._histograms.clear();\n\t\tthis._operationsCounter = 0;\n\t}\n\n\t/**\n\t * Gets the number of metric operations performed.\n\t * Useful for testing.\n\t *\n\t * @returns Operation count\n\t *\n\t * @example\n\t * ```typescript\n\t * const ops = metrics.getOperationCount();\n\t * ```\n\t */\n\tgetOperationCount(): number {\n\t\treturn this._operationsCounter;\n\t}\n\n\t/**\n\t * Exports metrics in Prometheus text format.\n\t *\n\t * @returns Prometheus text format string\n\t *\n\t * @example\n\t * ```typescript\n\t * const prometheusText = metrics.export();\n\t * console.log(prometheusText);\n\t * // Output:\n\t * // # HELP http_requests_total Total HTTP requests\n\t * // # TYPE http_requests_total counter\n\t * // http_requests_total{method=\"GET\",status=\"200\"} 1234\n\t * ```\n\t */\n\texport(): string {\n\t\tconst lines: string[] = [];\n\n\t\tconst metrics = Array.from(this._metrics.values());\n\t\tconst histograms = Array.from(this._histograms.values());\n\n\t\tconst helpEntries = new Map<string, string>();\n\t\tconst typeEntries = new Map<string, MetricType>();\n\n\t\tfor (const metric of metrics) {\n\t\t\tif (!helpEntries.has(metric.name)) {\n\t\t\t\tconst helpText = metric.help ?? `${metric.name} metric`;\n\t\t\t\tlines.push(`# HELP ${metric.name} ${helpText}`);\n\t\t\t\thelpEntries.set(metric.name, helpText);\n\t\t\t}\n\t\t\tif (!typeEntries.has(metric.name)) {\n\t\t\t\tlines.push(`# TYPE ${metric.name} ${metric.type}`);\n\t\t\t\ttypeEntries.set(metric.name, metric.type);\n\t\t\t}\n\n\t\t\tconst labelStr = this._formatLabels(metric.labels);\n\t\t\tlines.push(`${metric.name}{${labelStr}} ${metric.value}`);\n\t\t}\n\n\t\tfor (const histogram of histograms) {\n\t\t\tconst { name: fullName, labels } = histogram;\n\t\t\tif (histogram.count > 0) {\n\t\t\t\tif (!typeEntries.has(fullName)) {\n\t\t\t\t\tlines.push(`# TYPE ${fullName} histogram`);\n\t\t\t\t\ttypeEntries.set(fullName, MetricType.Histogram);\n\t\t\t\t}\n\n\t\t\t\tconst labelStr = this._formatLabels(labels);\n\t\t\t\tconst formatMetricLine = (suffix: string, value: number): string => {\n\t\t\t\t\tif (labelStr.length === 0) {\n\t\t\t\t\t\treturn `${fullName}${suffix} ${value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn `${fullName}${suffix}{${labelStr}} ${value}`;\n\t\t\t\t};\n\n\t\t\t\tlines.push(formatMetricLine('_sum', histogram.sum));\n\t\t\t\tlines.push(formatMetricLine('_count', histogram.count));\n\n\t\t\t\tfor (const [boundary, count] of histogram.buckets.entries()) {\n\t\t\t\t\tconst boundaryLabel =\n\t\t\t\t\t\tboundary === Infinity\n\t\t\t\t\t\t\t? '+Inf'\n\t\t\t\t\t\t\t: Number.isFinite(boundary)\n\t\t\t\t\t\t\t\t? String(boundary)\n\t\t\t\t\t\t\t\t: String(boundary);\n\t\t\t\t\tconst boundaryLabelStr = this._formatLabels({ le: boundaryLabel });\n\t\t\t\t\tconst bucketLabels =\n\t\t\t\t\t\tlabelStr.length === 0 ? boundaryLabelStr : `${labelStr},${boundaryLabelStr}`;\n\t\t\t\t\tlines.push(`${fullName}_bucket{${bucketLabels}} ${count}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines.join('\\n');\n\t}\n\n\t/**\n\t * Gets metric name with prefix.\n\t * @param name - Metric name\n\t * @returns Full metric name\n\t * @private\n\t */\n\tprivate _fullName(name: string): string {\n\t\tif (!this._prefix) {\n\t\t\treturn name;\n\t\t}\n\n\t\tconst prefix = `${this._prefix}_`;\n\t\treturn name.startsWith(prefix) ? name : `${prefix}${name}`;\n\t}\n\n\t/**\n\t * Creates a unique key for a metric with labels.\n\t * @param name - Metric name\n\t * @param labels - Labels\n\t * @returns Unique key\n\t * @private\n\t */\n\tprivate _metricKey(name: string, labels: Record<string, string>): string {\n\t\tconst sortedLabels = Object.entries(labels).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n\t\treturn JSON.stringify([name, sortedLabels]);\n\t}\n\n\tprivate _formatLabels(labels: Record<string, string>): string {\n\t\treturn Object.entries(labels)\n\t\t\t.map(([key, value]) => `${key}=\"${this._escapeLabelValue(value)}\"`)\n\t\t\t.join(',');\n\t}\n\n\tprivate _escapeLabelValue(value: string): string {\n\t\treturn value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"').replaceAll('\\n', '\\\\n');\n\t}\n}\n"],"names":["MetricType","DEFAULT_BUCKETS","Metrics","options","Map","name","value","labels","help","fullName","allLabels","key","existing","buckets","histogram","boundary","Infinity","histogramData","lines","metrics","Array","histograms","helpEntries","typeEntries","metric","helpText","labelStr","formatMetricLine","suffix","count","boundaryLabel","Number","String","boundaryLabelStr","bucketLabels","prefix","sortedLabels","Object","a","b","JSON"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metrics/metrics.impl.js","sources":["../../src/metrics/metrics.impl.ts"],"sourcesContent":["/**\n * Prometheus-compatible metrics collection.\n *\n * This module provides metrics collection and export in Prometheus text format.\n * Supports counters, gauges, and histograms for observability.\n *\n * @module metrics\n */\n\n/**\n * Metric types supported by the metrics collector.\n */\nexport enum MetricType {\n\t/** Counter - a cumulative metric that only increases */\n\tCounter = 'counter',\n\n\t/** Gauge - a metric that can go up and down */\n\tGauge = 'gauge',\n\n\t/** Histogram - a metric for sampling observations */\n\tHistogram = 'histogram',\n}\n\n/**\n * A collected metric with its value and labels.\n */\nexport interface Metric {\n\t/** Name of the metric */\n\tname: string;\n\n\t/** Type of metric (counter, gauge, histogram) */\n\ttype: MetricType;\n\n\t/** Current value */\n\tvalue: number;\n\n\t/** Labels for the metric */\n\tlabels: Record<string, string>;\n\n\t/** Help text describing the metric */\n\thelp?: string;\n\n\t/** Timestamp when metric was recorded (Unix epoch) */\n\ttimestamp?: number;\n}\n\ninterface HistogramMetric {\n\tname: string;\n\tlabels: Record<string, string>;\n\tsum: number;\n\tcount: number;\n\tboundaries: readonly number[];\n\tbuckets: Map<number, number>;\n}\n\n/**\n * Histogram bucket boundaries for latency tracking.\n */\nconst DEFAULT_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10];\n\n/**\n * Prometheus-compatible metrics collector.\n *\n * Collects and exports metrics in Prometheus text format for scraping.\n * Thread-safe and supports counters, gauges, and histograms.\n *\n * @remarks\n * **Metric Types:**\n * - **Counter**: Cumulative value that only increases (e.g., request counts)\n * - **Gauge**: Value that can go up or down (e.g., active connections)\n * - **Histogram**: Sampling observations (e.g., request latency)\n *\n * **Labels:**\n * Metrics can have labels for dimensional data:\n * ```typescript\n * counter('http_requests_total', { method: 'GET', status: '200' });\n * ```\n *\n * **Export Format:**\n * Metrics are exported in Prometheus text format:\n * ```\n * # HELP http_requests_total Total HTTP requests\n * # TYPE http_requests_total counter\n * http_requests_total{method=\"GET\",status=\"200\"} 1234\n * ```\n *\n * @example\n * ```typescript\n * const metrics = new Metrics({ prefix: 'mcp_server' });\n *\n * // Count requests\n * metrics.counter('requests_total', { method: 'GET' }).inc();\n *\n * // Track active connections\n * const activeConnections = metrics.gauge('active_connections');\n * activeConnections.set(5);\n * activeConnections.dec();\n *\n * // Record latency\n * metrics.histogram('request_duration_seconds').observe(0.023);\n *\n * // Export for Prometheus\n * const prometheusText = metrics.export();\n * ```\n */\nexport class Metrics {\n\t/** Metrics storage indexed by name and label hash */\n\tprivate _metrics: Map<string, Metric>;\n\n\t/** Histogram samples */\n\tprivate _histograms: Map<string, HistogramMetric>;\n\n\t/** Prefix for all metric names */\n\tprivate _prefix: string;\n\n\t/** Default labels to apply to all metrics */\n\tprivate _defaultLabels: Record<string, string>;\n\n\t/** Counter for metric collection operations */\n\tprivate _operationsCounter: number = 0;\n\n\t/**\n\t * Creates a new Metrics instance.\n\t *\n\t * @param options - Configuration options\n\t *\n\t * @example\n\t * ```typescript\n\t * const metrics = new Metrics({ prefix: 'mcp_server' });\n\t * ```\n\t */\n\tconstructor(options: { prefix?: string; defaultLabels?: Record<string, string> } = {}) {\n\t\tthis._metrics = new Map();\n\t\tthis._histograms = new Map();\n\t\tthis._prefix = options.prefix ?? '';\n\t\tthis._defaultLabels = { ...options.defaultLabels };\n\t}\n\n\t/**\n\t * Creates a counter metric.\n\t *\n\t * @param name - Metric name\n\t * @param value - Increment value (default: 1)\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.counter('requests_total', 1, { method: 'GET' });\n\t * metrics.counter('errors_total', 1, { type: 'timeout' });\n\t * ```\n\t */\n\tcounter(name: string, value = 1, labels: Record<string, string> = {}, help?: string): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst existing = this._metrics.get(key);\n\n\t\tif (existing) {\n\t\t\texisting.value += value;\n\t\t\tif (help && !existing.help) {\n\t\t\t\texisting.help = help;\n\t\t\t}\n\t\t} else {\n\t\t\tthis._metrics.set(key, {\n\t\t\t\tname: fullName,\n\t\t\t\ttype: MetricType.Counter,\n\t\t\t\tvalue,\n\t\t\t\tlabels: { ...allLabels },\n\t\t\t\thelp,\n\t\t\t});\n\t\t}\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Creates a gauge metric.\n\t *\n\t * @param name - Metric name\n\t * @param value - Current value\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t *\n\t * @example\n\t * ```typescript\n\t * const activeConnections = metrics.gauge('active_connections');\n\t * activeConnections.set(5);\n\t * activeConnections.dec();\n\t * ```\n\t */\n\tgauge(name: string, value: number, labels: Record<string, string> = {}, help?: string): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst existing = this._metrics.get(key);\n\t\tthis._metrics.set(key, {\n\t\t\tname: fullName,\n\t\t\ttype: MetricType.Gauge,\n\t\t\tvalue,\n\t\t\tlabels: { ...allLabels },\n\t\t\thelp: help ?? existing?.help,\n\t\t});\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Records a histogram observation.\n\t *\n\t * @param name - Histogram name\n\t * @param value - Observed value\n\t * @param labels - Optional labels\n\t * @param help - Help text\n\t * @param buckets - Custom bucket boundaries\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.histogram('request_duration_seconds').observe(0.023);\n\t * metrics.histogram('thought_processing_ms').observe(45);\n\t * ```\n\t */\n\thistogram(\n\t\tname: string,\n\t\tvalue: number,\n\t\tlabels: Record<string, string> = {},\n\t\tbuckets = DEFAULT_BUCKETS\n\t): void {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\tconst histogram = this._histograms.get(key);\n\t\tlet previousBoundary = -Infinity;\n\t\tfor (const boundary of buckets) {\n\t\t\tif (!Number.isFinite(boundary) || boundary <= previousBoundary) {\n\t\t\t\tthrow new RangeError('Histogram boundaries must be finite and strictly increasing');\n\t\t\t}\n\t\t\tpreviousBoundary = boundary;\n\t\t}\n\t\tif (\n\t\t\thistogram &&\n\t\t\t(histogram.boundaries.length !== buckets.length ||\n\t\t\t\thistogram.boundaries.some((boundary, index) => boundary !== buckets[index]))\n\t\t) {\n\t\t\tthrow new RangeError('Histogram bucket layout differs from the existing series');\n\t\t}\n\n\t\tif (histogram) {\n\t\t\thistogram.sum += value;\n\t\t\thistogram.count += 1;\n\t\t\tfor (const boundary of histogram.boundaries) {\n\t\t\t\tif (value <= boundary) {\n\t\t\t\t\thistogram.buckets.set(boundary, (histogram.buckets.get(boundary) ?? 0) + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst histogramData = {\n\t\t\t\tname: fullName,\n\t\t\t\tlabels: { ...allLabels },\n\t\t\t\tsum: value,\n\t\t\t\tcount: 1,\n\t\t\t\tboundaries: [...buckets],\n\t\t\t\tbuckets: new Map<number, number>(),\n\t\t\t};\n\t\t\tfor (const boundary of buckets) {\n\t\t\t\thistogramData.buckets.set(boundary, value <= boundary ? 1 : 0);\n\t\t\t}\n\t\t\tthis._histograms.set(key, histogramData);\n\t\t}\n\t\tthis._operationsCounter++;\n\t}\n\n\t/**\n\t * Gets the current value of a metric.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Labels\n\t * @returns Current value or undefined if not found\n\t *\n\t * @example\n\t * ```typescript\n\t * const count = metrics.get('requests_total', { method: 'GET' });\n\t * ```\n\t */\n\tget(name: string, labels: Record<string, string> = {}): number | undefined {\n\t\tconst fullName = this._fullName(name);\n\t\tconst allLabels = { ...this._defaultLabels, ...labels };\n\t\tconst key = this._metricKey(fullName, allLabels);\n\t\treturn this._metrics.get(key)?.value;\n\t}\n\n\t/**\n\t * Increments a counter by 1.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Optional labels\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.inc('requests_total', { method: 'GET' });\n\t * ```\n\t */\n\tinc(name: string, labels?: Record<string, string>): void {\n\t\tthis.counter(name, 1, labels);\n\t}\n\n\t/**\n\t * Decrements a gauge by 1.\n\t *\n\t * @param name - Metric name\n\t * @param labels - Optional labels\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.dec('active_connections');\n\t * ```\n\t */\n\tdec(name: string, labels?: Record<string, string>): void {\n\t\tconst value = this.get(name, labels) ?? 0;\n\t\tthis.gauge(name, value - 1, labels);\n\t}\n\n\t/**\n\t * Resets all metrics to zero.\n\t * Useful for testing or on server restart.\n\t *\n\t * @example\n\t * ```typescript\n\t * metrics.reset();\n\t * ```\n\t */\n\treset(): void {\n\t\tthis._metrics.clear();\n\t\tthis._histograms.clear();\n\t\tthis._operationsCounter = 0;\n\t}\n\n\t/**\n\t * Gets the number of metric operations performed.\n\t * Useful for testing.\n\t *\n\t * @returns Operation count\n\t *\n\t * @example\n\t * ```typescript\n\t * const ops = metrics.getOperationCount();\n\t * ```\n\t */\n\tgetOperationCount(): number {\n\t\treturn this._operationsCounter;\n\t}\n\n\t/**\n\t * Exports metrics in Prometheus text format.\n\t *\n\t * @returns Prometheus text format string\n\t *\n\t * @example\n\t * ```typescript\n\t * const prometheusText = metrics.export();\n\t * console.log(prometheusText);\n\t * // Output:\n\t * // # HELP http_requests_total Total HTTP requests\n\t * // # TYPE http_requests_total counter\n\t * // http_requests_total{method=\"GET\",status=\"200\"} 1234\n\t * ```\n\t */\n\texport(): string {\n\t\tconst lines: string[] = [];\n\n\t\tconst metrics = Array.from(this._metrics.values());\n\t\tconst histograms = Array.from(this._histograms.values());\n\n\t\tconst helpEntries = new Map<string, string>();\n\t\tconst typeEntries = new Map<string, MetricType>();\n\n\t\tfor (const metric of metrics) {\n\t\t\tif (!helpEntries.has(metric.name)) {\n\t\t\t\tconst helpText = metric.help ?? `${metric.name} metric`;\n\t\t\t\tlines.push(\n\t\t\t\t\t`# HELP ${metric.name} ${helpText.replaceAll('\\\\', '\\\\\\\\').replaceAll('\\n', '\\\\n')}`\n\t\t\t\t);\n\t\t\t\thelpEntries.set(metric.name, helpText);\n\t\t\t}\n\t\t\tif (!typeEntries.has(metric.name)) {\n\t\t\t\tlines.push(`# TYPE ${metric.name} ${metric.type}`);\n\t\t\t\ttypeEntries.set(metric.name, metric.type);\n\t\t\t}\n\n\t\t\tconst labelStr = this._formatLabels(metric.labels);\n\t\t\tlines.push(`${metric.name}{${labelStr}} ${metric.value}`);\n\t\t}\n\n\t\tfor (const histogram of histograms) {\n\t\t\tconst { name: fullName, labels } = histogram;\n\t\t\tif (histogram.count > 0) {\n\t\t\t\tif (!typeEntries.has(fullName)) {\n\t\t\t\t\tlines.push(`# TYPE ${fullName} histogram`);\n\t\t\t\t\ttypeEntries.set(fullName, MetricType.Histogram);\n\t\t\t\t}\n\n\t\t\t\tconst labelStr = this._formatLabels(labels);\n\t\t\t\tconst formatMetricLine = (suffix: string, value: number): string => {\n\t\t\t\t\tif (labelStr.length === 0) {\n\t\t\t\t\t\treturn `${fullName}${suffix} ${value}`;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn `${fullName}${suffix}{${labelStr}} ${value}`;\n\t\t\t\t};\n\n\t\t\t\tlines.push(formatMetricLine('_sum', histogram.sum));\n\t\t\t\tlines.push(formatMetricLine('_count', histogram.count));\n\n\t\t\t\tfor (const boundary of histogram.boundaries) {\n\t\t\t\t\tconst count = histogram.buckets.get(boundary);\n\t\t\t\t\tconst boundaryLabel = String(boundary);\n\t\t\t\t\tconst boundaryLabelStr = this._formatLabels({ le: boundaryLabel });\n\t\t\t\t\tconst bucketLabels =\n\t\t\t\t\t\tlabelStr.length === 0 ? boundaryLabelStr : `${labelStr},${boundaryLabelStr}`;\n\t\t\t\t\tlines.push(`${fullName}_bucket{${bucketLabels}} ${count}`);\n\t\t\t\t}\n\t\t\t\tconst infLabelStr = this._formatLabels({ le: '+Inf' });\n\t\t\t\tconst infLabels = labelStr.length === 0 ? infLabelStr : `${labelStr},${infLabelStr}`;\n\t\t\t\tlines.push(`${fullName}_bucket{${infLabels}} ${histogram.count}`);\n\t\t\t}\n\t\t}\n\n\t\treturn lines.join('\\n');\n\t}\n\n\t/**\n\t * Gets metric name with prefix.\n\t * @param name - Metric name\n\t * @returns Full metric name\n\t * @private\n\t */\n\tprivate _fullName(name: string): string {\n\t\tif (!this._prefix) {\n\t\t\treturn name;\n\t\t}\n\n\t\tconst prefix = `${this._prefix}_`;\n\t\treturn name.startsWith(prefix) ? name : `${prefix}${name}`;\n\t}\n\n\t/**\n\t * Creates a unique key for a metric with labels.\n\t * @param name - Metric name\n\t * @param labels - Labels\n\t * @returns Unique key\n\t * @private\n\t */\n\tprivate _metricKey(name: string, labels: Record<string, string>): string {\n\t\tconst sortedLabels = Object.entries(labels).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n\t\treturn JSON.stringify([name, sortedLabels]);\n\t}\n\n\tprivate _formatLabels(labels: Record<string, string>): string {\n\t\treturn Object.entries(labels)\n\t\t\t.map(([key, value]) => `${key}=\"${this._escapeLabelValue(value)}\"`)\n\t\t\t.join(',');\n\t}\n\n\tprivate _escapeLabelValue(value: string): string {\n\t\treturn value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"').replaceAll('\\n', '\\\\n');\n\t}\n}\n"],"names":["MetricType","DEFAULT_BUCKETS","Metrics","options","Map","name","value","labels","help","fullName","allLabels","key","existing","buckets","histogram","previousBoundary","boundary","Number","RangeError","index","histogramData","lines","metrics","Array","histograms","helpEntries","typeEntries","metric","helpText","labelStr","formatMetricLine","suffix","count","boundaryLabel","String","boundaryLabelStr","bucketLabels","infLabelStr","infLabels","prefix","sortedLabels","Object","a","b","JSON"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BranchId, SessionId, ThoughtId } from '../contracts/ids.js';
|
|
2
|
+
import type { ThoughtData } from '../core/thought.js';
|
|
3
|
+
export type PersistedBranchSnapshot = {
|
|
4
|
+
readonly branchId: BranchId;
|
|
5
|
+
readonly thoughts: readonly ThoughtData[];
|
|
6
|
+
};
|
|
7
|
+
export type StagedThoughtState = {
|
|
8
|
+
readonly history: readonly ThoughtData[];
|
|
9
|
+
readonly branches: readonly PersistedBranchSnapshot[];
|
|
10
|
+
};
|
|
11
|
+
export declare function stageBacktrackPersistence(sessionId: SessionId, history: readonly ThoughtData[], branches: readonly PersistedBranchSnapshot[], thought: ThoughtData, targetThoughtId: ThoughtId, maxHistorySize: number): StagedThoughtState;
|
|
12
|
+
export declare function repairRetainedBacktracks(sessionId: SessionId, history: readonly ThoughtData[], branches: readonly PersistedBranchSnapshot[]): StagedThoughtState;
|
|
13
|
+
//# sourceMappingURL=BacktrackPersistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BacktrackPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/BacktrackPersistence.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAStD,MAAM,MAAM,uBAAuB,GAAG;IACrC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAChC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACtD,CAAC;AA0BF,wBAAgB,yBAAyB,CACxC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,SAAS,EAC1B,cAAc,EAAE,MAAM,GACpB,kBAAkB,CA2CpB;AAED,wBAAgB,wBAAwB,CACvC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,QAAQ,EAAE,SAAS,uBAAuB,EAAE,GAC1C,kBAAkB,CAiDpB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { isDeepStrictEqual } from "node:util";
|
|
2
|
+
import { PersistenceCompatibilityError } from "../errors.js";
|
|
3
|
+
import { assertBranchScope, assertPersistableThoughtCollections, assertThoughtScope } from "./PersistenceScope.js";
|
|
4
|
+
function cloneThoughts(thoughts) {
|
|
5
|
+
return [
|
|
6
|
+
...structuredClone(thoughts)
|
|
7
|
+
];
|
|
8
|
+
}
|
|
9
|
+
function collections(sessionId, history, branches) {
|
|
10
|
+
return [
|
|
11
|
+
{
|
|
12
|
+
sessionId,
|
|
13
|
+
thoughts: history
|
|
14
|
+
},
|
|
15
|
+
...branches.map((branch)=>({
|
|
16
|
+
sessionId,
|
|
17
|
+
thoughts: branch.thoughts
|
|
18
|
+
}))
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
function retractCopies(thoughts, targetThoughtId) {
|
|
22
|
+
return thoughts.map((thought)=>thought.id === targetThoughtId ? {
|
|
23
|
+
...thought,
|
|
24
|
+
retracted: true
|
|
25
|
+
} : thought);
|
|
26
|
+
}
|
|
27
|
+
function stageBacktrackPersistence(sessionId, history, branches, thought, targetThoughtId, maxHistorySize) {
|
|
28
|
+
assertThoughtScope('saveBacktrackForSession', sessionId, thought);
|
|
29
|
+
if ('backtrack' !== thought.thought_type) throw new PersistenceCompatibilityError(`${sessionId}/thoughts`, 'saveBacktrackForSession requires a backtrack thought');
|
|
30
|
+
if (0 === targetThoughtId.length) throw new PersistenceCompatibilityError(`${sessionId}/thoughts`, 'backtrack target thought id must not be empty');
|
|
31
|
+
const stagedHistory = cloneThoughts(history);
|
|
32
|
+
const stagedBranches = branches.map((branch)=>({
|
|
33
|
+
branchId: branch.branchId,
|
|
34
|
+
thoughts: cloneThoughts(branch.thoughts)
|
|
35
|
+
}));
|
|
36
|
+
assertPersistableThoughtCollections(collections(sessionId, stagedHistory, stagedBranches), `${sessionId}/backtrack`);
|
|
37
|
+
const correctedHistory = [
|
|
38
|
+
...retractCopies(stagedHistory, targetThoughtId),
|
|
39
|
+
structuredClone(thought)
|
|
40
|
+
];
|
|
41
|
+
const retainedHistory = maxHistorySize > 0 ? correctedHistory.slice(-maxHistorySize) : correctedHistory;
|
|
42
|
+
const correctedBranches = stagedBranches.map((branch)=>({
|
|
43
|
+
branchId: branch.branchId,
|
|
44
|
+
thoughts: retractCopies(branch.thoughts, targetThoughtId)
|
|
45
|
+
}));
|
|
46
|
+
for (const branch of correctedBranches)assertBranchScope('saveBranchForSession', sessionId, branch.branchId, branch.thoughts);
|
|
47
|
+
assertPersistableThoughtCollections(collections(sessionId, retainedHistory, correctedBranches), `${sessionId}/backtrack`);
|
|
48
|
+
return {
|
|
49
|
+
history: retainedHistory,
|
|
50
|
+
branches: correctedBranches
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function repairRetainedBacktracks(sessionId, history, branches) {
|
|
54
|
+
let repairedHistory = cloneThoughts(history);
|
|
55
|
+
let repairedBranches = branches.map((branch)=>({
|
|
56
|
+
branchId: branch.branchId,
|
|
57
|
+
thoughts: cloneThoughts(branch.thoughts)
|
|
58
|
+
}));
|
|
59
|
+
const allThoughts = ()=>[
|
|
60
|
+
...repairedHistory,
|
|
61
|
+
...repairedBranches.flatMap((branch)=>branch.thoughts)
|
|
62
|
+
];
|
|
63
|
+
const backtracks = new Map();
|
|
64
|
+
for (const thought of allThoughts())if (void 0 !== thought.id && 'backtrack' === thought.thought_type) {
|
|
65
|
+
const existing = backtracks.get(thought.id);
|
|
66
|
+
if (void 0 === existing || isDeepStrictEqual(existing, thought)) backtracks.set(thought.id, thought);
|
|
67
|
+
}
|
|
68
|
+
for (const backtrack of backtracks.values()){
|
|
69
|
+
if (void 0 === backtrack.backtrack_target) continue;
|
|
70
|
+
const targetIds = new Set();
|
|
71
|
+
for (const candidate of allThoughts())if (void 0 !== candidate.id && candidate.id !== backtrack.id && candidate.thought_number === backtrack.backtrack_target) targetIds.add(candidate.id);
|
|
72
|
+
if (0 === targetIds.size) continue;
|
|
73
|
+
if (targetIds.size > 1) throw new PersistenceCompatibilityError(`restore:${sessionId}`, `ambiguous retained backtrack target ${backtrack.backtrack_target}`);
|
|
74
|
+
const targetThoughtId = targetIds.values().next().value;
|
|
75
|
+
if (void 0 !== targetThoughtId) {
|
|
76
|
+
repairedHistory = retractCopies(repairedHistory, targetThoughtId);
|
|
77
|
+
repairedBranches = repairedBranches.map((branch)=>({
|
|
78
|
+
branchId: branch.branchId,
|
|
79
|
+
thoughts: retractCopies(branch.thoughts, targetThoughtId)
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
history: repairedHistory,
|
|
85
|
+
branches: repairedBranches
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export { repairRetainedBacktracks, stageBacktrackPersistence };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=BacktrackPersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence/BacktrackPersistence.js","sources":["../../src/persistence/BacktrackPersistence.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util';\nimport type { BranchId, SessionId, ThoughtId } from '../contracts/ids.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError } from '../errors.js';\nimport {\n\tassertBranchScope,\n\tassertPersistableThoughtCollections,\n\tassertThoughtScope,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\n\nexport type PersistedBranchSnapshot = {\n\treadonly branchId: BranchId;\n\treadonly thoughts: readonly ThoughtData[];\n};\n\nexport type StagedThoughtState = {\n\treadonly history: readonly ThoughtData[];\n\treadonly branches: readonly PersistedBranchSnapshot[];\n};\n\nfunction cloneThoughts(thoughts: readonly ThoughtData[]): ThoughtData[] {\n\treturn [...structuredClone(thoughts)];\n}\n\nfunction collections(\n\tsessionId: SessionId,\n\thistory: readonly ThoughtData[],\n\tbranches: readonly PersistedBranchSnapshot[]\n): PersistedThoughtCollection[] {\n\treturn [\n\t\t{ sessionId, thoughts: history },\n\t\t...branches.map((branch) => ({ sessionId, thoughts: branch.thoughts })),\n\t];\n}\n\nfunction retractCopies(\n\tthoughts: readonly ThoughtData[],\n\ttargetThoughtId: ThoughtId\n): ThoughtData[] {\n\treturn thoughts.map((thought) =>\n\t\tthought.id === targetThoughtId ? { ...thought, retracted: true } : thought\n\t);\n}\n\nexport function stageBacktrackPersistence(\n\tsessionId: SessionId,\n\thistory: readonly ThoughtData[],\n\tbranches: readonly PersistedBranchSnapshot[],\n\tthought: ThoughtData,\n\ttargetThoughtId: ThoughtId,\n\tmaxHistorySize: number\n): StagedThoughtState {\n\tassertThoughtScope('saveBacktrackForSession', sessionId, thought);\n\tif (thought.thought_type !== 'backtrack') {\n\t\tthrow new PersistenceCompatibilityError(\n\t\t\t`${sessionId}/thoughts`,\n\t\t\t'saveBacktrackForSession requires a backtrack thought'\n\t\t);\n\t}\n\tif (targetThoughtId.length === 0) {\n\t\tthrow new PersistenceCompatibilityError(\n\t\t\t`${sessionId}/thoughts`,\n\t\t\t'backtrack target thought id must not be empty'\n\t\t);\n\t}\n\n\tconst stagedHistory = cloneThoughts(history);\n\tconst stagedBranches = branches.map((branch) => ({\n\t\tbranchId: branch.branchId,\n\t\tthoughts: cloneThoughts(branch.thoughts),\n\t}));\n\tassertPersistableThoughtCollections(\n\t\tcollections(sessionId, stagedHistory, stagedBranches),\n\t\t`${sessionId}/backtrack`\n\t);\n\n\tconst correctedHistory = [\n\t\t...retractCopies(stagedHistory, targetThoughtId),\n\t\tstructuredClone(thought),\n\t];\n\tconst retainedHistory =\n\t\tmaxHistorySize > 0 ? correctedHistory.slice(-maxHistorySize) : correctedHistory;\n\tconst correctedBranches = stagedBranches.map((branch) => ({\n\t\tbranchId: branch.branchId,\n\t\tthoughts: retractCopies(branch.thoughts, targetThoughtId),\n\t}));\n\tfor (const branch of correctedBranches) {\n\t\tassertBranchScope('saveBranchForSession', sessionId, branch.branchId, branch.thoughts);\n\t}\n\tassertPersistableThoughtCollections(\n\t\tcollections(sessionId, retainedHistory, correctedBranches),\n\t\t`${sessionId}/backtrack`\n\t);\n\treturn { history: retainedHistory, branches: correctedBranches };\n}\n\nexport function repairRetainedBacktracks(\n\tsessionId: SessionId,\n\thistory: readonly ThoughtData[],\n\tbranches: readonly PersistedBranchSnapshot[]\n): StagedThoughtState {\n\tlet repairedHistory = cloneThoughts(history);\n\tlet repairedBranches = branches.map((branch) => ({\n\t\tbranchId: branch.branchId,\n\t\tthoughts: cloneThoughts(branch.thoughts),\n\t}));\n\tconst allThoughts = (): readonly ThoughtData[] => [\n\t\t...repairedHistory,\n\t\t...repairedBranches.flatMap((branch) => branch.thoughts),\n\t];\n\tconst backtracks = new Map<string, ThoughtData>();\n\tfor (const thought of allThoughts()) {\n\t\tif (thought.id !== undefined && thought.thought_type === 'backtrack') {\n\t\t\tconst existing = backtracks.get(thought.id);\n\t\t\tif (existing === undefined || isDeepStrictEqual(existing, thought)) {\n\t\t\t\tbacktracks.set(thought.id, thought);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const backtrack of backtracks.values()) {\n\t\tif (backtrack.backtrack_target === undefined) continue;\n\t\tconst targetIds = new Set<ThoughtId>();\n\t\tfor (const candidate of allThoughts()) {\n\t\t\tif (\n\t\t\t\tcandidate.id !== undefined &&\n\t\t\t\tcandidate.id !== backtrack.id &&\n\t\t\t\tcandidate.thought_number === backtrack.backtrack_target\n\t\t\t) {\n\t\t\t\ttargetIds.add(candidate.id);\n\t\t\t}\n\t\t}\n\t\tif (targetIds.size === 0) continue;\n\t\tif (targetIds.size > 1) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t`restore:${sessionId}`,\n\t\t\t\t`ambiguous retained backtrack target ${backtrack.backtrack_target}`\n\t\t\t);\n\t\t}\n\t\tconst targetThoughtId = targetIds.values().next().value;\n\t\tif (targetThoughtId === undefined) continue;\n\t\trepairedHistory = retractCopies(repairedHistory, targetThoughtId);\n\t\trepairedBranches = repairedBranches.map((branch) => ({\n\t\t\tbranchId: branch.branchId,\n\t\t\tthoughts: retractCopies(branch.thoughts, targetThoughtId),\n\t\t}));\n\t}\n\n\treturn { history: repairedHistory, branches: repairedBranches };\n}\n"],"names":["cloneThoughts","thoughts","structuredClone","collections","sessionId","history","branches","branch","retractCopies","targetThoughtId","thought","stageBacktrackPersistence","maxHistorySize","assertThoughtScope","PersistenceCompatibilityError","stagedHistory","stagedBranches","assertPersistableThoughtCollections","correctedHistory","retainedHistory","correctedBranches","assertBranchScope","repairRetainedBacktracks","repairedHistory","repairedBranches","allThoughts","backtracks","Map","undefined","existing","isDeepStrictEqual","backtrack","targetIds","Set","candidate"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IMetrics } from '../contracts/interfaces.js';
|
|
2
2
|
import type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
3
|
-
import { type BranchId, type SessionId } from '../contracts/ids.js';
|
|
3
|
+
import { type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';
|
|
4
4
|
import type { Summary } from '../core/compression/Summary.js';
|
|
5
5
|
import type { Edge } from '../core/graph/Edge.js';
|
|
6
6
|
import type { ThoughtData } from '../core/thought.js';
|
|
@@ -18,6 +18,7 @@ export declare class FilePersistence implements PersistenceBackend {
|
|
|
18
18
|
constructor(options?: FilePersistenceOptions);
|
|
19
19
|
static create(options?: FilePersistenceOptions): Promise<FilePersistence>;
|
|
20
20
|
saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;
|
|
21
|
+
saveBacktrackForSession(sessionId: SessionId, thought: ThoughtData, targetThoughtId: ThoughtId): Promise<void>;
|
|
21
22
|
private _saveThought;
|
|
22
23
|
loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;
|
|
23
24
|
saveBranchForSession(sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): Promise<void>;
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"FilePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/FilePersistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import { asSessionId } from "../contracts/ids.js";
|
|
6
6
|
import { PersistenceCompatibilityError } from "../errors.js";
|
|
7
7
|
import { EMPTY_FILE_SNAPSHOT_V2, parseFileSnapshotV2, serializeFileSnapshotV2, sessionsInSnapshot } from "./FileSnapshotV2.js";
|
|
8
|
+
import { stageBacktrackPersistence } from "./BacktrackPersistence.js";
|
|
8
9
|
import { FILE_WRITER_LOCK_NAME, FileWriter } from "./FileWriter.js";
|
|
9
10
|
import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertPersistableThoughts, assertSummaryScopes, assertThoughtScope, compareCodePoint, parsePersistenceBranchId } from "./PersistenceScope.js";
|
|
10
11
|
const SNAPSHOT_NAME = 'snapshot.json';
|
|
@@ -38,6 +39,33 @@ class FilePersistence {
|
|
|
38
39
|
assertThoughtScope('saveThoughtForSession', validatedSessionId, thought);
|
|
39
40
|
await this._saveThought(validatedSessionId, thought);
|
|
40
41
|
}
|
|
42
|
+
async saveBacktrackForSession(sessionId, thought, targetThoughtId) {
|
|
43
|
+
const validatedSessionId = asSessionId(sessionId);
|
|
44
|
+
await this._mutate('save_backtrack', (snapshot)=>{
|
|
45
|
+
const staged = stageBacktrackPersistence(validatedSessionId, snapshot.thoughts.find((record)=>record.sessionId === validatedSessionId)?.thoughts ?? [], snapshot.branches.filter((record)=>record.sessionId === validatedSessionId).map((record)=>({
|
|
46
|
+
branchId: record.branchId,
|
|
47
|
+
thoughts: record.thoughts
|
|
48
|
+
})), thought, targetThoughtId, this._maxHistorySize);
|
|
49
|
+
return {
|
|
50
|
+
...snapshot,
|
|
51
|
+
thoughts: [
|
|
52
|
+
...snapshot.thoughts.filter((record)=>record.sessionId !== validatedSessionId),
|
|
53
|
+
{
|
|
54
|
+
sessionId: validatedSessionId,
|
|
55
|
+
thoughts: staged.history
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
branches: [
|
|
59
|
+
...snapshot.branches.filter((record)=>record.sessionId !== validatedSessionId),
|
|
60
|
+
...staged.branches.map((branch)=>({
|
|
61
|
+
sessionId: validatedSessionId,
|
|
62
|
+
branchId: branch.branchId,
|
|
63
|
+
thoughts: branch.thoughts
|
|
64
|
+
}))
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
41
69
|
async _saveThought(sessionId, thought) {
|
|
42
70
|
assertPersistableThoughts([
|
|
43
71
|
thought
|
|
@@ -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\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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"}
|
|
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 { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } 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 { stageBacktrackPersistence } from './BacktrackPersistence.js';\nimport { FILE_WRITER_LOCK_NAME, FileWriter, 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';\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\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tawait this._mutate('save_backtrack', (snapshot) => {\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tsnapshot.thoughts.find((record) => record.sessionId === validatedSessionId)?.thoughts ?? [],\n\t\t\t\tsnapshot.branches\n\t\t\t\t\t.filter((record) => record.sessionId === validatedSessionId)\n\t\t\t\t\t.map((record) => ({ branchId: record.branchId, thoughts: record.thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\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 !== validatedSessionId),\n\t\t\t\t\t{ sessionId: validatedSessionId, thoughts: staged.history },\n\t\t\t\t],\n\t\t\t\tbranches: [\n\t\t\t\t\t...snapshot.branches.filter((record) => record.sessionId !== validatedSessionId),\n\t\t\t\t\t...staged.branches.map((branch) => ({\n\t\t\t\t\t\tsessionId: validatedSessionId,\n\t\t\t\t\t\tbranchId: branch.branchId,\n\t\t\t\t\t\tthoughts: branch.thoughts,\n\t\t\t\t\t})),\n\t\t\t\t],\n\t\t\t};\n\t\t});\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(dataDir, 'directory does not match File v2 layout');\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","targetThoughtId","snapshot","staged","stageBacktrackPersistence","record","branch","assertPersistableThoughts","current","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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"}
|
|
@@ -7,6 +7,7 @@ export declare const FileSnapshotV2Schema: v.StrictObjectSchema<{
|
|
|
7
7
|
readonly thoughts: v.ArraySchema<v.StrictObjectSchema<{
|
|
8
8
|
readonly sessionId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
|
|
9
9
|
readonly thoughts: v.ArraySchema<v.ObjectSchema<{
|
|
10
|
+
readonly retracted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
10
11
|
readonly available_mcp_tools: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.DescriptionAction<string[], "Array of MCP tool names available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])">]>, undefined>;
|
|
11
12
|
readonly available_skills: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.DescriptionAction<string[], "Array of skill names available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])">]>, undefined>;
|
|
12
13
|
readonly thought: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.DescriptionAction<string, "Your current thinking step">]>;
|
|
@@ -176,6 +177,7 @@ export declare const FileSnapshotV2Schema: v.StrictObjectSchema<{
|
|
|
176
177
|
readonly sessionId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
|
|
177
178
|
readonly branchId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
|
|
178
179
|
readonly thoughts: v.ArraySchema<v.ObjectSchema<{
|
|
180
|
+
readonly retracted: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
|
|
179
181
|
readonly available_mcp_tools: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.DescriptionAction<string[], "Array of MCP tool names available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])">]>, undefined>;
|
|
180
182
|
readonly available_skills: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.StringSchema<undefined>, undefined>, v.DescriptionAction<string[], "Array of skill names available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])">]>, undefined>;
|
|
181
183
|
readonly thought: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.DescriptionAction<string, "Your current thinking step">]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileSnapshotV2.d.ts","sourceRoot":"","sources":["../../src/persistence/FileSnapshotV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"FileSnapshotV2.d.ts","sourceRoot":"","sources":["../../src/persistence/FileSnapshotV2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAgC7D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAM/B,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,cAMpC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAmCvF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAuB5F;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,EAAE,CAWxE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAEjE"}
|
|
@@ -8,14 +8,18 @@ import { validateFileSnapshotV2 } from "./FileSnapshotValidation.js";
|
|
|
8
8
|
import * as __rspack_external_valibot from "valibot";
|
|
9
9
|
const SessionIdStringSchema = __rspack_external_valibot.pipe(__rspack_external_valibot.string(), __rspack_external_valibot.regex(/^[A-Za-z0-9_-]{1,100}$/));
|
|
10
10
|
const BranchIdStringSchema = __rspack_external_valibot.pipe(__rspack_external_valibot.string(), __rspack_external_valibot.regex(/^[A-Za-z0-9_-]{1,50}$/));
|
|
11
|
+
const PersistedThoughtV2Schema = __rspack_external_valibot.object({
|
|
12
|
+
...SequentialThinkingSchema.entries,
|
|
13
|
+
retracted: __rspack_external_valibot.optional(__rspack_external_valibot.boolean())
|
|
14
|
+
});
|
|
11
15
|
const ThoughtSessionV2Schema = __rspack_external_valibot.strictObject({
|
|
12
16
|
sessionId: SessionIdStringSchema,
|
|
13
|
-
thoughts: __rspack_external_valibot.array(
|
|
17
|
+
thoughts: __rspack_external_valibot.array(PersistedThoughtV2Schema)
|
|
14
18
|
});
|
|
15
19
|
const BranchRecordV2Schema = __rspack_external_valibot.strictObject({
|
|
16
20
|
sessionId: SessionIdStringSchema,
|
|
17
21
|
branchId: BranchIdStringSchema,
|
|
18
|
-
thoughts: __rspack_external_valibot.array(
|
|
22
|
+
thoughts: __rspack_external_valibot.array(PersistedThoughtV2Schema)
|
|
19
23
|
});
|
|
20
24
|
const EdgeSessionV2Schema = __rspack_external_valibot.strictObject({
|
|
21
25
|
sessionId: SessionIdStringSchema,
|
|
@@ -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 } 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(
|
|
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 PersistedThoughtV2Schema = v.object({\n\t...SequentialThinkingSchema.entries,\n\tretracted: v.optional(v.boolean()),\n});\nconst ThoughtSessionV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\n});\nconst BranchRecordV2Schema = v.strictObject({\n\tsessionId: SessionIdStringSchema,\n\tbranchId: BranchIdStringSchema,\n\tthoughts: v.array(PersistedThoughtV2Schema),\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","PersistedThoughtV2Schema","SequentialThinkingSchema","ThoughtSessionV2Schema","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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"}
|
|
@@ -2,7 +2,7 @@ import type { ThoughtData } from '../core/thought.js';
|
|
|
2
2
|
import type { Edge } from '../core/graph/Edge.js';
|
|
3
3
|
import type { Summary } from '../core/compression/Summary.js';
|
|
4
4
|
import type { PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
5
|
-
import { type BranchId, type SessionId } from '../contracts/ids.js';
|
|
5
|
+
import { type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';
|
|
6
6
|
export interface MemoryPersistenceOptions {
|
|
7
7
|
maxSize?: number;
|
|
8
8
|
maxHistorySize?: number;
|
|
@@ -17,6 +17,7 @@ export declare class MemoryPersistence implements PersistenceBackend {
|
|
|
17
17
|
private readonly _persistBranches;
|
|
18
18
|
constructor(options?: MemoryPersistenceOptions);
|
|
19
19
|
saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;
|
|
20
|
+
saveBacktrackForSession(sessionId: SessionId, thought: ThoughtData, targetThoughtId: ThoughtId): Promise<void>;
|
|
20
21
|
loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;
|
|
21
22
|
saveBranchForSession(sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): Promise<void>;
|
|
22
23
|
deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/MemoryPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"MemoryPersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/MemoryPersistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAejG,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC3D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuC;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsD;IAChF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;gBAE/B,OAAO,GAAE,wBAA6B;IAOrC,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBhF,uBAAuB,CACnC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,SAAS,GACxB,OAAO,CAAC,IAAI,CAAC;IAoBH,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAInE,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;IAuBH,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/E,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC;IAQxB,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAKjE,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAQpC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAI3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtE,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAIhD,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjF,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAGpE"}
|