@kapeta/local-cluster-service 0.50.0 → 0.51.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/CHANGELOG.md +14 -0
- package/dist/cjs/src/storm/codegen.d.ts +3 -2
- package/dist/cjs/src/storm/codegen.js +170 -25
- package/dist/cjs/src/storm/event-parser.js +0 -4
- package/dist/cjs/src/storm/events.d.ts +31 -9
- package/dist/esm/src/storm/codegen.d.ts +3 -2
- package/dist/esm/src/storm/codegen.js +170 -25
- package/dist/esm/src/storm/event-parser.js +0 -4
- package/dist/esm/src/storm/events.d.ts +31 -9
- package/package.json +1 -1
- package/src/storm/codegen.ts +191 -32
- package/src/storm/event-parser.ts +0 -5
- package/src/storm/events.ts +39 -9
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.51.1](https://github.com/kapetacom/local-cluster-service/compare/v0.51.0...v0.51.1) (2024-06-05)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Add line numbers to chunks ([a60688e](https://github.com/kapetacom/local-cluster-service/commit/a60688e0341238160c6779ae43cae876a62e622d))
|
7
|
+
|
8
|
+
# [0.51.0](https://github.com/kapetacom/local-cluster-service/compare/v0.50.0...v0.51.0) (2024-06-05)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* Handle file streaming events ([#164](https://github.com/kapetacom/local-cluster-service/issues/164)) ([441847a](https://github.com/kapetacom/local-cluster-service/commit/441847a12d20826d843e62627ea9bf584043effb))
|
14
|
+
|
1
15
|
# [0.50.0](https://github.com/kapetacom/local-cluster-service/compare/v0.49.0...v0.50.0) (2024-06-05)
|
2
16
|
|
3
17
|
|
@@ -18,7 +18,8 @@ export declare class StormCodegen {
|
|
18
18
|
getStream(): StormStream;
|
19
19
|
private handleTemplateFileOutput;
|
20
20
|
private handleUiOutput;
|
21
|
-
private
|
21
|
+
private handleFileEvents;
|
22
|
+
private handleFileDoneOutput;
|
22
23
|
private getBasePath;
|
23
24
|
/**
|
24
25
|
* Generates the code for a block and sends it to the AI
|
@@ -34,7 +35,7 @@ export declare class StormCodegen {
|
|
34
35
|
/**
|
35
36
|
* Emits the text-based files to the stream
|
36
37
|
*/
|
37
|
-
private
|
38
|
+
private emitStaticFiles;
|
38
39
|
private emitFile;
|
39
40
|
/**
|
40
41
|
* Sends the template to the AI and processes the response
|
@@ -42,6 +42,51 @@ const path_1 = __importStar(require("path"));
|
|
42
42
|
const node_os_1 = __importDefault(require("node:os"));
|
43
43
|
const fs_1 = require("fs");
|
44
44
|
const path_2 = __importDefault(require("path"));
|
45
|
+
const SIMULATED_DELAY = 1000;
|
46
|
+
class SimulatedFileDelay {
|
47
|
+
file;
|
48
|
+
stream;
|
49
|
+
constructor(file, stream) {
|
50
|
+
this.file = file;
|
51
|
+
this.stream = stream;
|
52
|
+
}
|
53
|
+
async start() {
|
54
|
+
const commonPayload = {
|
55
|
+
filename: this.file.payload.filename,
|
56
|
+
path: this.file.payload.path,
|
57
|
+
blockName: this.file.payload.blockName,
|
58
|
+
blockRef: this.file.payload.blockRef,
|
59
|
+
instanceId: this.file.payload.instanceId,
|
60
|
+
};
|
61
|
+
this.stream.emit('data', {
|
62
|
+
type: 'FILE_START',
|
63
|
+
created: Date.now(),
|
64
|
+
reason: 'File start',
|
65
|
+
payload: commonPayload,
|
66
|
+
});
|
67
|
+
const lines = this.file.payload.content.split('\n');
|
68
|
+
const delayPerLine = SIMULATED_DELAY / lines.length;
|
69
|
+
let lineNumber = 0;
|
70
|
+
for (const line of lines) {
|
71
|
+
await new Promise((resolve) => {
|
72
|
+
setTimeout(() => {
|
73
|
+
this.stream.emit('data', {
|
74
|
+
type: 'FILE_CHUNK',
|
75
|
+
created: Date.now(),
|
76
|
+
reason: 'File chunk',
|
77
|
+
payload: {
|
78
|
+
...commonPayload,
|
79
|
+
content: line,
|
80
|
+
lineNumber: lineNumber++,
|
81
|
+
},
|
82
|
+
});
|
83
|
+
resolve();
|
84
|
+
}, delayPerLine);
|
85
|
+
});
|
86
|
+
}
|
87
|
+
this.stream.emit('data', this.file);
|
88
|
+
}
|
89
|
+
}
|
45
90
|
class StormCodegen {
|
46
91
|
userPrompt;
|
47
92
|
blocks;
|
@@ -70,42 +115,132 @@ class StormCodegen {
|
|
70
115
|
return this.out;
|
71
116
|
}
|
72
117
|
handleTemplateFileOutput(blockUri, aiName, template, data) {
|
118
|
+
if (this.handleFileEvents(blockUri, aiName, data)) {
|
119
|
+
return;
|
120
|
+
}
|
73
121
|
switch (data.type) {
|
74
|
-
case '
|
122
|
+
case 'FILE_DONE':
|
75
123
|
template.filename = data.payload.filename;
|
76
124
|
template.content = data.payload.content;
|
77
|
-
|
125
|
+
this.handleFileDoneOutput(blockUri, aiName, data);
|
126
|
+
break;
|
78
127
|
}
|
79
128
|
}
|
80
|
-
handleUiOutput(blockUri,
|
129
|
+
handleUiOutput(blockUri, blockName, data) {
|
130
|
+
const blockRef = blockUri.toNormalizedString();
|
131
|
+
const instanceId = event_parser_1.StormEventParser.toInstanceIdFromRef(blockRef);
|
132
|
+
if (this.handleFileEvents(blockUri, blockName, data)) {
|
133
|
+
return;
|
134
|
+
}
|
81
135
|
switch (data.type) {
|
82
136
|
case 'SCREEN':
|
83
|
-
const ref = blockUri.toNormalizedString();
|
84
137
|
this.out.emit('data', {
|
85
138
|
type: 'SCREEN',
|
86
139
|
reason: data.reason,
|
87
140
|
created: Date.now(),
|
88
141
|
payload: {
|
89
142
|
...data.payload,
|
90
|
-
blockName
|
91
|
-
blockRef
|
92
|
-
instanceId
|
143
|
+
blockName,
|
144
|
+
blockRef,
|
145
|
+
instanceId,
|
146
|
+
},
|
147
|
+
});
|
148
|
+
break;
|
149
|
+
case 'FILE_START':
|
150
|
+
case 'FILE_CHUNK_RESET':
|
151
|
+
this.out.emit('data', {
|
152
|
+
...data,
|
153
|
+
payload: {
|
154
|
+
...data.payload,
|
155
|
+
blockName,
|
156
|
+
blockRef,
|
157
|
+
instanceId,
|
93
158
|
},
|
94
159
|
});
|
95
|
-
|
96
|
-
|
160
|
+
break;
|
161
|
+
case 'FILE_CHUNK':
|
162
|
+
this.out.emit('data', {
|
163
|
+
...data,
|
164
|
+
payload: {
|
165
|
+
...data.payload,
|
166
|
+
blockName,
|
167
|
+
blockRef,
|
168
|
+
instanceId,
|
169
|
+
},
|
170
|
+
});
|
171
|
+
break;
|
172
|
+
case 'FILE_STATE':
|
173
|
+
this.out.emit('data', {
|
174
|
+
...data,
|
175
|
+
payload: {
|
176
|
+
...data.payload,
|
177
|
+
blockName,
|
178
|
+
blockRef,
|
179
|
+
instanceId,
|
180
|
+
},
|
181
|
+
});
|
182
|
+
break;
|
183
|
+
case 'FILE_DONE':
|
184
|
+
this.handleFileDoneOutput(blockUri, blockName, data);
|
185
|
+
break;
|
97
186
|
}
|
98
187
|
}
|
99
|
-
|
188
|
+
handleFileEvents(blockUri, blockName, data) {
|
189
|
+
const blockRef = blockUri.toNormalizedString();
|
190
|
+
const instanceId = event_parser_1.StormEventParser.toInstanceIdFromRef(blockRef);
|
191
|
+
const basePath = this.getBasePath(blockUri.fullName);
|
100
192
|
switch (data.type) {
|
101
|
-
case '
|
193
|
+
case 'FILE_START':
|
194
|
+
case 'FILE_CHUNK_RESET':
|
195
|
+
this.out.emit('data', {
|
196
|
+
...data,
|
197
|
+
payload: {
|
198
|
+
...data.payload,
|
199
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
200
|
+
blockName,
|
201
|
+
blockRef,
|
202
|
+
instanceId,
|
203
|
+
},
|
204
|
+
});
|
205
|
+
return true;
|
206
|
+
case 'FILE_CHUNK':
|
207
|
+
this.out.emit('data', {
|
208
|
+
...data,
|
209
|
+
payload: {
|
210
|
+
...data.payload,
|
211
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
212
|
+
blockName,
|
213
|
+
blockRef,
|
214
|
+
instanceId,
|
215
|
+
},
|
216
|
+
});
|
217
|
+
return true;
|
218
|
+
case 'FILE_STATE':
|
219
|
+
this.out.emit('data', {
|
220
|
+
...data,
|
221
|
+
payload: {
|
222
|
+
...data.payload,
|
223
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
224
|
+
blockName,
|
225
|
+
blockRef,
|
226
|
+
instanceId,
|
227
|
+
},
|
228
|
+
});
|
229
|
+
return true;
|
230
|
+
}
|
231
|
+
return false;
|
232
|
+
}
|
233
|
+
handleFileDoneOutput(blockUri, aiName, data) {
|
234
|
+
switch (data.type) {
|
235
|
+
case 'FILE_DONE':
|
102
236
|
const ref = blockUri.toNormalizedString();
|
103
237
|
this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
|
104
238
|
return {
|
105
|
-
type: '
|
239
|
+
type: 'FILE_DONE',
|
106
240
|
created: Date.now(),
|
107
241
|
payload: {
|
108
242
|
filename: data.payload.filename,
|
243
|
+
path: (0, path_1.join)(this.getBasePath(blockUri.fullName), data.payload.filename),
|
109
244
|
content: data.payload.content,
|
110
245
|
blockRef: ref,
|
111
246
|
instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
|
@@ -130,7 +265,7 @@ class StormCodegen {
|
|
130
265
|
}
|
131
266
|
const allFiles = this.toStormFiles(generatedResult);
|
132
267
|
// Send all the non-ai files to the stream
|
133
|
-
this.
|
268
|
+
await this.emitStaticFiles((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, allFiles);
|
134
269
|
if (this.isAborted()) {
|
135
270
|
return;
|
136
271
|
}
|
@@ -285,8 +420,8 @@ class StormCodegen {
|
|
285
420
|
/**
|
286
421
|
* Emits the text-based files to the stream
|
287
422
|
*/
|
288
|
-
|
289
|
-
files.
|
423
|
+
async emitStaticFiles(uri, aiName, files) {
|
424
|
+
const promises = files.map((file) => {
|
290
425
|
if (!file.content || typeof file.content !== 'string') {
|
291
426
|
return;
|
292
427
|
}
|
@@ -300,14 +435,30 @@ class StormCodegen {
|
|
300
435
|
// They will need to be implemented by the AI
|
301
436
|
return;
|
302
437
|
}
|
303
|
-
this.
|
438
|
+
const basePath = this.getBasePath(uri.fullName);
|
439
|
+
const ref = uri.toNormalizedString();
|
440
|
+
const fileEvent = {
|
441
|
+
type: 'FILE_DONE',
|
442
|
+
reason: 'File generated',
|
443
|
+
created: Date.now(),
|
444
|
+
payload: {
|
445
|
+
filename: file.filename,
|
446
|
+
path: (0, path_1.join)(basePath, file.filename),
|
447
|
+
content: file.content,
|
448
|
+
blockName: aiName,
|
449
|
+
blockRef: ref,
|
450
|
+
instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
|
451
|
+
},
|
452
|
+
};
|
453
|
+
return new SimulatedFileDelay(fileEvent, this.out).start();
|
304
454
|
});
|
455
|
+
return Promise.all(promises);
|
305
456
|
}
|
306
457
|
emitFile(uri, blockName, filename, content, reason = 'File generated') {
|
307
458
|
const basePath = this.getBasePath(uri.fullName);
|
308
459
|
const ref = uri.toNormalizedString();
|
309
460
|
this.out.emit('data', {
|
310
|
-
type: '
|
461
|
+
type: 'FILE_DONE',
|
311
462
|
reason,
|
312
463
|
created: Date.now(),
|
313
464
|
payload: {
|
@@ -330,21 +481,15 @@ class StormCodegen {
|
|
330
481
|
template: templateFile,
|
331
482
|
prompt: this.userPrompt,
|
332
483
|
});
|
333
|
-
const files = [];
|
334
484
|
this.out.on('aborted', () => {
|
335
485
|
stream.abort();
|
336
486
|
});
|
337
487
|
stream.on('data', (evt) => {
|
338
|
-
|
339
|
-
if (file) {
|
340
|
-
files.push(file);
|
341
|
-
}
|
488
|
+
this.handleTemplateFileOutput(blockUri, aiName, templateFile, evt);
|
342
489
|
});
|
343
490
|
await stream.waitForDone();
|
344
|
-
return files;
|
345
491
|
});
|
346
|
-
|
347
|
-
return fileChunks.flat();
|
492
|
+
await Promise.all(promises);
|
348
493
|
}
|
349
494
|
/**
|
350
495
|
* Converts the generated files to a format that can be sent to the AI
|
@@ -211,10 +211,6 @@ class StormEventParser {
|
|
211
211
|
evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
|
212
212
|
this.connections.push(evt.payload);
|
213
213
|
break;
|
214
|
-
default:
|
215
|
-
case 'SCREEN_CANDIDATE':
|
216
|
-
case 'FILE':
|
217
|
-
break;
|
218
214
|
}
|
219
215
|
return this.toResult(handle);
|
220
216
|
}
|
@@ -150,17 +150,39 @@ export interface StormEventScreenCandidate {
|
|
150
150
|
url: string;
|
151
151
|
};
|
152
152
|
}
|
153
|
-
export interface
|
154
|
-
|
153
|
+
export interface StormEventFileBasePayload {
|
154
|
+
filename: string;
|
155
|
+
path: string;
|
156
|
+
blockName: string;
|
157
|
+
blockRef: string;
|
158
|
+
instanceId: string;
|
159
|
+
}
|
160
|
+
export interface StormEventFileBase {
|
161
|
+
type: string;
|
155
162
|
reason: string;
|
156
163
|
created: number;
|
157
|
-
payload:
|
158
|
-
|
159
|
-
|
164
|
+
payload: StormEventFileBasePayload;
|
165
|
+
}
|
166
|
+
export interface StormEventFileLogical extends StormEventFileBase {
|
167
|
+
type: 'FILE_START' | 'FILE_CHUNK_RESET';
|
168
|
+
}
|
169
|
+
export interface StormEventFileState extends StormEventFileBase {
|
170
|
+
type: 'FILE_STATE';
|
171
|
+
payload: StormEventFileBasePayload & {
|
172
|
+
state: string;
|
173
|
+
};
|
174
|
+
}
|
175
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
176
|
+
type: 'FILE_DONE';
|
177
|
+
payload: StormEventFileBasePayload & {
|
160
178
|
content: string;
|
161
|
-
|
162
|
-
|
163
|
-
|
179
|
+
};
|
180
|
+
}
|
181
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
182
|
+
type: 'FILE_CHUNK';
|
183
|
+
payload: StormEventFileBasePayload & {
|
184
|
+
content: string;
|
185
|
+
lineNumber: number;
|
164
186
|
};
|
165
187
|
}
|
166
188
|
export interface StormEventBlockReady {
|
@@ -196,4 +218,4 @@ export interface StormEventPhases {
|
|
196
218
|
phaseType: StormEventPhaseType;
|
197
219
|
};
|
198
220
|
}
|
199
|
-
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate |
|
221
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventBlockReady | StormEventPhases;
|
@@ -18,7 +18,8 @@ export declare class StormCodegen {
|
|
18
18
|
getStream(): StormStream;
|
19
19
|
private handleTemplateFileOutput;
|
20
20
|
private handleUiOutput;
|
21
|
-
private
|
21
|
+
private handleFileEvents;
|
22
|
+
private handleFileDoneOutput;
|
22
23
|
private getBasePath;
|
23
24
|
/**
|
24
25
|
* Generates the code for a block and sends it to the AI
|
@@ -34,7 +35,7 @@ export declare class StormCodegen {
|
|
34
35
|
/**
|
35
36
|
* Emits the text-based files to the stream
|
36
37
|
*/
|
37
|
-
private
|
38
|
+
private emitStaticFiles;
|
38
39
|
private emitFile;
|
39
40
|
/**
|
40
41
|
* Sends the template to the AI and processes the response
|
@@ -42,6 +42,51 @@ const path_1 = __importStar(require("path"));
|
|
42
42
|
const node_os_1 = __importDefault(require("node:os"));
|
43
43
|
const fs_1 = require("fs");
|
44
44
|
const path_2 = __importDefault(require("path"));
|
45
|
+
const SIMULATED_DELAY = 1000;
|
46
|
+
class SimulatedFileDelay {
|
47
|
+
file;
|
48
|
+
stream;
|
49
|
+
constructor(file, stream) {
|
50
|
+
this.file = file;
|
51
|
+
this.stream = stream;
|
52
|
+
}
|
53
|
+
async start() {
|
54
|
+
const commonPayload = {
|
55
|
+
filename: this.file.payload.filename,
|
56
|
+
path: this.file.payload.path,
|
57
|
+
blockName: this.file.payload.blockName,
|
58
|
+
blockRef: this.file.payload.blockRef,
|
59
|
+
instanceId: this.file.payload.instanceId,
|
60
|
+
};
|
61
|
+
this.stream.emit('data', {
|
62
|
+
type: 'FILE_START',
|
63
|
+
created: Date.now(),
|
64
|
+
reason: 'File start',
|
65
|
+
payload: commonPayload,
|
66
|
+
});
|
67
|
+
const lines = this.file.payload.content.split('\n');
|
68
|
+
const delayPerLine = SIMULATED_DELAY / lines.length;
|
69
|
+
let lineNumber = 0;
|
70
|
+
for (const line of lines) {
|
71
|
+
await new Promise((resolve) => {
|
72
|
+
setTimeout(() => {
|
73
|
+
this.stream.emit('data', {
|
74
|
+
type: 'FILE_CHUNK',
|
75
|
+
created: Date.now(),
|
76
|
+
reason: 'File chunk',
|
77
|
+
payload: {
|
78
|
+
...commonPayload,
|
79
|
+
content: line,
|
80
|
+
lineNumber: lineNumber++,
|
81
|
+
},
|
82
|
+
});
|
83
|
+
resolve();
|
84
|
+
}, delayPerLine);
|
85
|
+
});
|
86
|
+
}
|
87
|
+
this.stream.emit('data', this.file);
|
88
|
+
}
|
89
|
+
}
|
45
90
|
class StormCodegen {
|
46
91
|
userPrompt;
|
47
92
|
blocks;
|
@@ -70,42 +115,132 @@ class StormCodegen {
|
|
70
115
|
return this.out;
|
71
116
|
}
|
72
117
|
handleTemplateFileOutput(blockUri, aiName, template, data) {
|
118
|
+
if (this.handleFileEvents(blockUri, aiName, data)) {
|
119
|
+
return;
|
120
|
+
}
|
73
121
|
switch (data.type) {
|
74
|
-
case '
|
122
|
+
case 'FILE_DONE':
|
75
123
|
template.filename = data.payload.filename;
|
76
124
|
template.content = data.payload.content;
|
77
|
-
|
125
|
+
this.handleFileDoneOutput(blockUri, aiName, data);
|
126
|
+
break;
|
78
127
|
}
|
79
128
|
}
|
80
|
-
handleUiOutput(blockUri,
|
129
|
+
handleUiOutput(blockUri, blockName, data) {
|
130
|
+
const blockRef = blockUri.toNormalizedString();
|
131
|
+
const instanceId = event_parser_1.StormEventParser.toInstanceIdFromRef(blockRef);
|
132
|
+
if (this.handleFileEvents(blockUri, blockName, data)) {
|
133
|
+
return;
|
134
|
+
}
|
81
135
|
switch (data.type) {
|
82
136
|
case 'SCREEN':
|
83
|
-
const ref = blockUri.toNormalizedString();
|
84
137
|
this.out.emit('data', {
|
85
138
|
type: 'SCREEN',
|
86
139
|
reason: data.reason,
|
87
140
|
created: Date.now(),
|
88
141
|
payload: {
|
89
142
|
...data.payload,
|
90
|
-
blockName
|
91
|
-
blockRef
|
92
|
-
instanceId
|
143
|
+
blockName,
|
144
|
+
blockRef,
|
145
|
+
instanceId,
|
146
|
+
},
|
147
|
+
});
|
148
|
+
break;
|
149
|
+
case 'FILE_START':
|
150
|
+
case 'FILE_CHUNK_RESET':
|
151
|
+
this.out.emit('data', {
|
152
|
+
...data,
|
153
|
+
payload: {
|
154
|
+
...data.payload,
|
155
|
+
blockName,
|
156
|
+
blockRef,
|
157
|
+
instanceId,
|
93
158
|
},
|
94
159
|
});
|
95
|
-
|
96
|
-
|
160
|
+
break;
|
161
|
+
case 'FILE_CHUNK':
|
162
|
+
this.out.emit('data', {
|
163
|
+
...data,
|
164
|
+
payload: {
|
165
|
+
...data.payload,
|
166
|
+
blockName,
|
167
|
+
blockRef,
|
168
|
+
instanceId,
|
169
|
+
},
|
170
|
+
});
|
171
|
+
break;
|
172
|
+
case 'FILE_STATE':
|
173
|
+
this.out.emit('data', {
|
174
|
+
...data,
|
175
|
+
payload: {
|
176
|
+
...data.payload,
|
177
|
+
blockName,
|
178
|
+
blockRef,
|
179
|
+
instanceId,
|
180
|
+
},
|
181
|
+
});
|
182
|
+
break;
|
183
|
+
case 'FILE_DONE':
|
184
|
+
this.handleFileDoneOutput(blockUri, blockName, data);
|
185
|
+
break;
|
97
186
|
}
|
98
187
|
}
|
99
|
-
|
188
|
+
handleFileEvents(blockUri, blockName, data) {
|
189
|
+
const blockRef = blockUri.toNormalizedString();
|
190
|
+
const instanceId = event_parser_1.StormEventParser.toInstanceIdFromRef(blockRef);
|
191
|
+
const basePath = this.getBasePath(blockUri.fullName);
|
100
192
|
switch (data.type) {
|
101
|
-
case '
|
193
|
+
case 'FILE_START':
|
194
|
+
case 'FILE_CHUNK_RESET':
|
195
|
+
this.out.emit('data', {
|
196
|
+
...data,
|
197
|
+
payload: {
|
198
|
+
...data.payload,
|
199
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
200
|
+
blockName,
|
201
|
+
blockRef,
|
202
|
+
instanceId,
|
203
|
+
},
|
204
|
+
});
|
205
|
+
return true;
|
206
|
+
case 'FILE_CHUNK':
|
207
|
+
this.out.emit('data', {
|
208
|
+
...data,
|
209
|
+
payload: {
|
210
|
+
...data.payload,
|
211
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
212
|
+
blockName,
|
213
|
+
blockRef,
|
214
|
+
instanceId,
|
215
|
+
},
|
216
|
+
});
|
217
|
+
return true;
|
218
|
+
case 'FILE_STATE':
|
219
|
+
this.out.emit('data', {
|
220
|
+
...data,
|
221
|
+
payload: {
|
222
|
+
...data.payload,
|
223
|
+
path: (0, path_1.join)(basePath, data.payload.filename),
|
224
|
+
blockName,
|
225
|
+
blockRef,
|
226
|
+
instanceId,
|
227
|
+
},
|
228
|
+
});
|
229
|
+
return true;
|
230
|
+
}
|
231
|
+
return false;
|
232
|
+
}
|
233
|
+
handleFileDoneOutput(blockUri, aiName, data) {
|
234
|
+
switch (data.type) {
|
235
|
+
case 'FILE_DONE':
|
102
236
|
const ref = blockUri.toNormalizedString();
|
103
237
|
this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
|
104
238
|
return {
|
105
|
-
type: '
|
239
|
+
type: 'FILE_DONE',
|
106
240
|
created: Date.now(),
|
107
241
|
payload: {
|
108
242
|
filename: data.payload.filename,
|
243
|
+
path: (0, path_1.join)(this.getBasePath(blockUri.fullName), data.payload.filename),
|
109
244
|
content: data.payload.content,
|
110
245
|
blockRef: ref,
|
111
246
|
instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
|
@@ -130,7 +265,7 @@ class StormCodegen {
|
|
130
265
|
}
|
131
266
|
const allFiles = this.toStormFiles(generatedResult);
|
132
267
|
// Send all the non-ai files to the stream
|
133
|
-
this.
|
268
|
+
await this.emitStaticFiles((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, allFiles);
|
134
269
|
if (this.isAborted()) {
|
135
270
|
return;
|
136
271
|
}
|
@@ -285,8 +420,8 @@ class StormCodegen {
|
|
285
420
|
/**
|
286
421
|
* Emits the text-based files to the stream
|
287
422
|
*/
|
288
|
-
|
289
|
-
files.
|
423
|
+
async emitStaticFiles(uri, aiName, files) {
|
424
|
+
const promises = files.map((file) => {
|
290
425
|
if (!file.content || typeof file.content !== 'string') {
|
291
426
|
return;
|
292
427
|
}
|
@@ -300,14 +435,30 @@ class StormCodegen {
|
|
300
435
|
// They will need to be implemented by the AI
|
301
436
|
return;
|
302
437
|
}
|
303
|
-
this.
|
438
|
+
const basePath = this.getBasePath(uri.fullName);
|
439
|
+
const ref = uri.toNormalizedString();
|
440
|
+
const fileEvent = {
|
441
|
+
type: 'FILE_DONE',
|
442
|
+
reason: 'File generated',
|
443
|
+
created: Date.now(),
|
444
|
+
payload: {
|
445
|
+
filename: file.filename,
|
446
|
+
path: (0, path_1.join)(basePath, file.filename),
|
447
|
+
content: file.content,
|
448
|
+
blockName: aiName,
|
449
|
+
blockRef: ref,
|
450
|
+
instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
|
451
|
+
},
|
452
|
+
};
|
453
|
+
return new SimulatedFileDelay(fileEvent, this.out).start();
|
304
454
|
});
|
455
|
+
return Promise.all(promises);
|
305
456
|
}
|
306
457
|
emitFile(uri, blockName, filename, content, reason = 'File generated') {
|
307
458
|
const basePath = this.getBasePath(uri.fullName);
|
308
459
|
const ref = uri.toNormalizedString();
|
309
460
|
this.out.emit('data', {
|
310
|
-
type: '
|
461
|
+
type: 'FILE_DONE',
|
311
462
|
reason,
|
312
463
|
created: Date.now(),
|
313
464
|
payload: {
|
@@ -330,21 +481,15 @@ class StormCodegen {
|
|
330
481
|
template: templateFile,
|
331
482
|
prompt: this.userPrompt,
|
332
483
|
});
|
333
|
-
const files = [];
|
334
484
|
this.out.on('aborted', () => {
|
335
485
|
stream.abort();
|
336
486
|
});
|
337
487
|
stream.on('data', (evt) => {
|
338
|
-
|
339
|
-
if (file) {
|
340
|
-
files.push(file);
|
341
|
-
}
|
488
|
+
this.handleTemplateFileOutput(blockUri, aiName, templateFile, evt);
|
342
489
|
});
|
343
490
|
await stream.waitForDone();
|
344
|
-
return files;
|
345
491
|
});
|
346
|
-
|
347
|
-
return fileChunks.flat();
|
492
|
+
await Promise.all(promises);
|
348
493
|
}
|
349
494
|
/**
|
350
495
|
* Converts the generated files to a format that can be sent to the AI
|
@@ -211,10 +211,6 @@ class StormEventParser {
|
|
211
211
|
evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
|
212
212
|
this.connections.push(evt.payload);
|
213
213
|
break;
|
214
|
-
default:
|
215
|
-
case 'SCREEN_CANDIDATE':
|
216
|
-
case 'FILE':
|
217
|
-
break;
|
218
214
|
}
|
219
215
|
return this.toResult(handle);
|
220
216
|
}
|
@@ -150,17 +150,39 @@ export interface StormEventScreenCandidate {
|
|
150
150
|
url: string;
|
151
151
|
};
|
152
152
|
}
|
153
|
-
export interface
|
154
|
-
|
153
|
+
export interface StormEventFileBasePayload {
|
154
|
+
filename: string;
|
155
|
+
path: string;
|
156
|
+
blockName: string;
|
157
|
+
blockRef: string;
|
158
|
+
instanceId: string;
|
159
|
+
}
|
160
|
+
export interface StormEventFileBase {
|
161
|
+
type: string;
|
155
162
|
reason: string;
|
156
163
|
created: number;
|
157
|
-
payload:
|
158
|
-
|
159
|
-
|
164
|
+
payload: StormEventFileBasePayload;
|
165
|
+
}
|
166
|
+
export interface StormEventFileLogical extends StormEventFileBase {
|
167
|
+
type: 'FILE_START' | 'FILE_CHUNK_RESET';
|
168
|
+
}
|
169
|
+
export interface StormEventFileState extends StormEventFileBase {
|
170
|
+
type: 'FILE_STATE';
|
171
|
+
payload: StormEventFileBasePayload & {
|
172
|
+
state: string;
|
173
|
+
};
|
174
|
+
}
|
175
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
176
|
+
type: 'FILE_DONE';
|
177
|
+
payload: StormEventFileBasePayload & {
|
160
178
|
content: string;
|
161
|
-
|
162
|
-
|
163
|
-
|
179
|
+
};
|
180
|
+
}
|
181
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
182
|
+
type: 'FILE_CHUNK';
|
183
|
+
payload: StormEventFileBasePayload & {
|
184
|
+
content: string;
|
185
|
+
lineNumber: number;
|
164
186
|
};
|
165
187
|
}
|
166
188
|
export interface StormEventBlockReady {
|
@@ -196,4 +218,4 @@ export interface StormEventPhases {
|
|
196
218
|
phaseType: StormEventPhaseType;
|
197
219
|
};
|
198
220
|
}
|
199
|
-
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate |
|
221
|
+
export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventBlockReady | StormEventPhases;
|
package/package.json
CHANGED
package/src/storm/codegen.ts
CHANGED
@@ -15,7 +15,7 @@ import {
|
|
15
15
|
import { BlockDefinition } from '@kapeta/schemas';
|
16
16
|
import { codeGeneratorManager } from '../codeGeneratorManager';
|
17
17
|
import { STORM_ID, stormClient } from './stormClient';
|
18
|
-
import { StormEvent,
|
18
|
+
import { StormEvent, StormEventFileChunk, StormEventFileDone, StormEventFileLogical } from './events';
|
19
19
|
import { BlockDefinitionInfo, StormEventParser } from './event-parser';
|
20
20
|
import { StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
|
21
21
|
import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
|
@@ -27,6 +27,56 @@ import Path from 'path';
|
|
27
27
|
|
28
28
|
type ImplementationGenerator = (prompt: StormFileImplementationPrompt, conversationId?: string) => Promise<StormStream>;
|
29
29
|
|
30
|
+
const SIMULATED_DELAY = 1000;
|
31
|
+
|
32
|
+
class SimulatedFileDelay {
|
33
|
+
private readonly file: StormEventFileDone;
|
34
|
+
public readonly stream;
|
35
|
+
constructor(file: StormEventFileDone, stream: StormStream) {
|
36
|
+
this.file = file;
|
37
|
+
this.stream = stream;
|
38
|
+
}
|
39
|
+
|
40
|
+
public async start() {
|
41
|
+
const commonPayload = {
|
42
|
+
filename: this.file.payload.filename,
|
43
|
+
path: this.file.payload.path,
|
44
|
+
blockName: this.file.payload.blockName,
|
45
|
+
blockRef: this.file.payload.blockRef,
|
46
|
+
instanceId: this.file.payload.instanceId,
|
47
|
+
};
|
48
|
+
this.stream.emit('data', {
|
49
|
+
type: 'FILE_START',
|
50
|
+
created: Date.now(),
|
51
|
+
reason: 'File start',
|
52
|
+
payload: commonPayload,
|
53
|
+
} satisfies StormEventFileLogical);
|
54
|
+
|
55
|
+
const lines = this.file.payload.content.split('\n');
|
56
|
+
const delayPerLine = SIMULATED_DELAY / lines.length;
|
57
|
+
let lineNumber = 0;
|
58
|
+
for (const line of lines) {
|
59
|
+
await new Promise<void>((resolve) => {
|
60
|
+
setTimeout(() => {
|
61
|
+
this.stream.emit('data', {
|
62
|
+
type: 'FILE_CHUNK',
|
63
|
+
created: Date.now(),
|
64
|
+
reason: 'File chunk',
|
65
|
+
payload: {
|
66
|
+
...commonPayload,
|
67
|
+
content: line,
|
68
|
+
lineNumber: lineNumber++,
|
69
|
+
},
|
70
|
+
} satisfies StormEventFileChunk);
|
71
|
+
resolve();
|
72
|
+
}, delayPerLine);
|
73
|
+
});
|
74
|
+
}
|
75
|
+
|
76
|
+
this.stream.emit('data', this.file);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
30
80
|
export class StormCodegen {
|
31
81
|
private readonly userPrompt: string;
|
32
82
|
private readonly blocks: BlockDefinitionInfo[];
|
@@ -59,50 +109,150 @@ export class StormCodegen {
|
|
59
109
|
return this.out;
|
60
110
|
}
|
61
111
|
|
62
|
-
private handleTemplateFileOutput(
|
112
|
+
private handleTemplateFileOutput(
|
113
|
+
blockUri: KapetaURI,
|
114
|
+
aiName: string,
|
115
|
+
template: StormFileInfo,
|
116
|
+
data: StormEvent
|
117
|
+
): void {
|
118
|
+
if (this.handleFileEvents(blockUri, aiName, data)) {
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
|
63
122
|
switch (data.type) {
|
64
|
-
case '
|
123
|
+
case 'FILE_DONE':
|
65
124
|
template.filename = data.payload.filename;
|
66
125
|
template.content = data.payload.content;
|
67
|
-
|
126
|
+
this.handleFileDoneOutput(blockUri, aiName, data);
|
127
|
+
break;
|
68
128
|
}
|
69
129
|
}
|
70
130
|
|
71
|
-
private handleUiOutput(blockUri: KapetaURI,
|
131
|
+
private handleUiOutput(blockUri: KapetaURI, blockName: string, data: StormEvent) {
|
132
|
+
const blockRef = blockUri.toNormalizedString();
|
133
|
+
const instanceId = StormEventParser.toInstanceIdFromRef(blockRef);
|
134
|
+
|
135
|
+
if (this.handleFileEvents(blockUri, blockName, data)) {
|
136
|
+
return;
|
137
|
+
}
|
138
|
+
|
72
139
|
switch (data.type) {
|
73
140
|
case 'SCREEN':
|
74
|
-
const ref = blockUri.toNormalizedString();
|
75
141
|
this.out.emit('data', {
|
76
142
|
type: 'SCREEN',
|
77
143
|
reason: data.reason,
|
78
144
|
created: Date.now(),
|
79
145
|
payload: {
|
80
146
|
...data.payload,
|
81
|
-
blockName
|
82
|
-
blockRef
|
83
|
-
instanceId
|
147
|
+
blockName,
|
148
|
+
blockRef,
|
149
|
+
instanceId,
|
150
|
+
},
|
151
|
+
});
|
152
|
+
break;
|
153
|
+
case 'FILE_START':
|
154
|
+
case 'FILE_CHUNK_RESET':
|
155
|
+
this.out.emit('data', {
|
156
|
+
...data,
|
157
|
+
payload: {
|
158
|
+
...data.payload,
|
159
|
+
blockName,
|
160
|
+
blockRef,
|
161
|
+
instanceId,
|
162
|
+
},
|
163
|
+
});
|
164
|
+
break;
|
165
|
+
case 'FILE_CHUNK':
|
166
|
+
this.out.emit('data', {
|
167
|
+
...data,
|
168
|
+
payload: {
|
169
|
+
...data.payload,
|
170
|
+
blockName,
|
171
|
+
blockRef,
|
172
|
+
instanceId,
|
84
173
|
},
|
85
174
|
});
|
86
|
-
|
87
|
-
|
175
|
+
break;
|
176
|
+
case 'FILE_STATE':
|
177
|
+
this.out.emit('data', {
|
178
|
+
...data,
|
179
|
+
payload: {
|
180
|
+
...data.payload,
|
181
|
+
blockName,
|
182
|
+
blockRef,
|
183
|
+
instanceId,
|
184
|
+
},
|
185
|
+
});
|
186
|
+
break;
|
187
|
+
case 'FILE_DONE':
|
188
|
+
this.handleFileDoneOutput(blockUri, blockName, data);
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
private handleFileEvents(blockUri: KapetaURI, blockName: string, data: StormEvent) {
|
194
|
+
const blockRef = blockUri.toNormalizedString();
|
195
|
+
const instanceId = StormEventParser.toInstanceIdFromRef(blockRef);
|
196
|
+
const basePath = this.getBasePath(blockUri.fullName);
|
197
|
+
switch (data.type) {
|
198
|
+
case 'FILE_START':
|
199
|
+
case 'FILE_CHUNK_RESET':
|
200
|
+
this.out.emit('data', {
|
201
|
+
...data,
|
202
|
+
payload: {
|
203
|
+
...data.payload,
|
204
|
+
path: join(basePath, data.payload.filename),
|
205
|
+
blockName,
|
206
|
+
blockRef,
|
207
|
+
instanceId,
|
208
|
+
},
|
209
|
+
});
|
210
|
+
return true;
|
211
|
+
case 'FILE_CHUNK':
|
212
|
+
this.out.emit('data', {
|
213
|
+
...data,
|
214
|
+
payload: {
|
215
|
+
...data.payload,
|
216
|
+
path: join(basePath, data.payload.filename),
|
217
|
+
blockName,
|
218
|
+
blockRef,
|
219
|
+
instanceId,
|
220
|
+
},
|
221
|
+
});
|
222
|
+
return true;
|
223
|
+
case 'FILE_STATE':
|
224
|
+
this.out.emit('data', {
|
225
|
+
...data,
|
226
|
+
payload: {
|
227
|
+
...data.payload,
|
228
|
+
path: join(basePath, data.payload.filename),
|
229
|
+
blockName,
|
230
|
+
blockRef,
|
231
|
+
instanceId,
|
232
|
+
},
|
233
|
+
});
|
234
|
+
return true;
|
88
235
|
}
|
236
|
+
|
237
|
+
return false;
|
89
238
|
}
|
90
239
|
|
91
|
-
private
|
240
|
+
private handleFileDoneOutput(blockUri: KapetaURI, aiName: string, data: StormEvent) {
|
92
241
|
switch (data.type) {
|
93
|
-
case '
|
242
|
+
case 'FILE_DONE':
|
94
243
|
const ref = blockUri.toNormalizedString();
|
95
244
|
this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
|
96
245
|
return {
|
97
|
-
type: '
|
246
|
+
type: 'FILE_DONE',
|
98
247
|
created: Date.now(),
|
99
248
|
payload: {
|
100
249
|
filename: data.payload.filename,
|
250
|
+
path: join(this.getBasePath(blockUri.fullName), data.payload.filename),
|
101
251
|
content: data.payload.content,
|
102
252
|
blockRef: ref,
|
103
253
|
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
104
254
|
},
|
105
|
-
} as
|
255
|
+
} as StormEventFileDone;
|
106
256
|
}
|
107
257
|
}
|
108
258
|
|
@@ -126,7 +276,7 @@ export class StormCodegen {
|
|
126
276
|
const allFiles = this.toStormFiles(generatedResult);
|
127
277
|
|
128
278
|
// Send all the non-ai files to the stream
|
129
|
-
this.
|
279
|
+
await this.emitStaticFiles(parseKapetaUri(block.uri), block.aiName, allFiles);
|
130
280
|
|
131
281
|
if (this.isAborted()) {
|
132
282
|
return;
|
@@ -318,8 +468,8 @@ export class StormCodegen {
|
|
318
468
|
/**
|
319
469
|
* Emits the text-based files to the stream
|
320
470
|
*/
|
321
|
-
private
|
322
|
-
files.
|
471
|
+
private async emitStaticFiles(uri: KapetaURI, aiName: string, files: StormFileInfo[]) {
|
472
|
+
const promises = files.map((file) => {
|
323
473
|
if (!file.content || typeof file.content !== 'string') {
|
324
474
|
return;
|
325
475
|
}
|
@@ -336,8 +486,25 @@ export class StormCodegen {
|
|
336
486
|
return;
|
337
487
|
}
|
338
488
|
|
339
|
-
this.
|
489
|
+
const basePath = this.getBasePath(uri.fullName);
|
490
|
+
const ref = uri.toNormalizedString();
|
491
|
+
const fileEvent: StormEventFileDone = {
|
492
|
+
type: 'FILE_DONE',
|
493
|
+
reason: 'File generated',
|
494
|
+
created: Date.now(),
|
495
|
+
payload: {
|
496
|
+
filename: file.filename,
|
497
|
+
path: join(basePath, file.filename),
|
498
|
+
content: file.content,
|
499
|
+
blockName: aiName,
|
500
|
+
blockRef: ref,
|
501
|
+
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
502
|
+
},
|
503
|
+
};
|
504
|
+
return new SimulatedFileDelay(fileEvent, this.out).start();
|
340
505
|
});
|
506
|
+
|
507
|
+
return Promise.all(promises);
|
341
508
|
}
|
342
509
|
|
343
510
|
private emitFile(
|
@@ -350,7 +517,7 @@ export class StormCodegen {
|
|
350
517
|
const basePath = this.getBasePath(uri.fullName);
|
351
518
|
const ref = uri.toNormalizedString();
|
352
519
|
this.out.emit('data', {
|
353
|
-
type: '
|
520
|
+
type: 'FILE_DONE',
|
354
521
|
reason,
|
355
522
|
created: Date.now(),
|
356
523
|
payload: {
|
@@ -361,7 +528,7 @@ export class StormCodegen {
|
|
361
528
|
blockRef: ref,
|
362
529
|
instanceId: StormEventParser.toInstanceIdFromRef(ref),
|
363
530
|
},
|
364
|
-
} satisfies
|
531
|
+
} satisfies StormEventFileDone);
|
365
532
|
}
|
366
533
|
|
367
534
|
/**
|
@@ -373,7 +540,7 @@ export class StormCodegen {
|
|
373
540
|
generator: ImplementationGenerator,
|
374
541
|
templates: StormFileInfo[],
|
375
542
|
contextFiles: StormFileInfo[]
|
376
|
-
) {
|
543
|
+
): Promise<void> {
|
377
544
|
const promises = templates.map(async (templateFile) => {
|
378
545
|
const stream = await generator({
|
379
546
|
context: contextFiles,
|
@@ -381,26 +548,18 @@ export class StormCodegen {
|
|
381
548
|
prompt: this.userPrompt,
|
382
549
|
});
|
383
550
|
|
384
|
-
const files: StormEventFile[] = [];
|
385
|
-
|
386
551
|
this.out.on('aborted', () => {
|
387
552
|
stream.abort();
|
388
553
|
});
|
389
554
|
|
390
555
|
stream.on('data', (evt) => {
|
391
|
-
|
392
|
-
if (file) {
|
393
|
-
files.push(file);
|
394
|
-
}
|
556
|
+
this.handleTemplateFileOutput(blockUri, aiName, templateFile, evt);
|
395
557
|
});
|
396
558
|
|
397
559
|
await stream.waitForDone();
|
398
|
-
return files;
|
399
560
|
});
|
400
561
|
|
401
|
-
|
402
|
-
|
403
|
-
return fileChunks.flat();
|
562
|
+
await Promise.all(promises);
|
404
563
|
}
|
405
564
|
|
406
565
|
/**
|
@@ -325,11 +325,6 @@ export class StormEventParser {
|
|
325
325
|
evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
|
326
326
|
this.connections.push(evt.payload);
|
327
327
|
break;
|
328
|
-
|
329
|
-
default:
|
330
|
-
case 'SCREEN_CANDIDATE':
|
331
|
-
case 'FILE':
|
332
|
-
break;
|
333
328
|
}
|
334
329
|
|
335
330
|
return this.toResult(handle);
|
package/src/storm/events.ts
CHANGED
@@ -182,17 +182,44 @@ export interface StormEventScreenCandidate {
|
|
182
182
|
};
|
183
183
|
}
|
184
184
|
|
185
|
-
export interface
|
186
|
-
|
185
|
+
export interface StormEventFileBasePayload {
|
186
|
+
filename: string;
|
187
|
+
path: string;
|
188
|
+
blockName: string;
|
189
|
+
blockRef: string;
|
190
|
+
instanceId: string;
|
191
|
+
}
|
192
|
+
|
193
|
+
export interface StormEventFileBase {
|
194
|
+
type: string;
|
187
195
|
reason: string;
|
188
196
|
created: number;
|
189
|
-
payload:
|
190
|
-
|
191
|
-
|
197
|
+
payload: StormEventFileBasePayload;
|
198
|
+
}
|
199
|
+
|
200
|
+
export interface StormEventFileLogical extends StormEventFileBase {
|
201
|
+
type: 'FILE_START' | 'FILE_CHUNK_RESET';
|
202
|
+
}
|
203
|
+
|
204
|
+
export interface StormEventFileState extends StormEventFileBase {
|
205
|
+
type: 'FILE_STATE';
|
206
|
+
payload: StormEventFileBasePayload & {
|
207
|
+
state: string;
|
208
|
+
};
|
209
|
+
}
|
210
|
+
|
211
|
+
export interface StormEventFileDone extends StormEventFileBase {
|
212
|
+
type: 'FILE_DONE';
|
213
|
+
payload: StormEventFileBasePayload & {
|
192
214
|
content: string;
|
193
|
-
|
194
|
-
|
195
|
-
|
215
|
+
};
|
216
|
+
}
|
217
|
+
|
218
|
+
export interface StormEventFileChunk extends StormEventFileBase {
|
219
|
+
type: 'FILE_CHUNK';
|
220
|
+
payload: StormEventFileBasePayload & {
|
221
|
+
content: string;
|
222
|
+
lineNumber: number;
|
196
223
|
};
|
197
224
|
}
|
198
225
|
|
@@ -245,7 +272,10 @@ export type StormEvent =
|
|
245
272
|
| StormEventError
|
246
273
|
| StormEventScreen
|
247
274
|
| StormEventScreenCandidate
|
248
|
-
|
|
275
|
+
| StormEventFileLogical
|
276
|
+
| StormEventFileState
|
277
|
+
| StormEventFileDone
|
278
|
+
| StormEventFileChunk
|
249
279
|
| StormEventDone
|
250
280
|
| StormEventDefinitionChange
|
251
281
|
| StormEventErrorClassifier
|