@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.
- package/README.md +153 -189
- package/dist/application/services/classification-engine.d.ts +33 -0
- package/dist/application/services/classification-engine.js +258 -0
- package/dist/application/services/compression-service.d.ts +20 -0
- package/dist/application/services/compression-service.js +312 -0
- package/dist/application/services/context-management-service.d.ts +38 -0
- package/dist/application/services/context-management-service.js +301 -0
- package/dist/application/services/context-persistence-service.d.ts +45 -0
- package/dist/application/services/context-persistence-service.js +273 -0
- package/dist/cli/migrate-workflow.js +3 -2
- package/dist/infrastructure/storage/context-storage.d.ts +150 -0
- package/dist/infrastructure/storage/context-storage.js +40 -0
- package/dist/infrastructure/storage/filesystem-blob-storage.d.ts +27 -0
- package/dist/infrastructure/storage/filesystem-blob-storage.js +363 -0
- package/dist/infrastructure/storage/hybrid-context-storage.d.ts +29 -0
- package/dist/infrastructure/storage/hybrid-context-storage.js +400 -0
- package/dist/infrastructure/storage/migrations/001_initial_schema.sql +38 -0
- package/dist/infrastructure/storage/migrations/002_context_concurrency_enhancements.sql +234 -0
- package/dist/infrastructure/storage/migrations/003_classification_overrides.sql +20 -0
- package/dist/infrastructure/storage/sqlite-metadata-storage.d.ts +35 -0
- package/dist/infrastructure/storage/sqlite-metadata-storage.js +410 -0
- package/dist/infrastructure/storage/sqlite-migrator.d.ts +46 -0
- package/dist/infrastructure/storage/sqlite-migrator.js +293 -0
- package/dist/types/context-types.d.ts +236 -0
- package/dist/types/context-types.js +10 -0
- package/dist/utils/storage-security.js +1 -1
- package/package.json +4 -1
- package/workflows/coding-task-workflow-with-loops.json +434 -0
- package/workflows/mr-review-workflow.json +75 -26
- package/workflows/systemic-bug-investigation-with-loops.json +423 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SqliteMigrator = void 0;
|
|
7
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
class SqliteMigrator {
|
|
12
|
+
constructor(databasePath, migrationsDir) {
|
|
13
|
+
this.maxRetries = 3;
|
|
14
|
+
this.lockTimeout = 10000;
|
|
15
|
+
this.db = new better_sqlite3_1.default(databasePath, {
|
|
16
|
+
verbose: undefined,
|
|
17
|
+
fileMustExist: false,
|
|
18
|
+
timeout: this.lockTimeout
|
|
19
|
+
});
|
|
20
|
+
this.db.pragma('journal_mode = WAL');
|
|
21
|
+
this.db.pragma('synchronous = NORMAL');
|
|
22
|
+
this.db.pragma('cache_size = 1000');
|
|
23
|
+
this.db.pragma('temp_store = memory');
|
|
24
|
+
this.db.pragma('foreign_keys = ON');
|
|
25
|
+
this.migrationsDir = migrationsDir || path_1.default.join(__dirname, 'migrations');
|
|
26
|
+
}
|
|
27
|
+
async initialize() {
|
|
28
|
+
try {
|
|
29
|
+
this.db.exec(`
|
|
30
|
+
CREATE TABLE IF NOT EXISTS schema_version (
|
|
31
|
+
version INTEGER PRIMARY KEY,
|
|
32
|
+
applied_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
33
|
+
description TEXT NOT NULL,
|
|
34
|
+
checksum TEXT NOT NULL,
|
|
35
|
+
migration_duration_ms INTEGER DEFAULT NULL
|
|
36
|
+
);
|
|
37
|
+
`);
|
|
38
|
+
this.db.exec(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS migration_locks (
|
|
40
|
+
id TEXT PRIMARY KEY DEFAULT 'migration_lock',
|
|
41
|
+
locked_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
42
|
+
locked_by TEXT NOT NULL,
|
|
43
|
+
expires_at DATETIME NOT NULL,
|
|
44
|
+
CHECK (id = 'migration_lock')
|
|
45
|
+
);
|
|
46
|
+
`);
|
|
47
|
+
console.log('✅ Migration system initialized');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
throw new Error(`Failed to initialize migration system: ${error}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
getCurrentVersion() {
|
|
54
|
+
try {
|
|
55
|
+
const result = this.db
|
|
56
|
+
.prepare('SELECT MAX(version) as version FROM schema_version')
|
|
57
|
+
.get();
|
|
58
|
+
return result?.version ?? 0;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
loadAvailableMigrations() {
|
|
65
|
+
try {
|
|
66
|
+
if (!fs_1.default.existsSync(this.migrationsDir)) {
|
|
67
|
+
console.warn(`Migrations directory not found: ${this.migrationsDir}`);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const files = fs_1.default.readdirSync(this.migrationsDir)
|
|
71
|
+
.filter(file => file.endsWith('.sql'))
|
|
72
|
+
.sort();
|
|
73
|
+
const migrations = [];
|
|
74
|
+
for (const filename of files) {
|
|
75
|
+
const match = filename.match(/^(\d+)_(.+)\.sql$/);
|
|
76
|
+
if (!match) {
|
|
77
|
+
console.warn(`Skipping invalid migration filename: ${filename}`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const version = parseInt(match[1], 10);
|
|
81
|
+
const description = match[2].replace(/[_-]/g, ' ');
|
|
82
|
+
const filepath = path_1.default.join(this.migrationsDir, filename);
|
|
83
|
+
const sql = fs_1.default.readFileSync(filepath, 'utf-8');
|
|
84
|
+
const checksum = this.calculateChecksum(sql);
|
|
85
|
+
migrations.push({
|
|
86
|
+
version,
|
|
87
|
+
filename,
|
|
88
|
+
description,
|
|
89
|
+
sql,
|
|
90
|
+
checksum
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return migrations.sort((a, b) => a.version - b.version);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw new Error(`Failed to load migrations: ${error}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
getMigrationStatus() {
|
|
100
|
+
const currentVersion = this.getCurrentVersion();
|
|
101
|
+
const availableMigrations = this.loadAvailableMigrations();
|
|
102
|
+
const pendingMigrations = availableMigrations.filter(m => m.version > currentVersion);
|
|
103
|
+
const targetVersion = Math.max(...availableMigrations.map(m => m.version), currentVersion);
|
|
104
|
+
const appliedMigrations = this.db
|
|
105
|
+
.prepare('SELECT version, description, applied_at, checksum FROM schema_version ORDER BY version')
|
|
106
|
+
.all();
|
|
107
|
+
return {
|
|
108
|
+
currentVersion,
|
|
109
|
+
targetVersion,
|
|
110
|
+
pendingMigrations,
|
|
111
|
+
appliedMigrations
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async migrate() {
|
|
115
|
+
const results = [];
|
|
116
|
+
const status = this.getMigrationStatus();
|
|
117
|
+
if (status.pendingMigrations.length === 0) {
|
|
118
|
+
console.log('📊 Database is up to date');
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
console.log(`📊 Applying ${status.pendingMigrations.length} pending migrations...`);
|
|
122
|
+
for (const migration of status.pendingMigrations) {
|
|
123
|
+
const result = await this.applyMigration(migration);
|
|
124
|
+
results.push(result);
|
|
125
|
+
if (!result.success) {
|
|
126
|
+
console.error(`❌ Migration failed at version ${migration.version}, stopping`);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return results;
|
|
131
|
+
}
|
|
132
|
+
async applyMigration(migration) {
|
|
133
|
+
const startTime = Date.now();
|
|
134
|
+
let lockId = null;
|
|
135
|
+
try {
|
|
136
|
+
lockId = await this.acquireMigrationLock();
|
|
137
|
+
const currentVersion = this.getCurrentVersion();
|
|
138
|
+
if (migration.version <= currentVersion) {
|
|
139
|
+
await this.releaseMigrationLock(lockId);
|
|
140
|
+
return {
|
|
141
|
+
success: true,
|
|
142
|
+
appliedVersion: migration.version,
|
|
143
|
+
duration: Date.now() - startTime
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
await this.validateMigrationChecksum(migration);
|
|
147
|
+
console.log(`📦 Applying migration ${migration.version}: ${migration.description}`);
|
|
148
|
+
const transaction = this.db.transaction(() => {
|
|
149
|
+
this.db.exec(migration.sql);
|
|
150
|
+
this.db
|
|
151
|
+
.prepare(`
|
|
152
|
+
INSERT INTO schema_version (version, description, checksum, migration_duration_ms)
|
|
153
|
+
VALUES (?, ?, ?, ?)
|
|
154
|
+
`)
|
|
155
|
+
.run(migration.version, migration.description, migration.checksum, Date.now() - startTime);
|
|
156
|
+
});
|
|
157
|
+
transaction();
|
|
158
|
+
const duration = Date.now() - startTime;
|
|
159
|
+
console.log(`✅ Migration ${migration.version} completed in ${duration}ms`);
|
|
160
|
+
await this.releaseMigrationLock(lockId);
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
appliedVersion: migration.version,
|
|
164
|
+
duration
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const duration = Date.now() - startTime;
|
|
169
|
+
console.error(`❌ Migration ${migration.version} failed:`, error);
|
|
170
|
+
if (lockId) {
|
|
171
|
+
try {
|
|
172
|
+
await this.releaseMigrationLock(lockId);
|
|
173
|
+
}
|
|
174
|
+
catch (lockError) {
|
|
175
|
+
console.error('Failed to release migration lock:', lockError);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: error instanceof Error ? error.message : String(error),
|
|
181
|
+
duration
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async acquireMigrationLock() {
|
|
186
|
+
const lockId = crypto_1.default.randomUUID();
|
|
187
|
+
const expiresAt = new Date(Date.now() + this.lockTimeout);
|
|
188
|
+
let attempts = 0;
|
|
189
|
+
while (attempts < this.maxRetries) {
|
|
190
|
+
try {
|
|
191
|
+
this.db
|
|
192
|
+
.prepare('DELETE FROM migration_locks WHERE expires_at < CURRENT_TIMESTAMP')
|
|
193
|
+
.run();
|
|
194
|
+
this.db
|
|
195
|
+
.prepare(`
|
|
196
|
+
INSERT INTO migration_locks (locked_by, expires_at)
|
|
197
|
+
VALUES (?, ?)
|
|
198
|
+
`)
|
|
199
|
+
.run(lockId, expiresAt.toISOString());
|
|
200
|
+
return lockId;
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
attempts++;
|
|
204
|
+
if (attempts >= this.maxRetries) {
|
|
205
|
+
throw new Error(`Failed to acquire migration lock after ${this.maxRetries} attempts`);
|
|
206
|
+
}
|
|
207
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
throw new Error('Unable to acquire migration lock');
|
|
211
|
+
}
|
|
212
|
+
async releaseMigrationLock(lockId) {
|
|
213
|
+
try {
|
|
214
|
+
this.db
|
|
215
|
+
.prepare('DELETE FROM migration_locks WHERE locked_by = ?')
|
|
216
|
+
.run(lockId);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
console.warn(`Failed to release migration lock ${lockId}:`, error);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async validateMigrationChecksum(migration) {
|
|
223
|
+
try {
|
|
224
|
+
const existingMigration = this.db
|
|
225
|
+
.prepare('SELECT checksum FROM schema_version WHERE version = ?')
|
|
226
|
+
.get(migration.version);
|
|
227
|
+
if (existingMigration && existingMigration.checksum !== migration.checksum) {
|
|
228
|
+
throw new Error(`Migration ${migration.version} checksum mismatch. ` +
|
|
229
|
+
`Expected: ${existingMigration.checksum}, Got: ${migration.checksum}. ` +
|
|
230
|
+
`Migration file may have been modified after being applied.`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (error instanceof Error && error.message.includes('checksum mismatch')) {
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
calculateChecksum(content) {
|
|
240
|
+
return crypto_1.default
|
|
241
|
+
.createHash('sha256')
|
|
242
|
+
.update(content.trim())
|
|
243
|
+
.digest('hex');
|
|
244
|
+
}
|
|
245
|
+
async validateIntegrity() {
|
|
246
|
+
try {
|
|
247
|
+
const result = this.db.prepare('PRAGMA integrity_check').get();
|
|
248
|
+
if (result.integrity_check !== 'ok') {
|
|
249
|
+
console.error('❌ Database integrity check failed:', result.integrity_check);
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
const fkCheck = this.db.prepare('PRAGMA foreign_key_check').all();
|
|
253
|
+
if (fkCheck.length > 0) {
|
|
254
|
+
console.error('❌ Foreign key constraints violated:', fkCheck);
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
console.log('✅ Database integrity validated');
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
console.error('❌ Failed to validate database integrity:', error);
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
close() {
|
|
266
|
+
try {
|
|
267
|
+
this.db.close();
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
console.warn('Warning during database close:', error);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
getStats() {
|
|
274
|
+
try {
|
|
275
|
+
const stats = this.db.prepare('PRAGMA database_list').all();
|
|
276
|
+
const pageCount = this.db.prepare('PRAGMA page_count').get();
|
|
277
|
+
const pageSize = this.db.prepare('PRAGMA page_size').get();
|
|
278
|
+
const walMode = this.db.prepare('PRAGMA journal_mode').get();
|
|
279
|
+
return {
|
|
280
|
+
databases: stats,
|
|
281
|
+
totalPages: pageCount.page_count,
|
|
282
|
+
pageSize: pageSize.page_size,
|
|
283
|
+
estimatedSize: pageCount.page_count * pageSize.page_size,
|
|
284
|
+
journalMode: walMode.journal_mode,
|
|
285
|
+
currentVersion: this.getCurrentVersion()
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
exports.SqliteMigrator = SqliteMigrator;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
export declare enum ContextLayer {
|
|
2
|
+
CRITICAL = "CRITICAL",
|
|
3
|
+
IMPORTANT = "IMPORTANT",
|
|
4
|
+
USEFUL = "USEFUL",
|
|
5
|
+
EPHEMERAL = "EPHEMERAL"
|
|
6
|
+
}
|
|
7
|
+
export interface ClassifiedContext {
|
|
8
|
+
[ContextLayer.CRITICAL]: Record<string, any>;
|
|
9
|
+
[ContextLayer.IMPORTANT]: Record<string, any>;
|
|
10
|
+
[ContextLayer.USEFUL]: Record<string, any>;
|
|
11
|
+
[ContextLayer.EPHEMERAL]: Record<string, any>;
|
|
12
|
+
}
|
|
13
|
+
export interface RawContext {
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
export interface PersistableContext extends Record<string, any> {
|
|
17
|
+
readonly _contextSize?: number;
|
|
18
|
+
readonly _timestamp?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CheckpointMetadata {
|
|
21
|
+
id: string;
|
|
22
|
+
sessionId: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
agentId?: string;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
tags?: string[];
|
|
27
|
+
contextSizeBytes: number;
|
|
28
|
+
contextHash: string;
|
|
29
|
+
blobPath: string;
|
|
30
|
+
classificationSummary?: ClassificationSummary;
|
|
31
|
+
status: 'active' | 'archived' | 'corrupt';
|
|
32
|
+
}
|
|
33
|
+
export interface ClassificationSummary {
|
|
34
|
+
criticalCount: number;
|
|
35
|
+
importantCount: number;
|
|
36
|
+
usefulCount: number;
|
|
37
|
+
ephemeralCount: number;
|
|
38
|
+
}
|
|
39
|
+
export interface SessionInfo {
|
|
40
|
+
id: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
lastAccessedAt: string;
|
|
43
|
+
workflowId?: string;
|
|
44
|
+
tags?: string[];
|
|
45
|
+
totalSizeBytes: number;
|
|
46
|
+
}
|
|
47
|
+
export interface CheckpointData {
|
|
48
|
+
metadata: CheckpointMetadata;
|
|
49
|
+
context: RawContext;
|
|
50
|
+
}
|
|
51
|
+
export interface CompressedBlob {
|
|
52
|
+
data: Buffer;
|
|
53
|
+
originalSize: number;
|
|
54
|
+
compressedSize: number;
|
|
55
|
+
compressionRatio: number;
|
|
56
|
+
algorithm: 'gzip' | 'deflate' | 'none';
|
|
57
|
+
}
|
|
58
|
+
export interface BlobMetadata {
|
|
59
|
+
checkpointId: string;
|
|
60
|
+
sessionId: string;
|
|
61
|
+
path: string;
|
|
62
|
+
sizeBytes: number;
|
|
63
|
+
hash: string;
|
|
64
|
+
encrypted: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface ClassificationRules {
|
|
67
|
+
patterns: {
|
|
68
|
+
[K in ContextLayer]: ClassificationPattern[];
|
|
69
|
+
};
|
|
70
|
+
heuristics: ClassificationHeuristics;
|
|
71
|
+
overrides: Record<string, ContextLayer>;
|
|
72
|
+
}
|
|
73
|
+
export interface ClassificationPattern {
|
|
74
|
+
keyPattern: string;
|
|
75
|
+
valuePattern?: string;
|
|
76
|
+
weight: number;
|
|
77
|
+
description: string;
|
|
78
|
+
}
|
|
79
|
+
export interface ClassificationHeuristics {
|
|
80
|
+
lengthThresholds: {
|
|
81
|
+
[K in ContextLayer]: number;
|
|
82
|
+
};
|
|
83
|
+
keywordWeights: Record<string, number>;
|
|
84
|
+
defaultLayer: ContextLayer;
|
|
85
|
+
}
|
|
86
|
+
export interface ContextConfig {
|
|
87
|
+
storage: StorageConfig;
|
|
88
|
+
classification: ClassificationRules;
|
|
89
|
+
compression: CompressionConfig;
|
|
90
|
+
encryption: EncryptionConfig;
|
|
91
|
+
quotas: QuotaConfig;
|
|
92
|
+
}
|
|
93
|
+
export interface StorageConfig {
|
|
94
|
+
dataDir: string;
|
|
95
|
+
maxCheckpoints: number;
|
|
96
|
+
maxSessionSize: number;
|
|
97
|
+
maxTotalSize: number;
|
|
98
|
+
cleanupInterval: number;
|
|
99
|
+
}
|
|
100
|
+
export interface CompressionConfig {
|
|
101
|
+
enabled: boolean;
|
|
102
|
+
algorithm: 'gzip' | 'deflate';
|
|
103
|
+
level: number;
|
|
104
|
+
layerSettings: {
|
|
105
|
+
[K in ContextLayer]: {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
aggressiveness: 'none' | 'light' | 'medium' | 'aggressive';
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export interface EncryptionConfig {
|
|
112
|
+
enabled: boolean;
|
|
113
|
+
algorithm: 'aes-256-gcm';
|
|
114
|
+
keySource: 'os-keychain' | 'env' | 'file';
|
|
115
|
+
}
|
|
116
|
+
export interface QuotaConfig {
|
|
117
|
+
maxCheckpointsPerSession: number;
|
|
118
|
+
maxContextSizePerCheckpoint: number;
|
|
119
|
+
maxTotalStoragePerSession: number;
|
|
120
|
+
maxGlobalStorage: number;
|
|
121
|
+
warningThreshold: number;
|
|
122
|
+
cleanupThreshold: number;
|
|
123
|
+
}
|
|
124
|
+
export interface IContextManagementService {
|
|
125
|
+
saveCheckpoint(params: SaveCheckpointParams): Promise<SaveCheckpointResult>;
|
|
126
|
+
loadCheckpoint(params: LoadCheckpointParams): Promise<LoadCheckpointResult>;
|
|
127
|
+
listCheckpoints(params: ListCheckpointsParams): Promise<CheckpointMetadata[]>;
|
|
128
|
+
markCritical(params: MarkCriticalParams): Promise<MarkCriticalResult>;
|
|
129
|
+
}
|
|
130
|
+
export interface IContextPersistenceService {
|
|
131
|
+
processPersistencePipeline(context: RawContext, workflowId: string): Promise<PersistableContext>;
|
|
132
|
+
restoreFromPersistence(persistableContext: PersistableContext): Promise<RawContext>;
|
|
133
|
+
classifyContext(context: RawContext): Promise<ClassifiedContext>;
|
|
134
|
+
getMetrics(): any;
|
|
135
|
+
resetMetrics(): void;
|
|
136
|
+
}
|
|
137
|
+
export interface IClassificationEngine {
|
|
138
|
+
classify(context: RawContext): Promise<ClassifiedContext>;
|
|
139
|
+
markCritical(sessionId: string, contextKey: string): Promise<void>;
|
|
140
|
+
loadRules(config?: Partial<ClassificationRules>): Promise<void>;
|
|
141
|
+
}
|
|
142
|
+
export interface ICompressionService {
|
|
143
|
+
compress(classified: ClassifiedContext): Promise<CompressedBlob>;
|
|
144
|
+
decompress(blob: CompressedBlob): Promise<RawContext>;
|
|
145
|
+
getStats(): CompressionStats;
|
|
146
|
+
}
|
|
147
|
+
export interface IContextStorage {
|
|
148
|
+
saveCheckpoint(persistableContext: PersistableContext, metadata: CheckpointMetadata): Promise<void>;
|
|
149
|
+
loadCheckpoint(checkpointId: string): Promise<{
|
|
150
|
+
persistableContext: PersistableContext;
|
|
151
|
+
}>;
|
|
152
|
+
getCheckpoint(checkpointId: string): Promise<CheckpointMetadata | null>;
|
|
153
|
+
listCheckpoints(params: {
|
|
154
|
+
sessionId: string;
|
|
155
|
+
limit?: number;
|
|
156
|
+
offset?: number;
|
|
157
|
+
tags?: string[];
|
|
158
|
+
}): Promise<CheckpointMetadata[]>;
|
|
159
|
+
deleteCheckpoint(checkpointId: string): Promise<void>;
|
|
160
|
+
getSession(sessionId: string): Promise<SessionInfo | null>;
|
|
161
|
+
upsertSession(session: SessionInfo): Promise<void>;
|
|
162
|
+
}
|
|
163
|
+
export interface SaveCheckpointParams {
|
|
164
|
+
sessionId?: string;
|
|
165
|
+
context: RawContext;
|
|
166
|
+
metadata?: {
|
|
167
|
+
name?: string;
|
|
168
|
+
tags?: string[];
|
|
169
|
+
};
|
|
170
|
+
force?: boolean;
|
|
171
|
+
}
|
|
172
|
+
export interface SaveCheckpointResult {
|
|
173
|
+
checkpointId: string;
|
|
174
|
+
sessionId: string;
|
|
175
|
+
status: 'SAVED' | 'SKIPPED_UNCHANGED';
|
|
176
|
+
sizeBytes?: number;
|
|
177
|
+
}
|
|
178
|
+
export interface LoadCheckpointParams {
|
|
179
|
+
checkpointId?: string;
|
|
180
|
+
sessionId?: string;
|
|
181
|
+
}
|
|
182
|
+
export interface LoadCheckpointResult {
|
|
183
|
+
checkpointId: string;
|
|
184
|
+
sessionId: string;
|
|
185
|
+
context: RawContext;
|
|
186
|
+
metadata: CheckpointMetadata;
|
|
187
|
+
}
|
|
188
|
+
export interface ListCheckpointsParams {
|
|
189
|
+
sessionId: string;
|
|
190
|
+
limit?: number;
|
|
191
|
+
offset?: number;
|
|
192
|
+
tags?: string[];
|
|
193
|
+
}
|
|
194
|
+
export interface MarkCriticalParams {
|
|
195
|
+
sessionId: string;
|
|
196
|
+
contextKey: string;
|
|
197
|
+
}
|
|
198
|
+
export interface MarkCriticalResult {
|
|
199
|
+
status: 'SUCCESS' | 'KEY_NOT_FOUND';
|
|
200
|
+
message: string;
|
|
201
|
+
}
|
|
202
|
+
export interface CompressionStats {
|
|
203
|
+
totalOperations: number;
|
|
204
|
+
averageRatio: number;
|
|
205
|
+
totalSizeReduction: number;
|
|
206
|
+
averageCompressionTime: number;
|
|
207
|
+
}
|
|
208
|
+
export interface ContextMetrics {
|
|
209
|
+
saveOperations: OperationMetrics;
|
|
210
|
+
loadOperations: OperationMetrics;
|
|
211
|
+
classificationTime: OperationMetrics;
|
|
212
|
+
compressionTime: OperationMetrics;
|
|
213
|
+
}
|
|
214
|
+
export interface OperationMetrics {
|
|
215
|
+
count: number;
|
|
216
|
+
averageTime: number;
|
|
217
|
+
p50Time: number;
|
|
218
|
+
p95Time: number;
|
|
219
|
+
p99Time: number;
|
|
220
|
+
errorRate: number;
|
|
221
|
+
}
|
|
222
|
+
export interface SystemHealth {
|
|
223
|
+
status: 'healthy' | 'degraded' | 'unavailable';
|
|
224
|
+
storage: {
|
|
225
|
+
available: boolean;
|
|
226
|
+
usedSpace: number;
|
|
227
|
+
availableSpace: number;
|
|
228
|
+
quotaUsage: number;
|
|
229
|
+
};
|
|
230
|
+
performance: {
|
|
231
|
+
averageSaveTime: number;
|
|
232
|
+
averageLoadTime: number;
|
|
233
|
+
compressionRatio: number;
|
|
234
|
+
};
|
|
235
|
+
errors: string[];
|
|
236
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContextLayer = void 0;
|
|
4
|
+
var ContextLayer;
|
|
5
|
+
(function (ContextLayer) {
|
|
6
|
+
ContextLayer["CRITICAL"] = "CRITICAL";
|
|
7
|
+
ContextLayer["IMPORTANT"] = "IMPORTANT";
|
|
8
|
+
ContextLayer["USEFUL"] = "USEFUL";
|
|
9
|
+
ContextLayer["EPHEMERAL"] = "EPHEMERAL";
|
|
10
|
+
})(ContextLayer || (exports.ContextLayer = ContextLayer = {}));
|
|
@@ -50,7 +50,7 @@ function validateSecureUrl(url) {
|
|
|
50
50
|
hostname === '127.0.0.1' ||
|
|
51
51
|
hostname.startsWith('192.168.') ||
|
|
52
52
|
hostname.startsWith('10.') ||
|
|
53
|
-
|
|
53
|
+
/^172\.(1[6-9]|2[0-9]|3[01])\./.test(hostname)) {
|
|
54
54
|
throw new error_handler_1.SecurityError('Access to local/private networks not allowed', 'url-validation');
|
|
55
55
|
}
|
|
56
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exaudeus/workrail",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "MCP server for structured workflow orchestration and step-by-step task guidance",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc -p tsconfig.build.json",
|
|
16
|
+
"release": "./scripts/release.sh",
|
|
16
17
|
"dev": "npm run build && node dist/mcp-server.js",
|
|
17
18
|
"prepare": "npm run build",
|
|
18
19
|
"watch": "tsc --watch"
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
"commander": "^14.0.0",
|
|
25
26
|
"dotenv": "^17.2.0",
|
|
26
27
|
"json-rpc-2.0": "^1.7.1",
|
|
28
|
+
"semver": "^7.7.2",
|
|
27
29
|
"tsconfig-paths": "^4.2.0",
|
|
28
30
|
"tslib": "^2.8.1",
|
|
29
31
|
"zod": "^3.22.4"
|
|
@@ -38,6 +40,7 @@
|
|
|
38
40
|
],
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@types/node": "^20.19.9",
|
|
43
|
+
"@types/semver": "^7.7.0",
|
|
41
44
|
"typescript": "^5.8.3"
|
|
42
45
|
}
|
|
43
46
|
}
|