@kapeta/local-cluster-service 0.52.3 → 0.53.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 CHANGED
@@ -1,3 +1,17 @@
1
+ ## [0.53.1](https://github.com/kapetacom/local-cluster-service/compare/v0.53.0...v0.53.1) (2024-06-13)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Do not use local versions ([bcb9aa8](https://github.com/kapetacom/local-cluster-service/commit/bcb9aa8d48114a6ad524a8bd34a41e1d76bc7897))
7
+
8
+ # [0.53.0](https://github.com/kapetacom/local-cluster-service/compare/v0.52.3...v0.53.0) (2024-06-12)
9
+
10
+
11
+ ### Features
12
+
13
+ * Emit code fixing events to UI ([#172](https://github.com/kapetacom/local-cluster-service/issues/172)) ([c10f5d0](https://github.com/kapetacom/local-cluster-service/commit/c10f5d03fdcf696085b2114aae45510a46ee6ec3))
14
+
1
15
  ## [0.52.3](https://github.com/kapetacom/local-cluster-service/compare/v0.52.2...v0.52.3) (2024-06-12)
2
16
 
3
17
 
@@ -25,6 +25,7 @@ export declare class StormCodegen {
25
25
  * Generates the code for a block and sends it to the AI
26
26
  */
27
27
  private processBlockCode;
28
+ private emitBlockStatus;
28
29
  private verifyAndFixCode;
29
30
  private tryToFixFile;
30
31
  private classifyErrors;
@@ -34,6 +34,7 @@ exports.StormCodegen = void 0;
34
34
  const codegen_1 = require("@kapeta/codegen");
35
35
  const codeGeneratorManager_1 = require("../codeGeneratorManager");
36
36
  const stormClient_1 = require("./stormClient");
37
+ const events_1 = require("./events");
37
38
  const event_parser_1 = require("./event-parser");
38
39
  const stream_1 = require("./stream");
39
40
  const nodejs_utils_1 = require("@kapeta/nodejs-utils");
@@ -44,8 +45,8 @@ const node_os_1 = __importDefault(require("node:os"));
44
45
  const fs_1 = require("fs");
45
46
  const yaml_1 = __importDefault(require("yaml"));
46
47
  const fs = __importStar(require("node:fs"));
47
- const uuid_1 = require("uuid");
48
48
  const SIMULATED_DELAY = 1000;
49
+ const ENABLE_SIMULATED_DELAY = false;
49
50
  class SimulatedFileDelay {
50
51
  file;
51
52
  stream;
@@ -149,43 +150,8 @@ class StormCodegen {
149
150
  },
150
151
  });
151
152
  break;
152
- case 'FILE_START':
153
- case 'FILE_CHUNK_RESET':
154
- this.out.emit('data', {
155
- ...data,
156
- payload: {
157
- ...data.payload,
158
- blockName,
159
- blockRef,
160
- instanceId,
161
- },
162
- });
163
- break;
164
- case 'FILE_CHUNK':
165
- this.out.emit('data', {
166
- ...data,
167
- payload: {
168
- ...data.payload,
169
- blockName,
170
- blockRef,
171
- instanceId,
172
- },
173
- });
174
- break;
175
- case 'FILE_STATE':
176
- this.out.emit('data', {
177
- ...data,
178
- payload: {
179
- ...data.payload,
180
- blockName,
181
- blockRef,
182
- instanceId,
183
- },
184
- });
185
- break;
186
153
  case 'FILE_DONE':
187
154
  return this.handleFileDoneOutput(blockUri, blockName, data);
188
- break;
189
155
  }
190
156
  }
191
157
  handleFileEvents(blockUri, blockName, data) {
@@ -272,6 +238,7 @@ class StormCodegen {
272
238
  if (this.isAborted()) {
273
239
  return;
274
240
  }
241
+ const blockUri = (0, nodejs_utils_1.parseKapetaUri)(block.uri);
275
242
  const relevantFiles = allFiles.filter((file) => file.type !== codegen_1.AIFileTypes.IGNORE && file.type !== codegen_1.AIFileTypes.WEB_SCREEN);
276
243
  const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
277
244
  const screenFiles = [];
@@ -284,7 +251,7 @@ class StormCodegen {
284
251
  prompt: this.userPrompt,
285
252
  });
286
253
  uiStream.on('data', (evt) => {
287
- const uiFile = this.handleUiOutput((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, evt);
254
+ const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
288
255
  if (uiFile != undefined) {
289
256
  screenFiles.push(uiFile);
290
257
  }
@@ -302,7 +269,7 @@ class StormCodegen {
302
269
  // Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
303
270
  const serviceFiles = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.SERVICE);
304
271
  if (serviceFiles.length > 0) {
305
- await this.processTemplates((0, nodejs_utils_1.parseKapetaUri)(block.uri), block.aiName, stormClient_1.stormClient.createServiceImplementation.bind(stormClient_1.stormClient), serviceFiles, contextFiles);
272
+ await this.processTemplates(blockUri, block.aiName, stormClient_1.stormClient.createServiceImplementation.bind(stormClient_1.stormClient), serviceFiles, contextFiles);
306
273
  }
307
274
  const basePath = this.getBasePath(block.content.metadata.name);
308
275
  if (this.isAborted()) {
@@ -322,7 +289,7 @@ class StormCodegen {
322
289
  const filePath = (0, path_2.join)(basePath, screenFile.payload.filename);
323
290
  await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
324
291
  }
325
- const screenFilesConverted = screenFiles.map(screenFile => {
292
+ const screenFilesConverted = screenFiles.map((screenFile) => {
326
293
  return {
327
294
  filename: screenFile.payload.filename,
328
295
  content: screenFile.payload.content,
@@ -332,10 +299,12 @@ class StormCodegen {
332
299
  };
333
300
  });
334
301
  allFiles.push(...screenFilesConverted);
302
+ const blockRef = block.uri;
303
+ this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.QA);
335
304
  const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
336
305
  const codeGenerator = new codegen_1.BlockCodeGenerator(block.content);
337
- await this.verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles);
338
- const blockRef = block.uri;
306
+ this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.BUILDING);
307
+ await this.verifyAndFixCode(blockUri, block.aiName, codeGenerator, basePath, filesToBeFixed, allFiles);
339
308
  this.out.emit('data', {
340
309
  type: 'BLOCK_READY',
341
310
  reason: 'Block ready',
@@ -348,7 +317,20 @@ class StormCodegen {
348
317
  },
349
318
  });
350
319
  }
351
- async verifyAndFixCode(codeGenerator, basePath, filesToBeFixed, allFiles) {
320
+ emitBlockStatus(blockUri, blockName, status) {
321
+ this.out.emit('data', {
322
+ type: 'BLOCK_STATUS',
323
+ reason: status,
324
+ created: Date.now(),
325
+ payload: {
326
+ status,
327
+ blockName,
328
+ blockRef: blockUri.toNormalizedString(),
329
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(blockUri.toNormalizedString()),
330
+ },
331
+ });
332
+ }
333
+ async verifyAndFixCode(blockUri, blockName, codeGenerator, basePath, filesToBeFixed, allFiles) {
352
334
  let attempts = 0;
353
335
  let validCode = false;
354
336
  for (let i = 0; i <= 3; i++) {
@@ -362,11 +344,17 @@ class StormCodegen {
362
344
  }
363
345
  if (result && !result.valid) {
364
346
  console.debug('Validation error:', result);
347
+ this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.PLANNING_FIX);
365
348
  const errors = await this.classifyErrors(result.error, basePath);
366
- for (const [filename, fileErrors] of errors.entries()) {
367
- // todo: only try to fix file if it is part of filesToBeFixed
368
- await this.tryToFixFile(basePath, filename, fileErrors, allFiles, codeGenerator);
349
+ if (errors.size > 0) {
350
+ this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.FIXING);
351
+ const promises = Array.from(errors.entries()).map(([filename, fileErrors]) => {
352
+ // todo: only try to fix file if it is part of filesToBeFixed
353
+ return this.tryToFixFile(blockUri, blockName, basePath, filename, fileErrors, allFiles, codeGenerator);
354
+ });
355
+ await Promise.all(promises);
369
356
  }
357
+ this.emitBlockStatus(blockUri, blockName, events_1.StormEventBlockStatusType.FIX_DONE);
370
358
  }
371
359
  }
372
360
  catch (e) {
@@ -380,10 +368,10 @@ class StormCodegen {
380
368
  console.error(`Validation failed for ${basePath} after ${attempts} attempts`);
381
369
  }
382
370
  }
383
- async tryToFixFile(basePath, filename, fileErrors, allFiles, codeGenerator) {
371
+ async tryToFixFile(blockUri, blockName, basePath, filename, fileErrors, allFiles, codeGenerator) {
384
372
  console.log(`Processing ${filename}`);
385
373
  const language = await codeGenerator.language();
386
- const relevantFiles = allFiles.filter(file => file.type != codegen_1.AIFileTypes.IGNORE);
374
+ const relevantFiles = allFiles.filter((file) => file.type != codegen_1.AIFileTypes.IGNORE);
387
375
  for (let attempts = 1; attempts <= 5; attempts++) {
388
376
  if (fileErrors.length == 0) {
389
377
  console.log(`No more errors for ${filename}`);
@@ -393,17 +381,17 @@ class StormCodegen {
393
381
  const filesForContext = await this.getErrorDetailsForFile(basePath, filename, fileErrors[0], relevantFiles, language);
394
382
  console.log(`Get error details for ${filename} requesting code fixes`);
395
383
  const fix = this.createFixRequestForFile(basePath, filename, fileErrors[0], filesForContext, relevantFiles, language);
396
- const codeFixFiles = await this.codeFix(fix);
384
+ const codeFixFile = await this.codeFix(blockUri, blockName, fix);
397
385
  console.log(`Got fixed code for ${filename}`);
398
- for (const codeFixFile of codeFixFiles) {
399
- const filePath = codeFixFile.filename.indexOf(basePath) > -1 ? codeFixFile.filename : (0, path_2.join)(basePath, codeFixFile.filename);
400
- const existing = (0, fs_1.readFileSync)(filePath);
401
- if (existing.toString().replace(/(\r\n|\r|\n)+$/, '') == codeFixFile.content.replace(/(\r\n|\r|\n)+$/, '')) {
402
- console.log(`${filename} not changed by gemini`);
403
- continue;
404
- }
405
- (0, fs_1.writeFileSync)(filePath, codeFixFile.content);
386
+ const filePath = codeFixFile.filename.indexOf(basePath) > -1
387
+ ? codeFixFile.filename
388
+ : (0, path_2.join)(basePath, codeFixFile.filename);
389
+ const existing = (0, fs_1.readFileSync)(filePath);
390
+ if (existing.toString().replace(/(\r\n|\r|\n)+$/, '') == codeFixFile.content.replace(/(\r\n|\r|\n)+$/, '')) {
391
+ console.log(`${filename} not changed by gemini`);
392
+ continue;
406
393
  }
394
+ (0, fs_1.writeFileSync)(filePath, codeFixFile.content);
407
395
  const result = await codeGenerator.validateForTarget(basePath);
408
396
  if (result && result.valid) {
409
397
  return;
@@ -421,7 +409,11 @@ class StormCodegen {
421
409
  errorStream.on('data', (evt) => {
422
410
  if (evt.type === 'ERROR_CLASSIFIER') {
423
411
  const eventFileName = this.removePrefix(basePath + '/', evt.payload.filename);
424
- const fix = { error: evt.payload.error, lineNumber: evt.payload.lineNumber, column: evt.payload.column };
412
+ const fix = {
413
+ error: evt.payload.error,
414
+ lineNumber: evt.payload.lineNumber,
415
+ column: evt.payload.column,
416
+ };
425
417
  let existingFixes = fixes.get(eventFileName);
426
418
  if (existingFixes) {
427
419
  existingFixes.push(fix);
@@ -438,24 +430,24 @@ class StormCodegen {
438
430
  const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename); // to compensate when compiler returns absolute path
439
431
  return new Promise(async (resolve, reject) => {
440
432
  const request = {
441
- "language": language,
442
- "sourceFile": {
443
- "filename": filename,
444
- "content": (0, fs_1.readFileSync)(filePath, 'utf8')
433
+ language: language,
434
+ sourceFile: {
435
+ filename: filename,
436
+ content: (0, fs_1.readFileSync)(filePath, 'utf8'),
445
437
  },
446
- "error": error,
447
- "projectFiles": allFiles.map(f => f.filename)
438
+ error: error,
439
+ projectFiles: allFiles.map((f) => f.filename),
448
440
  };
449
441
  const detailsStream = await stormClient_1.stormClient.createErrorDetails(JSON.stringify(request), []);
450
442
  detailsStream.on('data', (evt) => {
451
443
  if (evt.type === 'ERROR_DETAILS') {
452
444
  resolve(evt.payload.files);
453
445
  }
454
- reject(new Error("Error details: Unexpected event [" + evt.type + "]"));
446
+ reject(new Error('Error details: Unexpected event [' + evt.type + ']'));
455
447
  });
456
448
  this.out.on('aborted', () => {
457
449
  detailsStream.abort();
458
- reject("aborted");
450
+ reject(new Error('aborted'));
459
451
  });
460
452
  detailsStream.on('error', (err) => {
461
453
  reject(err);
@@ -466,31 +458,27 @@ class StormCodegen {
466
458
  createFixRequestForFile(basePath, filename, error, filesForContext, allFiles, language) {
467
459
  const files = new Set(filesForContext);
468
460
  files.add(filename);
469
- const requestedFiles = Array.from(files).flatMap(file => {
461
+ const requestedFiles = Array.from(files).flatMap((file) => {
470
462
  if (fs.existsSync(file)) {
471
463
  return file;
472
464
  }
473
465
  // file does not exist - look for similar
474
466
  const candidateName = file.split('/').pop();
475
- return allFiles
476
- .filter(file => file.filename.split('/').pop() === candidateName)
477
- .map(f => f.filename);
467
+ return allFiles.filter((file) => file.filename.split('/').pop() === candidateName).map((f) => f.filename);
478
468
  });
479
469
  const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename);
480
470
  const content = (0, fs_1.readFileSync)(filePath, 'utf8');
481
471
  const affectedLine = this.getErrorLine(error, content);
482
472
  const fixRequest = {
483
- "language": language,
484
- "filename": filename,
485
- "errors": error.error,
486
- "affectedLine": affectedLine,
487
- "projectFiles": requestedFiles.map(filename => {
473
+ language: language,
474
+ filename: filename,
475
+ error: error.error,
476
+ affectedLine: affectedLine,
477
+ projectFiles: requestedFiles.map((filename) => {
488
478
  const filePath = filename.indexOf(basePath) > -1 ? filename : (0, path_2.join)(basePath, filename);
489
479
  const content = (0, fs_1.readFileSync)(filePath, 'utf8');
490
480
  return { filename: filename, content: content };
491
481
  }),
492
- "conversationId": this.conversationId,
493
- "sessionId": (0, uuid_1.v4)()
494
482
  };
495
483
  return JSON.stringify(fixRequest);
496
484
  }
@@ -498,7 +486,7 @@ class StormCodegen {
498
486
  const lines = sourceCode.split('\n');
499
487
  const errorLine = lines[errorDetails.lineNumber - 1];
500
488
  if (!errorLine) {
501
- return "Error: Line number out of range.";
489
+ return 'Error: Line number out of range.';
502
490
  }
503
491
  return errorLine;
504
492
  }
@@ -511,24 +499,36 @@ class StormCodegen {
511
499
  /**
512
500
  * Sends the code to the AI for a fix
513
501
  */
514
- async codeFix(fix, history) {
502
+ async codeFix(blockUri, blockName, fix, history) {
515
503
  return new Promise(async (resolve, reject) => {
516
- const fixStream = await stormClient_1.stormClient.createCodeFix(fix, history);
517
- fixStream.on('data', (evt) => {
518
- if (evt.type === 'CODE_FIX') {
519
- resolve(evt.payload.content.files);
520
- }
521
- reject(new Error("Error details: Unexpected event [" + evt.type + "]"));
522
- });
523
- this.out.on('aborted', () => {
524
- fixStream.abort();
525
- reject("aborted");
526
- });
527
- fixStream.on('error', (err) => {
528
- console.log("error", err);
529
- reject(err);
530
- });
531
- await fixStream.waitForDone();
504
+ try {
505
+ const fixStream = await stormClient_1.stormClient.createCodeFix(fix, history, this.conversationId);
506
+ let resolved = false;
507
+ fixStream.on('data', (evt) => {
508
+ if (this.handleFileEvents(blockUri, blockName, evt)) {
509
+ return;
510
+ }
511
+ if (evt.type === 'CODE_FIX') {
512
+ resolved = true;
513
+ resolve(evt.payload);
514
+ }
515
+ });
516
+ this.out.on('aborted', () => {
517
+ fixStream.abort();
518
+ reject(new Error('aborted'));
519
+ });
520
+ fixStream.on('error', (err) => {
521
+ reject(err);
522
+ });
523
+ fixStream.on('end', () => {
524
+ if (!resolved) {
525
+ reject(new Error('Code fix never returned a valid event'));
526
+ }
527
+ });
528
+ }
529
+ catch (e) {
530
+ reject(e);
531
+ }
532
532
  });
533
533
  }
534
534
  /**
@@ -564,7 +564,13 @@ class StormCodegen {
564
564
  instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
565
565
  },
566
566
  };
567
- return new SimulatedFileDelay(fileEvent, this.out).start();
567
+ if (ENABLE_SIMULATED_DELAY) {
568
+ // Simulate a delay when sending the file
569
+ return new SimulatedFileDelay(fileEvent, this.out).start();
570
+ }
571
+ else {
572
+ this.out.emit('data', fileEvent);
573
+ }
568
574
  });
569
575
  return Promise.all(promises);
570
576
  }
@@ -97,9 +97,9 @@ async function resolveOptions() {
97
97
  }
98
98
  return {
99
99
  serviceKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeService.definition.metadata.name}:${blockTypeService.version}`),
100
- serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)('kapeta/language-target-java-spring-boot:local'), //normalizeKapetaUri(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
100
+ serviceLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${javaLanguage.definition.metadata.name}:${javaLanguage.version}`),
101
101
  frontendKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeFrontend.definition.metadata.name}:${blockTypeFrontend.version}`),
102
- frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)('kapeta/language-target-react-ts:local'), // normalizeKapetaUri(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
102
+ frontendLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${reactLanguage.definition.metadata.name}:${reactLanguage.version}`),
103
103
  cliKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeCli.definition.metadata.name}:${blockTypeCli.version}`),
104
104
  cliLanguage: (0, nodejs_utils_1.normalizeKapetaUri)(`${nodejsLanguage.definition.metadata.name}:${nodejsLanguage.version}`),
105
105
  desktopKind: (0, nodejs_utils_1.normalizeKapetaUri)(`${blockTypeDesktop.definition.metadata.name}:${blockTypeDesktop.version}`),
@@ -159,7 +159,6 @@ class StormEventParser {
159
159
  processEvent(handle, evt) {
160
160
  let blockInfo;
161
161
  this.events.push(evt);
162
- console.log('Processing event: %s', evt.type);
163
162
  switch (evt.type) {
164
163
  case 'CREATE_PLAN_PROPERTIES':
165
164
  this.planName = evt.payload.name;
@@ -292,7 +291,9 @@ class StormEventParser {
292
291
  };
293
292
  }
294
293
  const clientTypes = kaplang_core_1.DSLDataTypeParser.parse(clientConsumerBlock.content.spec.entities.source.value, { ignoreSemantics: true });
295
- const apiTypes = kaplang_core_1.DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, { ignoreSemantics: true });
294
+ const apiTypes = kaplang_core_1.DSLDataTypeParser.parse(apiProviderBlock.content.spec.entities?.source?.value, {
295
+ ignoreSemantics: true,
296
+ });
296
297
  apiTypes.forEach((apiType) => {
297
298
  if (clientTypes.some((clientType) => clientType.name === apiType.name)) {
298
299
  // Already exists
@@ -111,9 +111,8 @@ export interface StormEventCodeFix {
111
111
  reason: string;
112
112
  created: number;
113
113
  payload: {
114
- content: {
115
- files: StormEventErrorDetailsFile[];
116
- };
114
+ filename: string;
115
+ content: string;
117
116
  };
118
117
  }
119
118
  export interface StormEventErrorClassifierInfo {
@@ -210,6 +209,24 @@ export interface StormEventBlockReady {
210
209
  instanceId: string;
211
210
  };
212
211
  }
212
+ export declare enum StormEventBlockStatusType {
213
+ QA = "QA",
214
+ FIXING = "FIXING",
215
+ PLANNING_FIX = "PLANNING_FIX",
216
+ FIX_DONE = "FIX_DONE",
217
+ BUILDING = "BUILDING"
218
+ }
219
+ export interface StormEventBlockStatus {
220
+ type: 'BLOCK_STATUS';
221
+ reason: string;
222
+ created: number;
223
+ payload: {
224
+ status: StormEventBlockStatusType;
225
+ blockName: string;
226
+ blockRef: string;
227
+ instanceId: string;
228
+ };
229
+ }
213
230
  export interface StormEventDone {
214
231
  type: 'DONE';
215
232
  created: number;
@@ -223,7 +240,8 @@ export interface StormEventDefinitionChange {
223
240
  export declare enum StormEventPhaseType {
224
241
  META = "META",
225
242
  DEFINITIONS = "DEFINITIONS",
226
- IMPLEMENTATION = "IMPLEMENTATION"
243
+ IMPLEMENTATION = "IMPLEMENTATION",
244
+ QA = "QA"
227
245
  }
228
246
  export interface StormEventPhases {
229
247
  type: 'PHASE_START' | 'PHASE_END';
@@ -232,4 +250,4 @@ export interface StormEventPhases {
232
250
  phaseType: StormEventPhaseType;
233
251
  };
234
252
  }
235
- export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases;
253
+ export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFileLogical | StormEventFileState | StormEventFileDone | StormEventFileChunk | StormEventDone | StormEventDefinitionChange | StormEventErrorClassifier | StormEventCodeFix | StormEventErrorDetails | StormEventBlockReady | StormEventPhases | StormEventBlockStatus;
@@ -1,9 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StormEventPhaseType = void 0;
3
+ exports.StormEventPhaseType = exports.StormEventBlockStatusType = void 0;
4
+ var StormEventBlockStatusType;
5
+ (function (StormEventBlockStatusType) {
6
+ StormEventBlockStatusType["QA"] = "QA";
7
+ StormEventBlockStatusType["FIXING"] = "FIXING";
8
+ StormEventBlockStatusType["PLANNING_FIX"] = "PLANNING_FIX";
9
+ StormEventBlockStatusType["FIX_DONE"] = "FIX_DONE";
10
+ StormEventBlockStatusType["BUILDING"] = "BUILDING";
11
+ })(StormEventBlockStatusType || (exports.StormEventBlockStatusType = StormEventBlockStatusType = {}));
4
12
  var StormEventPhaseType;
5
13
  (function (StormEventPhaseType) {
6
14
  StormEventPhaseType["META"] = "META";
7
15
  StormEventPhaseType["DEFINITIONS"] = "DEFINITIONS";
8
16
  StormEventPhaseType["IMPLEMENTATION"] = "IMPLEMENTATION";
17
+ StormEventPhaseType["QA"] = "QA";
9
18
  })(StormEventPhaseType || (exports.StormEventPhaseType = StormEventPhaseType = {}));
@@ -32,7 +32,6 @@ class StormClient {
32
32
  }
33
33
  if (body.conversationId) {
34
34
  headers[exports.ConversationIdHeader] = body.conversationId;
35
- console.log('Setting ConversationIdHeader', headers[exports.ConversationIdHeader]);
36
35
  }
37
36
  return {
38
37
  url,
@@ -66,7 +65,12 @@ class StormClient {
66
65
  out.end();
67
66
  });
68
67
  out.on('aborted', () => {
69
- abort.abort();
68
+ try {
69
+ abort.abort();
70
+ }
71
+ catch (e) {
72
+ console.warn('Error aborting stream', e);
73
+ }
70
74
  });
71
75
  return out;
72
76
  }
@@ -11,6 +11,7 @@ export declare class StormStream extends EventEmitter {
11
11
  private conversationId;
12
12
  private lines;
13
13
  private aborted;
14
+ private done;
14
15
  constructor(prompt?: string, conversationId?: string | null);
15
16
  getConversationId(): string;
16
17
  isAborted(): boolean;
@@ -10,6 +10,7 @@ class StormStream extends node_events_1.EventEmitter {
10
10
  conversationId = '';
11
11
  lines = [];
12
12
  aborted = false;
13
+ done = false;
13
14
  constructor(prompt = '', conversationId) {
14
15
  super();
15
16
  this.conversationId = conversationId || '';
@@ -34,6 +35,7 @@ class StormStream extends node_events_1.EventEmitter {
34
35
  }
35
36
  }
36
37
  end() {
38
+ this.done = true;
37
39
  this.emit('end');
38
40
  }
39
41
  on(event, listener) {
@@ -43,6 +45,9 @@ class StormStream extends node_events_1.EventEmitter {
43
45
  return super.emit(eventName, ...args);
44
46
  }
45
47
  waitForDone() {
48
+ if (this.done) {
49
+ return Promise.resolve();
50
+ }
46
51
  return new Promise((resolve, reject) => {
47
52
  const errorHandler = (err) => {
48
53
  this.removeListener('error', errorHandler);
@@ -54,8 +59,8 @@ class StormStream extends node_events_1.EventEmitter {
54
59
  this.removeListener('end', endHandler);
55
60
  resolve();
56
61
  };
57
- this.once('error', errorHandler);
58
- this.once('end', endHandler);
62
+ this.on('error', errorHandler);
63
+ this.on('end', endHandler);
59
64
  });
60
65
  }
61
66
  abort() {
@@ -63,6 +68,7 @@ class StormStream extends node_events_1.EventEmitter {
63
68
  return;
64
69
  }
65
70
  this.aborted = true;
71
+ this.done = true;
66
72
  this.emit('aborted');
67
73
  }
68
74
  }
@@ -25,6 +25,7 @@ export declare class StormCodegen {
25
25
  * Generates the code for a block and sends it to the AI
26
26
  */
27
27
  private processBlockCode;
28
+ private emitBlockStatus;
28
29
  private verifyAndFixCode;
29
30
  private tryToFixFile;
30
31
  private classifyErrors;