@kapeta/local-cluster-service 0.54.0 → 0.54.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,10 @@
1
+ ## [0.54.1](https://github.com/kapetacom/local-cluster-service/compare/v0.54.0...v0.54.1) (2024-06-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * handle screen events by adding a meta-file to context + routes ([#180](https://github.com/kapetacom/local-cluster-service/issues/180)) ([69d67f8](https://github.com/kapetacom/local-cluster-service/commit/69d67f84fd7a373d49f5c20ff9057d8b2baa620a))
7
+
1
8
  # [0.54.0](https://github.com/kapetacom/local-cluster-service/compare/v0.53.5...v0.54.0) (2024-06-17)
2
9
 
3
10
 
@@ -242,7 +242,6 @@ class StormCodegen {
242
242
  file.type !== codegen_1.AIFileTypes.WEB_SCREEN &&
243
243
  file.type !== codegen_1.AIFileTypes.WEB_ROUTER);
244
244
  const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
245
- const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
246
245
  const screenFiles = [];
247
246
  let filteredEvents = [];
248
247
  for (const event of this.events) {
@@ -252,65 +251,63 @@ class StormCodegen {
252
251
  }
253
252
  }
254
253
  const screenEvents = [];
255
- // generate screens
256
- const screenStream = await stormClient_1.stormClient.listScreens({
257
- events: filteredEvents,
258
- templates: uiTemplates,
259
- context: relevantFiles,
260
- blockName: block.aiName,
261
- prompt: this.userPrompt,
262
- });
263
- screenStream.on('data', (evt) => {
264
- if (evt.type === 'SCREEN') {
265
- screenEvents.push(evt);
266
- }
267
- this.handleUiOutput(blockUri, block.aiName, evt);
254
+ const getScreenEventsFile = () => ({
255
+ content: JSON.stringify(screenEvents),
256
+ filename: '<screens>.json',
257
+ type: codegen_1.AIFileTypes.CONFIG,
258
+ mode: codegen_1.MODE_WRITE_NEVER,
259
+ permissions: '0644',
268
260
  });
269
- this.out.on('aborted', () => {
270
- screenStream.abort();
271
- });
272
- await screenStream.waitForDone();
273
- // screenfiles
274
- const screenTemplates = screenEvents
275
- .map((screenEvent) => ({
276
- ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
277
- filename: screenEvent.payload.filename,
278
- }))
279
- .filter((tpl) => !!tpl.content);
280
- await Promise.all(screenTemplates.concat(webRouters).map(async (template) => {
281
- const payload = {
261
+ const uiEvents = [];
262
+ // generate screens
263
+ if (uiTemplates.length) {
264
+ const screenStream = await stormClient_1.stormClient.listScreens({
282
265
  events: filteredEvents,
266
+ templates: uiTemplates,
267
+ context: relevantFiles,
283
268
  blockName: block.aiName,
284
- filename: template.filename,
285
- template: template,
286
- context: relevantFiles.concat([
287
- {
288
- type: codegen_1.AIFileTypes.INSTRUCTIONS,
289
- mode: codegen_1.MODE_CREATE_ONLY,
290
- permissions: '0644',
291
- filename: '<screens>.md',
292
- content: `
293
- # Generated screens
294
-
295
- ${JSON.stringify({ screenEvents })}
296
-
297
- `,
298
- },
299
- ]),
300
269
  prompt: this.userPrompt,
301
- };
302
- const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
303
- uiStream.on('data', (evt) => {
304
- const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
305
- if (uiFile != undefined) {
306
- screenFiles.push(uiFile);
270
+ });
271
+ screenStream.on('data', (evt) => {
272
+ if (evt.type === 'SCREEN') {
273
+ screenEvents.push(evt);
307
274
  }
275
+ this.handleUiOutput(blockUri, block.aiName, evt);
308
276
  });
309
277
  this.out.on('aborted', () => {
310
- uiStream.abort();
278
+ screenStream.abort();
311
279
  });
312
- await uiStream.waitForDone();
313
- }));
280
+ await screenStream.waitForDone();
281
+ // screenfiles
282
+ const screenTemplates = screenEvents
283
+ .map((screenEvent) => ({
284
+ ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
285
+ filename: screenEvent.payload.filename,
286
+ }))
287
+ .filter((tpl) => !!tpl.content);
288
+ await Promise.all(screenTemplates.map(async (template) => {
289
+ const payload = {
290
+ events: filteredEvents,
291
+ blockName: block.aiName,
292
+ filename: template.filename,
293
+ template: template,
294
+ context: relevantFiles.concat([getScreenEventsFile()]),
295
+ prompt: this.userPrompt,
296
+ };
297
+ const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
298
+ uiStream.on('data', (evt) => {
299
+ const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
300
+ if (uiFile != undefined) {
301
+ screenFiles.push(uiFile);
302
+ }
303
+ uiEvents.push(evt);
304
+ });
305
+ this.out.on('aborted', () => {
306
+ uiStream.abort();
307
+ });
308
+ await uiStream.waitForDone();
309
+ }));
310
+ }
314
311
  if (this.isAborted()) {
315
312
  return;
316
313
  }
@@ -324,6 +321,24 @@ ${JSON.stringify({ screenEvents })}
324
321
  type: codegen_1.AIFileTypes.WEB_SCREEN,
325
322
  };
326
323
  });
324
+ allFiles.push(...screenFilesConverted);
325
+ const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
326
+ await Promise.all(webRouters.map(async (webRouter) => {
327
+ const payload = {
328
+ filename: webRouter.filename,
329
+ template: webRouter,
330
+ context: screenFilesConverted.concat([getScreenEventsFile()]),
331
+ prompt: this.userPrompt,
332
+ };
333
+ const stream = await stormClient_1.stormClient.generateCode(payload);
334
+ stream.on('data', (evt) => {
335
+ this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
336
+ });
337
+ this.out.on('aborted', () => {
338
+ stream.abort();
339
+ });
340
+ await stream.waitForDone();
341
+ }));
327
342
  // Gather the context files for implementation. These will be all be passed to the AI
328
343
  const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
329
344
  // Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
@@ -335,6 +350,7 @@ ${JSON.stringify({ screenEvents })}
335
350
  return;
336
351
  }
337
352
  for (const screenFile of screenFilesConverted) {
353
+ // this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
338
354
  const filePath = (0, path_2.join)(basePath, screenFile.filename);
339
355
  await (0, promises_1.writeFile)(filePath, screenFile.content);
340
356
  }
@@ -346,12 +362,13 @@ ${JSON.stringify({ screenEvents })}
346
362
  const filePath = (0, path_2.join)(basePath, serviceFile.filename);
347
363
  await (0, promises_1.writeFile)(filePath, serviceFile.content);
348
364
  }
365
+ // Write again after modifications
366
+ for (const webRouterFile of webRouters) {
367
+ const filePath = (0, path_2.join)(basePath, webRouterFile.filename);
368
+ await (0, promises_1.writeFile)(filePath, webRouterFile.content);
369
+ }
349
370
  const kapetaYmlPath = (0, path_2.join)(basePath, 'kapeta.yml');
350
371
  await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
351
- for (const screenFile of screenFiles) {
352
- const filePath = (0, path_2.join)(basePath, screenFile.payload.filename);
353
- await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
354
- }
355
372
  const blockRef = block.uri;
356
373
  this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.QA);
357
374
  const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
@@ -13,6 +13,7 @@ declare class StormClient {
13
13
  createErrorClassification(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
14
14
  createCodeFix(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
15
15
  createErrorDetails(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
16
+ generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
16
17
  }
17
18
  export declare const stormClient: StormClient;
18
19
  export {};
@@ -116,5 +116,11 @@ class StormClient {
116
116
  prompt,
117
117
  });
118
118
  }
119
+ generateCode(prompt, history, conversationId) {
120
+ return this.send('/v2/code/generate', {
121
+ conversationId: conversationId,
122
+ prompt,
123
+ });
124
+ }
119
125
  }
120
126
  exports.stormClient = new StormClient();
@@ -242,7 +242,6 @@ class StormCodegen {
242
242
  file.type !== codegen_1.AIFileTypes.WEB_SCREEN &&
243
243
  file.type !== codegen_1.AIFileTypes.WEB_ROUTER);
244
244
  const uiTemplates = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_SCREEN);
245
- const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
246
245
  const screenFiles = [];
247
246
  let filteredEvents = [];
248
247
  for (const event of this.events) {
@@ -252,65 +251,63 @@ class StormCodegen {
252
251
  }
253
252
  }
254
253
  const screenEvents = [];
255
- // generate screens
256
- const screenStream = await stormClient_1.stormClient.listScreens({
257
- events: filteredEvents,
258
- templates: uiTemplates,
259
- context: relevantFiles,
260
- blockName: block.aiName,
261
- prompt: this.userPrompt,
262
- });
263
- screenStream.on('data', (evt) => {
264
- if (evt.type === 'SCREEN') {
265
- screenEvents.push(evt);
266
- }
267
- this.handleUiOutput(blockUri, block.aiName, evt);
254
+ const getScreenEventsFile = () => ({
255
+ content: JSON.stringify(screenEvents),
256
+ filename: '<screens>.json',
257
+ type: codegen_1.AIFileTypes.CONFIG,
258
+ mode: codegen_1.MODE_WRITE_NEVER,
259
+ permissions: '0644',
268
260
  });
269
- this.out.on('aborted', () => {
270
- screenStream.abort();
271
- });
272
- await screenStream.waitForDone();
273
- // screenfiles
274
- const screenTemplates = screenEvents
275
- .map((screenEvent) => ({
276
- ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
277
- filename: screenEvent.payload.filename,
278
- }))
279
- .filter((tpl) => !!tpl.content);
280
- await Promise.all(screenTemplates.concat(webRouters).map(async (template) => {
281
- const payload = {
261
+ const uiEvents = [];
262
+ // generate screens
263
+ if (uiTemplates.length) {
264
+ const screenStream = await stormClient_1.stormClient.listScreens({
282
265
  events: filteredEvents,
266
+ templates: uiTemplates,
267
+ context: relevantFiles,
283
268
  blockName: block.aiName,
284
- filename: template.filename,
285
- template: template,
286
- context: relevantFiles.concat([
287
- {
288
- type: codegen_1.AIFileTypes.INSTRUCTIONS,
289
- mode: codegen_1.MODE_CREATE_ONLY,
290
- permissions: '0644',
291
- filename: '<screens>.md',
292
- content: `
293
- # Generated screens
294
-
295
- ${JSON.stringify({ screenEvents })}
296
-
297
- `,
298
- },
299
- ]),
300
269
  prompt: this.userPrompt,
301
- };
302
- const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
303
- uiStream.on('data', (evt) => {
304
- const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
305
- if (uiFile != undefined) {
306
- screenFiles.push(uiFile);
270
+ });
271
+ screenStream.on('data', (evt) => {
272
+ if (evt.type === 'SCREEN') {
273
+ screenEvents.push(evt);
307
274
  }
275
+ this.handleUiOutput(blockUri, block.aiName, evt);
308
276
  });
309
277
  this.out.on('aborted', () => {
310
- uiStream.abort();
278
+ screenStream.abort();
311
279
  });
312
- await uiStream.waitForDone();
313
- }));
280
+ await screenStream.waitForDone();
281
+ // screenfiles
282
+ const screenTemplates = screenEvents
283
+ .map((screenEvent) => ({
284
+ ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
285
+ filename: screenEvent.payload.filename,
286
+ }))
287
+ .filter((tpl) => !!tpl.content);
288
+ await Promise.all(screenTemplates.map(async (template) => {
289
+ const payload = {
290
+ events: filteredEvents,
291
+ blockName: block.aiName,
292
+ filename: template.filename,
293
+ template: template,
294
+ context: relevantFiles.concat([getScreenEventsFile()]),
295
+ prompt: this.userPrompt,
296
+ };
297
+ const uiStream = await stormClient_1.stormClient.createUIImplementation(payload);
298
+ uiStream.on('data', (evt) => {
299
+ const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
300
+ if (uiFile != undefined) {
301
+ screenFiles.push(uiFile);
302
+ }
303
+ uiEvents.push(evt);
304
+ });
305
+ this.out.on('aborted', () => {
306
+ uiStream.abort();
307
+ });
308
+ await uiStream.waitForDone();
309
+ }));
310
+ }
314
311
  if (this.isAborted()) {
315
312
  return;
316
313
  }
@@ -324,6 +321,24 @@ ${JSON.stringify({ screenEvents })}
324
321
  type: codegen_1.AIFileTypes.WEB_SCREEN,
325
322
  };
326
323
  });
324
+ allFiles.push(...screenFilesConverted);
325
+ const webRouters = allFiles.filter((file) => file.type === codegen_1.AIFileTypes.WEB_ROUTER);
326
+ await Promise.all(webRouters.map(async (webRouter) => {
327
+ const payload = {
328
+ filename: webRouter.filename,
329
+ template: webRouter,
330
+ context: screenFilesConverted.concat([getScreenEventsFile()]),
331
+ prompt: this.userPrompt,
332
+ };
333
+ const stream = await stormClient_1.stormClient.generateCode(payload);
334
+ stream.on('data', (evt) => {
335
+ this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
336
+ });
337
+ this.out.on('aborted', () => {
338
+ stream.abort();
339
+ });
340
+ await stream.waitForDone();
341
+ }));
327
342
  // Gather the context files for implementation. These will be all be passed to the AI
328
343
  const contextFiles = relevantFiles.filter((file) => ![codegen_1.AIFileTypes.SERVICE, codegen_1.AIFileTypes.WEB_SCREEN, codegen_1.AIFileTypes.WEB_ROUTER].includes(file.type));
329
344
  // Send the service and UI templates to the AI. These will be sent one-by-one in addition to the context files
@@ -335,6 +350,7 @@ ${JSON.stringify({ screenEvents })}
335
350
  return;
336
351
  }
337
352
  for (const screenFile of screenFilesConverted) {
353
+ // this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
338
354
  const filePath = (0, path_2.join)(basePath, screenFile.filename);
339
355
  await (0, promises_1.writeFile)(filePath, screenFile.content);
340
356
  }
@@ -346,12 +362,13 @@ ${JSON.stringify({ screenEvents })}
346
362
  const filePath = (0, path_2.join)(basePath, serviceFile.filename);
347
363
  await (0, promises_1.writeFile)(filePath, serviceFile.content);
348
364
  }
365
+ // Write again after modifications
366
+ for (const webRouterFile of webRouters) {
367
+ const filePath = (0, path_2.join)(basePath, webRouterFile.filename);
368
+ await (0, promises_1.writeFile)(filePath, webRouterFile.content);
369
+ }
349
370
  const kapetaYmlPath = (0, path_2.join)(basePath, 'kapeta.yml');
350
371
  await (0, promises_1.writeFile)(kapetaYmlPath, yaml_1.default.stringify(block.content));
351
- for (const screenFile of screenFiles) {
352
- const filePath = (0, path_2.join)(basePath, screenFile.payload.filename);
353
- await (0, promises_1.writeFile)(filePath, screenFile.payload.content);
354
- }
355
372
  const blockRef = block.uri;
356
373
  this.emitBlockStatus(blockUri, block.aiName, events_1.StormEventBlockStatusType.QA);
357
374
  const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
@@ -13,6 +13,7 @@ declare class StormClient {
13
13
  createErrorClassification(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
14
14
  createCodeFix(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
15
15
  createErrorDetails(prompt: string, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
16
+ generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string): Promise<StormStream>;
16
17
  }
17
18
  export declare const stormClient: StormClient;
18
19
  export {};
@@ -116,5 +116,11 @@ class StormClient {
116
116
  prompt,
117
117
  });
118
118
  }
119
+ generateCode(prompt, history, conversationId) {
120
+ return this.send('/v2/code/generate', {
121
+ conversationId: conversationId,
122
+ prompt,
123
+ });
124
+ }
119
125
  }
120
126
  exports.stormClient = new StormClient();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.54.0",
3
+ "version": "0.54.1",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -12,6 +12,7 @@ import {
12
12
  GeneratedFile,
13
13
  GeneratedResult,
14
14
  MODE_CREATE_ONLY,
15
+ MODE_WRITE_NEVER,
15
16
  } from '@kapeta/codegen';
16
17
 
17
18
  import { BlockDefinition } from '@kapeta/schemas';
@@ -277,7 +278,6 @@ export class StormCodegen {
277
278
  file.type !== AIFileTypes.WEB_ROUTER
278
279
  );
279
280
  const uiTemplates = allFiles.filter((file) => file.type === AIFileTypes.WEB_SCREEN);
280
- const webRouters = allFiles.filter((file) => file.type === AIFileTypes.WEB_ROUTER);
281
281
  const screenFiles: StormEventFileDone[] = [];
282
282
  let filteredEvents = [] as StormEvent[];
283
283
  for (const event of this.events) {
@@ -288,75 +288,74 @@ export class StormCodegen {
288
288
  }
289
289
 
290
290
  const screenEvents: StormEventScreen[] = [];
291
- // generate screens
292
- const screenStream = await stormClient.listScreens({
293
- events: filteredEvents,
294
- templates: uiTemplates,
295
- context: relevantFiles,
296
- blockName: block.aiName,
297
- prompt: this.userPrompt,
298
- });
299
- screenStream.on('data', (evt) => {
300
- if (evt.type === 'SCREEN') {
301
- screenEvents.push(evt);
302
- }
303
- this.handleUiOutput(blockUri, block.aiName, evt);
304
- });
305
-
306
- this.out.on('aborted', () => {
307
- screenStream.abort();
291
+ const getScreenEventsFile = () => ({
292
+ content: JSON.stringify(screenEvents),
293
+ filename: '<screens>.json',
294
+ type: AIFileTypes.CONFIG,
295
+ mode: MODE_WRITE_NEVER,
296
+ permissions: '0644',
308
297
  });
298
+ const uiEvents = [];
309
299
 
310
- await screenStream.waitForDone();
311
-
312
- // screenfiles
313
- const screenTemplates = screenEvents
314
- .map((screenEvent) => ({
315
- ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
316
- filename: screenEvent.payload.filename,
317
- }))
318
- .filter((tpl): tpl is StormFileInfo => !!tpl.content);
319
-
320
- await Promise.all(
321
- screenTemplates.concat(webRouters).map(async (template) => {
322
- const payload = {
323
- events: filteredEvents,
324
- blockName: block.aiName,
325
- filename: template.filename,
326
- template: template,
327
- context: relevantFiles.concat([
328
- {
329
- type: AIFileTypes.INSTRUCTIONS,
330
- mode: MODE_CREATE_ONLY,
331
- permissions: '0644',
332
- filename: '<screens>.md',
333
- content: `
334
- # Generated screens
335
-
336
- ${JSON.stringify({ screenEvents })}
337
-
338
- `,
339
- },
340
- ]),
341
- prompt: this.userPrompt,
342
- };
343
-
344
- const uiStream = await stormClient.createUIImplementation(payload);
345
-
346
- uiStream.on('data', (evt) => {
347
- const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
348
- if (uiFile != undefined) {
349
- screenFiles.push(uiFile);
350
- }
351
- });
300
+ // generate screens
301
+ if (uiTemplates.length) {
302
+ const screenStream = await stormClient.listScreens({
303
+ events: filteredEvents,
304
+ templates: uiTemplates,
305
+ context: relevantFiles,
306
+ blockName: block.aiName,
307
+ prompt: this.userPrompt,
308
+ });
309
+ screenStream.on('data', (evt) => {
310
+ if (evt.type === 'SCREEN') {
311
+ screenEvents.push(evt);
312
+ }
313
+ this.handleUiOutput(blockUri, block.aiName, evt);
314
+ });
352
315
 
353
- this.out.on('aborted', () => {
354
- uiStream.abort();
355
- });
316
+ this.out.on('aborted', () => {
317
+ screenStream.abort();
318
+ });
356
319
 
357
- await uiStream.waitForDone();
358
- })
359
- );
320
+ await screenStream.waitForDone();
321
+
322
+ // screenfiles
323
+ const screenTemplates = screenEvents
324
+ .map((screenEvent) => ({
325
+ ...uiTemplates.find((template) => template.filename.endsWith(screenEvent.payload.template)),
326
+ filename: screenEvent.payload.filename,
327
+ }))
328
+ .filter((tpl): tpl is StormFileInfo => !!tpl.content);
329
+
330
+ await Promise.all(
331
+ screenTemplates.map(async (template) => {
332
+ const payload = {
333
+ events: filteredEvents,
334
+ blockName: block.aiName,
335
+ filename: template.filename,
336
+ template: template,
337
+ context: relevantFiles.concat([getScreenEventsFile()]),
338
+ prompt: this.userPrompt,
339
+ };
340
+
341
+ const uiStream = await stormClient.createUIImplementation(payload);
342
+
343
+ uiStream.on('data', (evt) => {
344
+ const uiFile = this.handleUiOutput(blockUri, block.aiName, evt);
345
+ if (uiFile != undefined) {
346
+ screenFiles.push(uiFile);
347
+ }
348
+ uiEvents.push(evt);
349
+ });
350
+
351
+ this.out.on('aborted', () => {
352
+ uiStream.abort();
353
+ });
354
+
355
+ await uiStream.waitForDone();
356
+ })
357
+ );
358
+ }
360
359
 
361
360
  if (this.isAborted()) {
362
361
  return;
@@ -372,6 +371,31 @@ ${JSON.stringify({ screenEvents })}
372
371
  type: AIFileTypes.WEB_SCREEN,
373
372
  };
374
373
  });
374
+ allFiles.push(...screenFilesConverted);
375
+
376
+ const webRouters = allFiles.filter((file) => file.type === AIFileTypes.WEB_ROUTER);
377
+ await Promise.all(
378
+ webRouters.map(async (webRouter) => {
379
+ const payload = {
380
+ filename: webRouter.filename,
381
+ template: webRouter,
382
+ context: screenFilesConverted.concat([getScreenEventsFile()]),
383
+ prompt: this.userPrompt,
384
+ };
385
+
386
+ const stream = await stormClient.generateCode(payload);
387
+
388
+ stream.on('data', (evt) => {
389
+ this.handleTemplateFileOutput(blockUri, block.aiName, webRouter, evt);
390
+ });
391
+
392
+ this.out.on('aborted', () => {
393
+ stream.abort();
394
+ });
395
+
396
+ await stream.waitForDone();
397
+ })
398
+ );
375
399
 
376
400
  // Gather the context files for implementation. These will be all be passed to the AI
377
401
  const contextFiles: StormFileInfo[] = relevantFiles.filter(
@@ -395,6 +419,7 @@ ${JSON.stringify({ screenEvents })}
395
419
  }
396
420
 
397
421
  for (const screenFile of screenFilesConverted) {
422
+ // this.emitFile(blockUri, block.aiName, screenFile.filename, screenFile.content);
398
423
  const filePath = join(basePath, screenFile.filename);
399
424
  await writeFile(filePath, screenFile.content);
400
425
  }
@@ -409,20 +434,21 @@ ${JSON.stringify({ screenEvents })}
409
434
  await writeFile(filePath, serviceFile.content);
410
435
  }
411
436
 
412
- const kapetaYmlPath = join(basePath, 'kapeta.yml');
413
- await writeFile(kapetaYmlPath, YAML.stringify(block.content as BlockDefinition));
414
-
415
- for (const screenFile of screenFiles) {
416
- const filePath = join(basePath, screenFile.payload.filename);
417
- await writeFile(filePath, screenFile.payload.content);
437
+ // Write again after modifications
438
+ for (const webRouterFile of webRouters) {
439
+ const filePath = join(basePath, webRouterFile.filename);
440
+ await writeFile(filePath, webRouterFile.content);
418
441
  }
419
442
 
443
+ const kapetaYmlPath = join(basePath, 'kapeta.yml');
444
+ await writeFile(kapetaYmlPath, YAML.stringify(block.content));
445
+
420
446
  const blockRef = block.uri;
421
447
 
422
448
  this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.QA);
423
449
 
424
450
  const filesToBeFixed = serviceFiles.concat(contextFiles).concat(screenFilesConverted);
425
- const codeGenerator = new BlockCodeGenerator(block.content as BlockDefinition);
451
+ const codeGenerator = new BlockCodeGenerator(block.content);
426
452
 
427
453
  this.emitBlockStatus(blockUri, block.aiName, StormEventBlockStatusType.BUILDING);
428
454
  await this.verifyAndFixCode(blockUri, block.aiName, codeGenerator, basePath, filesToBeFixed, allFiles);
@@ -881,6 +907,7 @@ ${JSON.stringify({ screenEvents })}
881
907
  type,
882
908
  };
883
909
  });
910
+
884
911
  return allFiles;
885
912
  }
886
913
 
@@ -154,6 +154,13 @@ class StormClient {
154
154
  prompt,
155
155
  });
156
156
  }
157
+
158
+ public generateCode(prompt: StormFileImplementationPrompt, history?: ConversationItem[], conversationId?: string) {
159
+ return this.send('/v2/code/generate', {
160
+ conversationId: conversationId,
161
+ prompt,
162
+ });
163
+ }
157
164
  }
158
165
 
159
166
  export const stormClient = new StormClient();