@exaudeus/workrail 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +153 -189
  2. package/dist/application/services/classification-engine.d.ts +33 -0
  3. package/dist/application/services/classification-engine.js +258 -0
  4. package/dist/application/services/compression-service.d.ts +20 -0
  5. package/dist/application/services/compression-service.js +312 -0
  6. package/dist/application/services/context-management-service.d.ts +38 -0
  7. package/dist/application/services/context-management-service.js +301 -0
  8. package/dist/application/services/context-persistence-service.d.ts +45 -0
  9. package/dist/application/services/context-persistence-service.js +273 -0
  10. package/dist/cli/migrate-workflow.js +3 -2
  11. package/dist/infrastructure/storage/context-storage.d.ts +150 -0
  12. package/dist/infrastructure/storage/context-storage.js +40 -0
  13. package/dist/infrastructure/storage/filesystem-blob-storage.d.ts +27 -0
  14. package/dist/infrastructure/storage/filesystem-blob-storage.js +363 -0
  15. package/dist/infrastructure/storage/hybrid-context-storage.d.ts +29 -0
  16. package/dist/infrastructure/storage/hybrid-context-storage.js +400 -0
  17. package/dist/infrastructure/storage/migrations/001_initial_schema.sql +38 -0
  18. package/dist/infrastructure/storage/migrations/002_context_concurrency_enhancements.sql +234 -0
  19. package/dist/infrastructure/storage/migrations/003_classification_overrides.sql +20 -0
  20. package/dist/infrastructure/storage/sqlite-metadata-storage.d.ts +35 -0
  21. package/dist/infrastructure/storage/sqlite-metadata-storage.js +410 -0
  22. package/dist/infrastructure/storage/sqlite-migrator.d.ts +46 -0
  23. package/dist/infrastructure/storage/sqlite-migrator.js +293 -0
  24. package/dist/types/context-types.d.ts +236 -0
  25. package/dist/types/context-types.js +10 -0
  26. package/dist/utils/storage-security.js +1 -1
  27. package/package.json +4 -1
  28. package/workflows/coding-task-workflow-with-loops.json +434 -0
  29. package/workflows/mr-review-workflow.json +75 -26
  30. package/workflows/systemic-bug-investigation-with-loops.json +423 -0
@@ -0,0 +1,301 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ContextManagementService = void 0;
37
+ const crypto = __importStar(require("crypto"));
38
+ const error_handler_1 = require("../../core/error-handler");
39
+ class ContextManagementService {
40
+ constructor(persistenceService, storage) {
41
+ this.persistenceService = persistenceService;
42
+ this.storage = storage;
43
+ this.metrics = {
44
+ totalSaveOperations: 0,
45
+ totalLoadOperations: 0,
46
+ totalListOperations: 0,
47
+ totalMarkCriticalOperations: 0,
48
+ averageSaveTime: 0,
49
+ averageLoadTime: 0,
50
+ lastOperationTime: 0,
51
+ errorCount: 0
52
+ };
53
+ }
54
+ async saveCheckpoint(params) {
55
+ const startTimeMs = Date.now();
56
+ try {
57
+ const frozenParams = Object.freeze({ ...params });
58
+ const frozenContext = Object.freeze({ ...frozenParams.context });
59
+ const sessionId = frozenParams.sessionId || this.generateSessionId(frozenContext);
60
+ const lastCheckpointData = await this.getLastCheckpointData(sessionId);
61
+ const currentHash = this.hashContext(frozenParams.context);
62
+ if (!frozenParams.force && lastCheckpointData && lastCheckpointData.contextHash === currentHash) {
63
+ return {
64
+ checkpointId: lastCheckpointData.id || 'none',
65
+ sessionId,
66
+ status: 'SKIPPED_UNCHANGED',
67
+ sizeBytes: lastCheckpointData.contextSizeBytes || undefined
68
+ };
69
+ }
70
+ const pipelineResult = await this.persistenceService.processPersistencePipeline(frozenParams.context, '');
71
+ const checkpointId = this.generateCheckpointId(sessionId);
72
+ const metadata = {
73
+ id: checkpointId,
74
+ sessionId,
75
+ name: frozenParams.metadata?.name,
76
+ agentId: 'default',
77
+ createdAt: new Date().toISOString(),
78
+ tags: frozenParams.metadata?.tags,
79
+ contextSizeBytes: pipelineResult.compressed.compressedSize,
80
+ contextHash: currentHash,
81
+ blobPath: '',
82
+ classificationSummary: {
83
+ criticalCount: this.countLayers(pipelineResult.classified, 'CRITICAL'),
84
+ importantCount: this.countLayers(pipelineResult.classified, 'IMPORTANT'),
85
+ usefulCount: this.countLayers(pipelineResult.classified, 'USEFUL'),
86
+ ephemeralCount: this.countLayers(pipelineResult.classified, 'EPHEMERAL')
87
+ },
88
+ status: 'active'
89
+ };
90
+ await this.storage.saveCheckpoint(metadata, pipelineResult.compressed);
91
+ await this.upsertSessionInfo(sessionId);
92
+ const endTime = Date.now();
93
+ this.updateSaveMetrics(endTime - startTimeMs);
94
+ return {
95
+ checkpointId,
96
+ sessionId,
97
+ status: 'SAVED',
98
+ sizeBytes: pipelineResult.compressed.compressedSize
99
+ };
100
+ }
101
+ catch (error) {
102
+ this.metrics.errorCount++;
103
+ throw new Error(`Failed to save checkpoint: ${error instanceof Error ? error.message : 'Unknown error'}`);
104
+ }
105
+ }
106
+ async loadCheckpoint(params) {
107
+ const startTime = process.hrtime.bigint();
108
+ try {
109
+ const frozenParams = Object.freeze({ ...params });
110
+ if (!frozenParams.checkpointId && !frozenParams.sessionId) {
111
+ throw new Error('Either checkpointId or sessionId must be provided');
112
+ }
113
+ let checkpointId;
114
+ if (frozenParams.checkpointId) {
115
+ checkpointId = frozenParams.checkpointId;
116
+ }
117
+ else {
118
+ const checkpoints = await this.storage.listCheckpoints(frozenParams.sessionId, 1, 0);
119
+ if (!checkpoints || checkpoints.length === 0) {
120
+ throw new Error(`No checkpoints found for session: ${frozenParams.sessionId}`);
121
+ }
122
+ checkpointId = checkpoints[0].id;
123
+ }
124
+ const checkpointData = await this.storage.loadCheckpoint(checkpointId);
125
+ if (!checkpointData) {
126
+ throw new error_handler_1.CheckpointNotFoundError(checkpointId);
127
+ }
128
+ const restorationResult = await this.persistenceService.restoreFromPersistence(checkpointData.blob);
129
+ const metadata = checkpointData.metadata;
130
+ if (!metadata) {
131
+ throw new error_handler_1.CheckpointNotFoundError(checkpointId);
132
+ }
133
+ const endTime = process.hrtime.bigint();
134
+ this.updateLoadMetrics(endTime);
135
+ return {
136
+ checkpointId,
137
+ sessionId: metadata.sessionId,
138
+ context: restorationResult.context,
139
+ metadata: {
140
+ name: metadata.name,
141
+ tags: metadata.tags,
142
+ createdAt: metadata.createdAt,
143
+ contextSizeBytes: metadata.contextSizeBytes
144
+ }
145
+ };
146
+ }
147
+ catch (error) {
148
+ this.metrics.errorCount++;
149
+ throw new Error(`Failed to load checkpoint: ${error instanceof Error ? error.message : 'Unknown error'}`);
150
+ }
151
+ }
152
+ async listCheckpoints(params) {
153
+ const startTime = process.hrtime.bigint();
154
+ try {
155
+ const frozenParams = Object.freeze({ ...params });
156
+ const checkpoints = await this.storage.listCheckpoints(frozenParams.sessionId, frozenParams.limit || 20, frozenParams.offset || 0);
157
+ const endTime = process.hrtime.bigint();
158
+ this.updateListMetrics(endTime);
159
+ return checkpoints;
160
+ }
161
+ catch (error) {
162
+ this.metrics.errorCount++;
163
+ throw new Error(`Failed to list checkpoints: ${error instanceof Error ? error.message : 'Unknown error'}`);
164
+ }
165
+ }
166
+ async markCritical(params) {
167
+ const startTime = process.hrtime.bigint();
168
+ try {
169
+ const frozenParams = Object.freeze({ ...params });
170
+ const classificationEngine = this.persistenceService.getClassificationEngine();
171
+ await classificationEngine.markCritical(frozenParams.sessionId, frozenParams.contextKey);
172
+ const endTime = process.hrtime.bigint();
173
+ this.updateMarkCriticalMetrics(endTime);
174
+ return {
175
+ status: 'SUCCESS',
176
+ message: `Key '${frozenParams.contextKey}' marked as critical for session '${frozenParams.sessionId}'`
177
+ };
178
+ }
179
+ catch (error) {
180
+ this.metrics.errorCount++;
181
+ throw new Error(`Failed to mark critical: ${error instanceof Error ? error.message : 'Unknown error'}`);
182
+ }
183
+ }
184
+ getMetrics() {
185
+ return Object.freeze({ ...this.metrics });
186
+ }
187
+ resetMetrics() {
188
+ this.metrics = {
189
+ totalSaveOperations: 0,
190
+ totalLoadOperations: 0,
191
+ totalListOperations: 0,
192
+ totalMarkCriticalOperations: 0,
193
+ averageSaveTime: 0,
194
+ averageLoadTime: 0,
195
+ lastOperationTime: 0,
196
+ errorCount: 0
197
+ };
198
+ }
199
+ generateSessionId(context) {
200
+ const contextString = JSON.stringify(context, Object.keys(context).sort());
201
+ const hash = crypto.createHash('sha256').update(contextString).digest('hex');
202
+ return `session_${hash.substring(0, 16)}`;
203
+ }
204
+ generateCheckpointId(sessionId) {
205
+ const timestamp = Date.now();
206
+ const randomSuffix = crypto.randomBytes(4).toString('hex');
207
+ return `${sessionId}_checkpoint_${timestamp}_${randomSuffix}`;
208
+ }
209
+ async isContextUnchanged(sessionId, context) {
210
+ try {
211
+ const lastCheckpointData = await this.getLastCheckpointData(sessionId);
212
+ if (!lastCheckpointData.contextHash) {
213
+ return false;
214
+ }
215
+ const currentHash = this.hashContext(context);
216
+ return currentHash === lastCheckpointData.contextHash;
217
+ }
218
+ catch (error) {
219
+ console.warn(`Failed to check context changes: ${error instanceof Error ? error.message : 'Unknown error'}`);
220
+ return false;
221
+ }
222
+ }
223
+ async getLastCheckpointId(sessionId) {
224
+ const lastCheckpointData = await this.getLastCheckpointData(sessionId);
225
+ return lastCheckpointData.id || null;
226
+ }
227
+ countLayers(classified, layerType) {
228
+ if (!classified || typeof classified !== 'object') {
229
+ return 0;
230
+ }
231
+ const layer = classified[layerType];
232
+ if (!layer || typeof layer !== 'object') {
233
+ return 0;
234
+ }
235
+ return Object.keys(layer).length;
236
+ }
237
+ async upsertSessionInfo(sessionId) {
238
+ try {
239
+ const sessionInfo = {
240
+ id: sessionId,
241
+ createdAt: new Date().toISOString(),
242
+ lastAccessedAt: new Date().toISOString(),
243
+ totalSizeBytes: 0
244
+ };
245
+ await this.storage.upsertSession(sessionInfo);
246
+ }
247
+ catch (error) {
248
+ console.warn(`Failed to update session info: ${error instanceof Error ? error.message : 'Unknown error'}`);
249
+ }
250
+ }
251
+ updateSaveMetrics(operationTime) {
252
+ this.metrics.totalSaveOperations++;
253
+ this.metrics.averageSaveTime = this.calculateMovingAverage(this.metrics.averageSaveTime, operationTime, this.metrics.totalSaveOperations);
254
+ this.metrics.lastOperationTime = operationTime;
255
+ }
256
+ updateLoadMetrics(startTime) {
257
+ const endTime = process.hrtime.bigint();
258
+ const operationTime = Number(endTime - startTime) / 1000000;
259
+ this.metrics.totalLoadOperations++;
260
+ this.metrics.averageLoadTime = this.calculateMovingAverage(this.metrics.averageLoadTime, operationTime, this.metrics.totalLoadOperations);
261
+ this.metrics.lastOperationTime = operationTime;
262
+ }
263
+ updateListMetrics(startTime) {
264
+ const endTime = process.hrtime.bigint();
265
+ const operationTime = Number(endTime - startTime) / 1000000;
266
+ this.metrics.totalListOperations++;
267
+ this.metrics.lastOperationTime = operationTime;
268
+ }
269
+ updateMarkCriticalMetrics(startTime) {
270
+ const endTime = process.hrtime.bigint();
271
+ const operationTime = Number(endTime - startTime) / 1000000;
272
+ this.metrics.totalMarkCriticalOperations++;
273
+ this.metrics.lastOperationTime = operationTime;
274
+ }
275
+ calculateMovingAverage(currentAverage, newValue, count) {
276
+ return ((currentAverage * (count - 1)) + newValue) / count;
277
+ }
278
+ hashContext(context) {
279
+ const contextString = JSON.stringify(context, Object.keys(context).sort());
280
+ return crypto.createHash('sha256').update(contextString).digest('hex');
281
+ }
282
+ async getLastCheckpointData(sessionId) {
283
+ try {
284
+ const checkpoints = await this.storage.listCheckpoints(sessionId, 1, 0);
285
+ if (!checkpoints || checkpoints.length === 0) {
286
+ return { id: undefined, contextSizeBytes: undefined, contextHash: undefined };
287
+ }
288
+ const checkpoint = checkpoints[0];
289
+ return {
290
+ id: checkpoint.id,
291
+ contextSizeBytes: checkpoint.contextSizeBytes,
292
+ contextHash: checkpoint.contextHash
293
+ };
294
+ }
295
+ catch (error) {
296
+ console.warn(`Failed to get last checkpoint data for session ${sessionId}: ${error instanceof Error ? error.message : 'Unknown error'}`);
297
+ return { id: undefined, contextSizeBytes: undefined, contextHash: undefined };
298
+ }
299
+ }
300
+ }
301
+ exports.ContextManagementService = ContextManagementService;
@@ -0,0 +1,45 @@
1
+ import { IContextPersistenceService, IClassificationEngine, ICompressionService, RawContext, ClassifiedContext, PersistableContext, CompressedBlob, CompressionStats } from '../../types/context-types';
2
+ interface PersistenceMetrics {
3
+ totalOperations: number;
4
+ averageClassificationTime: number;
5
+ averageCompressionTime: number;
6
+ averageTotalTime: number;
7
+ lastOperationTime: number;
8
+ compressionStats: CompressionStats;
9
+ }
10
+ export declare class ContextPersistenceService implements IContextPersistenceService {
11
+ private readonly classificationEngine;
12
+ private readonly compressionService;
13
+ private metrics;
14
+ constructor(classificationEngine: IClassificationEngine, compressionService: ICompressionService);
15
+ classifyContext(context: RawContext): Promise<ClassifiedContext>;
16
+ compressContext(classified: ClassifiedContext): Promise<CompressedBlob>;
17
+ decompressContext(compressed: CompressedBlob): Promise<RawContext>;
18
+ generateSessionId(workflowId: string, context: RawContext): string;
19
+ processPersistencePipeline(context: RawContext, workflowId: string): Promise<{
20
+ sessionId: string;
21
+ classified: ClassifiedContext;
22
+ compressed: CompressedBlob;
23
+ metrics: {
24
+ classificationTime: number;
25
+ compressionTime: number;
26
+ totalTime: number;
27
+ };
28
+ }>;
29
+ processRestorationPipeline(compressed: CompressedBlob): Promise<{
30
+ context: RawContext;
31
+ metrics: {
32
+ decompressionTime: number;
33
+ };
34
+ }>;
35
+ getMetrics(): PersistenceMetrics;
36
+ resetMetrics(): void;
37
+ restoreFromPersistence(persistableContext: PersistableContext): Promise<RawContext>;
38
+ private createFallbackClassification;
39
+ private createUncompressedBlob;
40
+ private generateFallbackSessionId;
41
+ private updateClassificationMetrics;
42
+ private updateCompressionMetrics;
43
+ private updatePipelineMetrics;
44
+ }
45
+ export {};
@@ -0,0 +1,273 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ContextPersistenceService = void 0;
37
+ const crypto = __importStar(require("crypto"));
38
+ const context_types_1 = require("../../types/context-types");
39
+ const SESSION_ID_CONFIG = {
40
+ algorithm: 'sha256',
41
+ encoding: 'hex',
42
+ maxLength: 32
43
+ };
44
+ class ContextPersistenceService {
45
+ constructor(classificationEngine, compressionService) {
46
+ this.classificationEngine = classificationEngine;
47
+ this.compressionService = compressionService;
48
+ this.metrics = {
49
+ totalOperations: 0,
50
+ averageClassificationTime: 0,
51
+ averageCompressionTime: 0,
52
+ averageTotalTime: 0,
53
+ lastOperationTime: 0,
54
+ compressionStats: {
55
+ totalOperations: 0,
56
+ averageRatio: 1.0,
57
+ totalSizeReduction: 0,
58
+ averageCompressionTime: 0
59
+ }
60
+ };
61
+ }
62
+ async classifyContext(context) {
63
+ const startTime = process.hrtime.bigint();
64
+ try {
65
+ const frozenContext = Object.freeze({ ...context });
66
+ const classified = await this.classificationEngine.classify(frozenContext);
67
+ const immutableClassified = {
68
+ [context_types_1.ContextLayer.CRITICAL]: Object.freeze({ ...classified[context_types_1.ContextLayer.CRITICAL] }),
69
+ [context_types_1.ContextLayer.IMPORTANT]: Object.freeze({ ...classified[context_types_1.ContextLayer.IMPORTANT] }),
70
+ [context_types_1.ContextLayer.USEFUL]: Object.freeze({ ...classified[context_types_1.ContextLayer.USEFUL] }),
71
+ [context_types_1.ContextLayer.EPHEMERAL]: Object.freeze({ ...classified[context_types_1.ContextLayer.EPHEMERAL] })
72
+ };
73
+ const endTime = process.hrtime.bigint();
74
+ const classificationTime = Number(endTime - startTime) / 1000000;
75
+ this.updateClassificationMetrics(classificationTime);
76
+ return Object.freeze(immutableClassified);
77
+ }
78
+ catch (error) {
79
+ console.error('Context classification failed:', error);
80
+ return this.createFallbackClassification(context);
81
+ }
82
+ }
83
+ async compressContext(classified) {
84
+ const startTime = process.hrtime.bigint();
85
+ try {
86
+ const frozenClassified = Object.freeze({ ...classified });
87
+ const compressed = await this.compressionService.compress(frozenClassified);
88
+ const endTime = process.hrtime.bigint();
89
+ const compressionTime = Number(endTime - startTime) / 1000000;
90
+ this.updateCompressionMetrics(compressionTime);
91
+ return compressed;
92
+ }
93
+ catch (error) {
94
+ console.error('Context compression failed:', error);
95
+ return this.createUncompressedBlob(classified);
96
+ }
97
+ }
98
+ async decompressContext(compressed) {
99
+ try {
100
+ const decompressed = await this.compressionService.decompress(compressed);
101
+ return Object.freeze({ ...decompressed });
102
+ }
103
+ catch (error) {
104
+ console.error('Context decompression failed:', error);
105
+ throw new Error(`Failed to decompress context: ${error instanceof Error ? error.message : String(error)}`);
106
+ }
107
+ }
108
+ generateSessionId(workflowId, context) {
109
+ try {
110
+ const contextString = JSON.stringify(context, Object.keys(context).sort());
111
+ const contextHash = crypto
112
+ .createHash(SESSION_ID_CONFIG.algorithm)
113
+ .update(contextString)
114
+ .digest(SESSION_ID_CONFIG.encoding);
115
+ const combinedInput = `${workflowId}:${contextHash}`;
116
+ const sessionHash = crypto
117
+ .createHash(SESSION_ID_CONFIG.algorithm)
118
+ .update(combinedInput)
119
+ .digest(SESSION_ID_CONFIG.encoding);
120
+ const sessionId = sessionHash.substring(0, SESSION_ID_CONFIG.maxLength);
121
+ if (!/^[a-zA-Z0-9-]+$/.test(sessionId)) {
122
+ throw new Error('Generated session ID contains invalid characters');
123
+ }
124
+ return sessionId;
125
+ }
126
+ catch (error) {
127
+ console.warn('Session ID generation failed, using fallback:', error);
128
+ return this.generateFallbackSessionId(workflowId);
129
+ }
130
+ }
131
+ async processPersistencePipeline(context, workflowId) {
132
+ const pipelineStartTime = process.hrtime.bigint();
133
+ try {
134
+ const sessionId = this.generateSessionId(workflowId, context);
135
+ const classificationStart = process.hrtime.bigint();
136
+ const classified = await this.classifyContext(context);
137
+ const classificationEnd = process.hrtime.bigint();
138
+ const classificationTime = Number(classificationEnd - classificationStart) / 1000000;
139
+ const compressionStart = process.hrtime.bigint();
140
+ const compressed = await this.compressContext(classified);
141
+ const compressionEnd = process.hrtime.bigint();
142
+ const compressionTime = Number(compressionEnd - compressionStart) / 1000000;
143
+ const pipelineEndTime = process.hrtime.bigint();
144
+ const totalTime = Number(pipelineEndTime - pipelineStartTime) / 1000000;
145
+ this.updatePipelineMetrics(totalTime);
146
+ return {
147
+ sessionId,
148
+ classified: Object.freeze(classified),
149
+ compressed,
150
+ metrics: {
151
+ classificationTime,
152
+ compressionTime,
153
+ totalTime
154
+ }
155
+ };
156
+ }
157
+ catch (error) {
158
+ console.error('Persistence pipeline failed:', error);
159
+ throw new Error(`Persistence pipeline error: ${error instanceof Error ? error.message : String(error)}`);
160
+ }
161
+ }
162
+ async processRestorationPipeline(compressed) {
163
+ const startTime = process.hrtime.bigint();
164
+ try {
165
+ const context = await this.decompressContext(compressed);
166
+ const endTime = process.hrtime.bigint();
167
+ const decompressionTime = Number(endTime - startTime) / 1000000;
168
+ return {
169
+ context: Object.freeze(context),
170
+ metrics: {
171
+ decompressionTime
172
+ }
173
+ };
174
+ }
175
+ catch (error) {
176
+ console.error('Restoration pipeline failed:', error);
177
+ throw new Error(`Restoration pipeline error: ${error instanceof Error ? error.message : String(error)}`);
178
+ }
179
+ }
180
+ getMetrics() {
181
+ const latestCompressionStats = this.compressionService.getStats();
182
+ return {
183
+ ...this.metrics,
184
+ compressionStats: { ...latestCompressionStats }
185
+ };
186
+ }
187
+ resetMetrics() {
188
+ this.metrics = {
189
+ totalOperations: 0,
190
+ averageClassificationTime: 0,
191
+ averageCompressionTime: 0,
192
+ averageTotalTime: 0,
193
+ lastOperationTime: 0,
194
+ compressionStats: {
195
+ totalOperations: 0,
196
+ averageRatio: 1.0,
197
+ totalSizeReduction: 0,
198
+ averageCompressionTime: 0
199
+ }
200
+ };
201
+ this.compressionService.resetStats?.();
202
+ }
203
+ async restoreFromPersistence(persistableContext) {
204
+ const startTime = process.hrtime.bigint();
205
+ try {
206
+ const frozenPersistable = Object.freeze({ ...persistableContext });
207
+ const restoredContext = await this.compressionService.decompress(frozenPersistable);
208
+ const endTime = process.hrtime.bigint();
209
+ const operationTime = Number(endTime - startTime) / 1000000;
210
+ this.metrics.totalOperations++;
211
+ this.metrics.lastOperationTime = operationTime;
212
+ return Object.freeze({ ...restoredContext });
213
+ }
214
+ catch (error) {
215
+ console.warn('Context restoration failed, attempting graceful fallback:', error);
216
+ const fallbackContext = {
217
+ restorationError: true,
218
+ originalError: error instanceof Error ? error.message : 'Unknown error',
219
+ fallbackData: persistableContext
220
+ };
221
+ return Object.freeze(fallbackContext);
222
+ }
223
+ }
224
+ createFallbackClassification(context) {
225
+ const safeContext = { ...context };
226
+ return Object.freeze({
227
+ [context_types_1.ContextLayer.CRITICAL]: {},
228
+ [context_types_1.ContextLayer.IMPORTANT]: Object.freeze(safeContext),
229
+ [context_types_1.ContextLayer.USEFUL]: {},
230
+ [context_types_1.ContextLayer.EPHEMERAL]: {}
231
+ });
232
+ }
233
+ async createUncompressedBlob(classified) {
234
+ const flattened = {};
235
+ for (const [layer, data] of Object.entries(classified)) {
236
+ Object.assign(flattened, data);
237
+ }
238
+ const serialized = JSON.stringify(flattened);
239
+ const data = Buffer.from(serialized, 'utf8');
240
+ const size = data.length;
241
+ return {
242
+ data,
243
+ originalSize: size,
244
+ compressedSize: size,
245
+ compressionRatio: 1.0,
246
+ algorithm: 'none'
247
+ };
248
+ }
249
+ generateFallbackSessionId(workflowId) {
250
+ const timestamp = Date.now().toString(36);
251
+ const randomSuffix = Math.random().toString(36).substring(2, 8);
252
+ const fallbackId = `${workflowId}-${timestamp}-${randomSuffix}`;
253
+ return fallbackId.substring(0, SESSION_ID_CONFIG.maxLength);
254
+ }
255
+ updateClassificationMetrics(classificationTime) {
256
+ const prevOps = this.metrics.totalOperations;
257
+ this.metrics.totalOperations += 1;
258
+ this.metrics.averageClassificationTime =
259
+ (this.metrics.averageClassificationTime * prevOps + classificationTime) / this.metrics.totalOperations;
260
+ this.metrics.lastOperationTime = Date.now();
261
+ }
262
+ updateCompressionMetrics(compressionTime) {
263
+ const prevOps = this.metrics.totalOperations || 1;
264
+ this.metrics.averageCompressionTime =
265
+ (this.metrics.averageCompressionTime * (prevOps - 1) + compressionTime) / prevOps;
266
+ }
267
+ updatePipelineMetrics(totalTime) {
268
+ const prevOps = this.metrics.totalOperations || 1;
269
+ this.metrics.averageTotalTime =
270
+ (this.metrics.averageTotalTime * (prevOps - 1) + totalTime) / prevOps;
271
+ }
272
+ }
273
+ exports.ContextPersistenceService = ContextPersistenceService;
@@ -11,6 +11,7 @@ const fs_1 = __importDefault(require("fs"));
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const validation_1 = require("../application/validation");
13
13
  const chalk_1 = __importDefault(require("chalk"));
14
+ const semver_1 = __importDefault(require("semver"));
14
15
  function detectWorkflowVersion(workflow) {
15
16
  if (workflow.version) {
16
17
  return workflow.version;
@@ -29,13 +30,13 @@ function migrateWorkflow(workflow) {
29
30
  warnings: [],
30
31
  errors: []
31
32
  };
32
- if (result.originalVersion === result.targetVersion) {
33
+ if (semver_1.default.eq(result.originalVersion, result.targetVersion)) {
33
34
  result.success = true;
34
35
  result.warnings.push(`Workflow is already at version ${result.targetVersion}`);
35
36
  result.migratedWorkflow = workflow;
36
37
  return result;
37
38
  }
38
- if (result.originalVersion > result.targetVersion) {
39
+ if (semver_1.default.gt(result.originalVersion, result.targetVersion)) {
39
40
  result.errors.push(`Cannot downgrade from version ${result.originalVersion} to ${result.targetVersion}`);
40
41
  return result;
41
42
  }