@kapeta/local-cluster-service 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/src/storm/codegen.d.ts +5 -1
  3. package/dist/cjs/src/storm/codegen.js +68 -18
  4. package/dist/cjs/src/storm/event-parser.d.ts +5 -5
  5. package/dist/cjs/src/storm/event-parser.js +50 -33
  6. package/dist/cjs/src/storm/events.d.ts +8 -2
  7. package/dist/cjs/src/storm/events.js +0 -4
  8. package/dist/cjs/src/storm/routes.js +20 -29
  9. package/dist/cjs/src/storm/stormClient.d.ts +2 -2
  10. package/dist/cjs/src/storm/stormClient.js +0 -7
  11. package/dist/cjs/src/storm/stream.d.ts +7 -0
  12. package/dist/cjs/test/storm/event-parser.test.d.ts +5 -0
  13. package/dist/cjs/test/storm/event-parser.test.js +169 -0
  14. package/dist/esm/src/storm/codegen.d.ts +5 -1
  15. package/dist/esm/src/storm/codegen.js +68 -18
  16. package/dist/esm/src/storm/event-parser.d.ts +5 -5
  17. package/dist/esm/src/storm/event-parser.js +50 -33
  18. package/dist/esm/src/storm/events.d.ts +8 -2
  19. package/dist/esm/src/storm/events.js +0 -4
  20. package/dist/esm/src/storm/routes.js +20 -29
  21. package/dist/esm/src/storm/stormClient.d.ts +2 -2
  22. package/dist/esm/src/storm/stormClient.js +0 -7
  23. package/dist/esm/src/storm/stream.d.ts +7 -0
  24. package/dist/esm/test/storm/event-parser.test.d.ts +5 -0
  25. package/dist/esm/test/storm/event-parser.test.js +169 -0
  26. package/package.json +3 -1
  27. package/src/storm/codegen.ts +83 -27
  28. package/src/storm/event-parser.ts +68 -47
  29. package/src/storm/events.ts +10 -2
  30. package/src/storm/routes.ts +42 -59
  31. package/src/storm/stormClient.ts +3 -11
  32. package/src/storm/stream.ts +8 -0
  33. package/test/storm/event-parser.test.ts +190 -0
@@ -21,17 +21,17 @@ router.post('/:handle/all', async (req, res) => {
21
21
  try {
22
22
  const stormOptions = await (0, event_parser_1.resolveOptions)();
23
23
  const eventParser = new event_parser_1.StormEventParser(stormOptions);
24
- console.log('Got prompt', req.stringBody);
25
24
  const aiRequest = JSON.parse(req.stringBody ?? '{}');
26
25
  const metaStream = await stormClient_1.stormClient.createMetadata(aiRequest.prompt, aiRequest.history);
27
26
  res.set('Content-Type', 'application/x-ndjson');
28
27
  metaStream.on('data', (data) => {
29
- eventParser.addEvent(data);
28
+ const result = eventParser.addEvent(req.params.handle, data);
29
+ sendDefinitions(res, result);
30
30
  });
31
31
  await streamStormPartialResponse(metaStream, res);
32
32
  if (!eventParser.isValid()) {
33
33
  // We can't continue if the meta stream is invalid
34
- res.write({
34
+ sendEvent(res, {
35
35
  type: 'ERROR_INTERNAL',
36
36
  payload: { error: eventParser.getError() },
37
37
  reason: 'Failed to generate system',
@@ -41,8 +41,8 @@ router.post('/:handle/all', async (req, res) => {
41
41
  return;
42
42
  }
43
43
  const result = eventParser.toResult(handle);
44
- console.log('RESULT\n', JSON.stringify(result, null, 2));
45
- const stormCodegen = new codegen_1.StormCodegen(aiRequest.prompt, result.blocks);
44
+ sendDefinitions(res, result);
45
+ const stormCodegen = new codegen_1.StormCodegen(aiRequest.prompt, result.blocks, eventParser.getEvents());
46
46
  const codegenStream = streamStormPartialResponse(stormCodegen.getStream(), res);
47
47
  await stormCodegen.process();
48
48
  await codegenStream;
@@ -52,42 +52,30 @@ router.post('/:handle/all', async (req, res) => {
52
52
  sendError(err, res);
53
53
  }
54
54
  });
55
- router.post('/metadata', async (req, res) => {
56
- const aiRequest = JSON.parse(req.stringBody ?? '{}');
57
- const result = await stormClient_1.stormClient.createMetadata(aiRequest.prompt, aiRequest.history);
58
- await streamStormResponse(result, res);
59
- });
60
- router.post('/services/implement', async (req, res) => {
61
- const aiRequest = JSON.parse(req.stringBody ?? '{}');
62
- const result = await stormClient_1.stormClient.createServiceImplementation(aiRequest.prompt, aiRequest.history);
63
- await streamStormResponse(result, res);
64
- });
65
- router.post('/ui/implement', async (req, res) => {
66
- const aiRequest = JSON.parse(req.stringBody ?? '{}');
67
- const result = await stormClient_1.stormClient.createUIImplementation(aiRequest.prompt, aiRequest.history);
68
- await streamStormResponse(result, res);
69
- });
70
- async function streamStormResponse(result, res) {
71
- res.set('Content-Type', 'application/x-ndjson');
72
- await streamStormPartialResponse(result, res);
73
- sendDone(res);
55
+ function sendDefinitions(res, result) {
56
+ sendEvent(res, {
57
+ type: 'DEFINITION_CHANGE',
58
+ payload: result,
59
+ reason: 'Updates to definition',
60
+ created: Date.now(),
61
+ });
74
62
  }
75
63
  function sendDone(res) {
76
- res.write(JSON.stringify({
64
+ sendEvent(res, {
77
65
  type: 'DONE',
78
66
  created: Date.now(),
79
- }) + '\n');
67
+ });
80
68
  res.end();
81
69
  }
82
70
  function sendError(err, res) {
83
71
  console.error('Failed to send prompt', err);
84
72
  if (res.headersSent) {
85
- res.write(JSON.stringify({
73
+ sendEvent(res, {
86
74
  type: 'ERROR_INTERNAL',
87
75
  created: Date.now(),
88
76
  payload: { error: err.message },
89
77
  reason: 'Failed while sending prompt',
90
- }) + '\n');
78
+ });
91
79
  }
92
80
  else {
93
81
  res.status(400).send({ error: err.message });
@@ -96,7 +84,7 @@ function sendError(err, res) {
96
84
  function streamStormPartialResponse(result, res) {
97
85
  return new Promise((resolve, reject) => {
98
86
  result.on('data', (data) => {
99
- res.write(JSON.stringify(data) + '\n');
87
+ sendEvent(res, data);
100
88
  });
101
89
  result.on('error', (err) => {
102
90
  reject(err);
@@ -106,4 +94,7 @@ function streamStormPartialResponse(result, res) {
106
94
  });
107
95
  });
108
96
  }
97
+ function sendEvent(res, evt) {
98
+ res.write(JSON.stringify(evt) + '\n');
99
+ }
109
100
  exports.default = router;
@@ -1,4 +1,4 @@
1
- import { ConversationItem, StormFileImplementationPrompt, StormStream } from './stream';
1
+ import { ConversationItem, StormFileImplementationPrompt, StormStream, StormUIImplementationPrompt } from './stream';
2
2
  export declare const STORM_ID = "storm";
3
3
  declare class StormClient {
4
4
  private readonly _baseUrl;
@@ -6,7 +6,7 @@ declare class StormClient {
6
6
  private createOptions;
7
7
  private send;
8
8
  createMetadata(prompt: string, history?: ConversationItem[]): Promise<StormStream>;
9
- createUIImplementation(prompt: StormFileImplementationPrompt, history?: ConversationItem[]): Promise<StormStream>;
9
+ createUIImplementation(prompt: StormUIImplementationPrompt, history?: ConversationItem[]): Promise<StormStream>;
10
10
  createServiceImplementation(prompt: StormFileImplementationPrompt, history?: ConversationItem[]): Promise<StormStream>;
11
11
  }
12
12
  export declare const stormClient: StormClient;
@@ -53,12 +53,6 @@ class StormClient {
53
53
  jsonLStream.on('error', (error) => {
54
54
  out.emit('error', error);
55
55
  });
56
- jsonLStream.on('pause', () => {
57
- console.log('paused');
58
- });
59
- jsonLStream.on('resume', () => {
60
- console.log('resumed');
61
- });
62
56
  jsonLStream.on('close', () => {
63
57
  out.end();
64
58
  });
@@ -77,7 +71,6 @@ class StormClient {
77
71
  });
78
72
  }
79
73
  createServiceImplementation(prompt, history) {
80
- console.log('SENDING SERVICE PROMPT', JSON.stringify(prompt, null, 2));
81
74
  return this.send('/v2/services/merge', {
82
75
  history: history ?? [],
83
76
  prompt,
@@ -36,3 +36,10 @@ export interface StormFileImplementationPrompt {
36
36
  template: StormFileInfo;
37
37
  prompt: string;
38
38
  }
39
+ export interface StormUIImplementationPrompt {
40
+ events: StormEvent[];
41
+ templates: StormFileInfo[];
42
+ context: StormFileInfo[];
43
+ blockName: string;
44
+ prompt: string;
45
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Copyright 2023 Kapeta Inc.
3
+ * SPDX-License-Identifier: BUSL-1.1
4
+ */
5
+ export {};
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2023 Kapeta Inc.
4
+ * SPDX-License-Identifier: BUSL-1.1
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const event_parser_1 = require("../../src/storm/event-parser");
8
+ const parserOptions = {
9
+ serviceKind: 'kapeta/block-service:local',
10
+ serviceLanguage: 'kapeta/language-target-nodejs-ts:local',
11
+ frontendKind: 'kapeta/block-type-frontend:local',
12
+ frontendLanguage: 'kapeta/language-target-react-ts:local',
13
+ cliKind: 'kapeta/block-type-cli:local',
14
+ cliLanguage: 'kapeta/language-target-nodejs-ts:local',
15
+ desktopKind: 'kapeta/block-type-desktop:local',
16
+ desktopLanguage: 'kapeta/language-target-electron-ts:local',
17
+ gatewayKind: 'kapeta/block-type-gateway:local',
18
+ mqKind: 'kapeta/block-type-mq:local',
19
+ exchangeKind: 'kapeta/resource-type-exchange:local',
20
+ queueKind: 'kapeta/resource-type-queue:local',
21
+ publisherKind: 'kapeta/resource-type-publisher:local',
22
+ subscriberKind: 'kapeta/resource-type-subscriber:local',
23
+ databaseKind: 'kapeta/block-type-database:local',
24
+ apiKind: 'kapeta/block-type-api:local',
25
+ clientKind: 'kapeta/block-type-client:local',
26
+ webPageKind: 'kapeta/block-type-web-page:local',
27
+ webFragmentKind: 'kapeta/block-type-web-fragment:local',
28
+ jwtProviderKind: 'kapeta/resource-type-jwt-provider:local',
29
+ jwtConsumerKind: 'kapeta/resource-type-jwt-consumer:local',
30
+ smtpKind: 'kapeta/resource-type-smtp:local',
31
+ externalApiKind: 'kapeta/resource-type-external-api:local',
32
+ };
33
+ const events = [
34
+ {
35
+ type: 'CREATE_PLAN_PROPERTIES',
36
+ created: Date.now(),
37
+ reason: 'create plan properties',
38
+ payload: {
39
+ name: 'my-plan',
40
+ description: 'my plan description',
41
+ },
42
+ },
43
+ {
44
+ type: 'CREATE_BLOCK',
45
+ reason: 'create backend',
46
+ created: Date.now(),
47
+ payload: {
48
+ name: 'service',
49
+ description: 'A service block',
50
+ type: 'BACKEND',
51
+ resources: [
52
+ {
53
+ name: 'entities',
54
+ type: 'DATABASE',
55
+ description: 'A database resource',
56
+ },
57
+ {
58
+ type: 'API',
59
+ name: 'entities',
60
+ description: 'An API resource',
61
+ },
62
+ ],
63
+ },
64
+ },
65
+ {
66
+ type: 'CREATE_BLOCK',
67
+ reason: 'create frontend',
68
+ created: Date.now(),
69
+ payload: {
70
+ name: 'ui',
71
+ description: 'A frontend block',
72
+ type: 'FRONTEND',
73
+ resources: [
74
+ {
75
+ name: 'web',
76
+ type: 'WEBPAGE',
77
+ description: 'A web page',
78
+ },
79
+ {
80
+ type: 'CLIENT',
81
+ name: 'entities',
82
+ description: 'Client for backend',
83
+ },
84
+ ],
85
+ },
86
+ },
87
+ {
88
+ type: 'CREATE_CONNECTION',
89
+ created: Date.now(),
90
+ reason: 'connect service to ui',
91
+ payload: {
92
+ fromComponent: 'service',
93
+ fromResource: 'entities',
94
+ fromResourceType: 'API',
95
+ toComponent: 'ui',
96
+ toResource: 'entities',
97
+ toResourceType: 'CLIENT',
98
+ },
99
+ },
100
+ {
101
+ type: 'CREATE_API',
102
+ reason: 'create api',
103
+ created: Date.now(),
104
+ payload: {
105
+ blockName: 'service',
106
+ content: `controller Entities('/entities') {
107
+ @GET('/')
108
+ list(): string[]
109
+ }`,
110
+ },
111
+ },
112
+ {
113
+ type: 'CREATE_MODEL',
114
+ created: Date.now(),
115
+ reason: 'create model',
116
+ payload: {
117
+ blockName: 'service',
118
+ content: `type Entity {
119
+ @Id
120
+ id: string
121
+
122
+ name: string
123
+ }`,
124
+ },
125
+ },
126
+ ];
127
+ describe('event-parser', () => {
128
+ it('it can parse events into a plan and blocks with proper layout', () => {
129
+ const parser = new event_parser_1.StormEventParser(parserOptions);
130
+ events.forEach((event) => parser.addEvent('kapeta', event));
131
+ const result = parser.toResult('kapeta');
132
+ expect(result.plan.metadata.name).toBe('kapeta/my-plan');
133
+ expect(result.plan.metadata.description).toBe('my plan description');
134
+ expect(result.blocks.length).toBe(2);
135
+ expect(result.blocks[0].content.metadata.name).toBe('kapeta/service');
136
+ expect(result.blocks[1].content.metadata.name).toBe('kapeta/ui');
137
+ const dbResource = result.blocks[0].content.spec.consumers?.[0];
138
+ const apiResource = result.blocks[0].content.spec.providers?.[0];
139
+ const clientResource = result.blocks[1].content.spec.consumers?.[0];
140
+ const pageResource = result.blocks[1].content.spec.providers?.[0];
141
+ expect(apiResource).toBeDefined();
142
+ expect(clientResource).toBeDefined();
143
+ expect(dbResource).toBeDefined();
144
+ expect(pageResource).toBeDefined();
145
+ expect(apiResource?.kind).toBe(parserOptions.apiKind);
146
+ expect(clientResource?.kind).toBe(parserOptions.clientKind);
147
+ expect(dbResource?.kind).toBe(parserOptions.databaseKind);
148
+ expect(pageResource?.kind).toBe(parserOptions.webPageKind);
149
+ expect(apiResource?.spec).toEqual(clientResource?.spec);
150
+ expect(dbResource?.spec.source.value).toContain('type Entity');
151
+ const serviceBlockInstance = result.plan.spec.blocks[0];
152
+ expect(serviceBlockInstance.name).toBe('service');
153
+ expect(serviceBlockInstance.dimensions.width).toBe(150);
154
+ expect(serviceBlockInstance.dimensions.height).toBe(200);
155
+ expect(serviceBlockInstance.dimensions.top).toBe(3);
156
+ expect(serviceBlockInstance.dimensions.left).toBe(6);
157
+ const uiBlockInstance = result.plan.spec.blocks[1];
158
+ expect(uiBlockInstance.name).toBe('ui');
159
+ expect(uiBlockInstance.dimensions.width).toBe(150);
160
+ expect(uiBlockInstance.dimensions.height).toBe(200);
161
+ expect(uiBlockInstance.dimensions.top).toBe(107);
162
+ expect(uiBlockInstance.dimensions.left).toBe(112);
163
+ expect(result.plan.spec.connections.length).toBe(1);
164
+ expect(result.plan.spec.connections[0].consumer.blockId).toBe(uiBlockInstance.id);
165
+ expect(result.plan.spec.connections[0].consumer.resourceName).toBe(clientResource?.metadata.name);
166
+ expect(result.plan.spec.connections[0].provider.blockId).toBe(serviceBlockInstance.id);
167
+ expect(result.plan.spec.connections[0].provider.resourceName).toBe(apiResource?.metadata.name);
168
+ });
169
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.45.0",
3
+ "version": "0.47.0",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -74,6 +74,8 @@
74
74
  "gunzip-maybe": "^1.4.2",
75
75
  "lodash": "^4.17.15",
76
76
  "md5": "2.2.1",
77
+ "ngraph.forcelayout": "^3.3.1",
78
+ "ngraph.graph": "^20.0.1",
77
79
  "node-cache": "^5.1.2",
78
80
  "node-uuid": "^1.4.8",
79
81
  "parse-data-uri": "^0.2.0",
@@ -8,7 +8,7 @@ import { AIFileTypes, BlockCodeGenerator, GeneratedFile, GeneratedResult } from
8
8
  import { BlockDefinition } from '@kapeta/schemas';
9
9
  import { codeGeneratorManager } from '../codeGeneratorManager';
10
10
  import { STORM_ID, stormClient } from './stormClient';
11
- import { ScreenTemplate, StormEvent, StormEventFile } from './events';
11
+ import { ScreenTemplate, StormEvent, StormEventFile, StormEventScreen } from './events';
12
12
  import { BlockDefinitionInfo } from './event-parser';
13
13
  import { ConversationItem, StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
14
14
  import { KapetaURI } from '@kapeta/nodejs-utils';
@@ -22,15 +22,15 @@ export class StormCodegen {
22
22
  private readonly userPrompt: string;
23
23
  private readonly blocks: BlockDefinitionInfo[];
24
24
  private readonly out = new StormStream();
25
+ private readonly events: StormEvent[];
25
26
 
26
- constructor(userPrompt: string, blocks: BlockDefinitionInfo[]) {
27
+ constructor(userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]) {
27
28
  this.userPrompt = userPrompt;
28
29
  this.blocks = blocks;
30
+ this.events = events;
29
31
  }
30
32
 
31
33
  public async process() {
32
- console.log('Processing blocks', this.blocks.length);
33
-
34
34
  for (const block of this.blocks) {
35
35
  await this.processBlockCode(block);
36
36
  }
@@ -42,13 +42,44 @@ export class StormCodegen {
42
42
  return this.out;
43
43
  }
44
44
 
45
- private handleFileOutput(blockUri: KapetaURI, template: StormFileInfo, data: StormEvent) {
45
+ private handleTemplateFileOutput(blockUri: KapetaURI, template: StormFileInfo, data: StormEvent) {
46
46
  switch (data.type) {
47
47
  case 'FILE':
48
48
  template.filename = data.payload.filename;
49
49
  template.content = data.payload.content;
50
+ return this.handleFileOutput(blockUri, data);
51
+ }
52
+ }
53
+
54
+ private handleUiOutput(blockUri: KapetaURI, data: StormEvent) {
55
+ switch (data.type) {
56
+ case 'SCREEN':
57
+ this.out.emit('data', {
58
+ type: 'SCREEN',
59
+ reason: data.reason,
60
+ created: Date.now(),
61
+ payload: {
62
+ ...data.payload,
63
+ blockName: blockUri.toNormalizedString(),
64
+ },
65
+ });
66
+ case 'FILE':
67
+ return this.handleFileOutput(blockUri, data);
68
+ }
69
+ }
70
+
71
+ private handleFileOutput(blockUri: KapetaURI, data: StormEvent) {
72
+ switch (data.type) {
73
+ case 'FILE':
50
74
  this.emitFile(blockUri, data.payload.filename, data.payload.content, data.reason);
51
- break;
75
+ return {
76
+ type: 'FILE',
77
+ created: Date.now(),
78
+ payload: {
79
+ filename: data.payload.filename,
80
+ content: data.payload.content,
81
+ },
82
+ } as StormEventFile;
52
83
  }
53
84
  }
54
85
 
@@ -57,9 +88,8 @@ export class StormCodegen {
57
88
  */
58
89
  private async processBlockCode(block: BlockDefinitionInfo) {
59
90
  // Generate the code for the block using the standard codegen templates
60
- const generatedResult = await this.generateBlock(block.content, block.screens);
91
+ const generatedResult = await this.generateBlock(block.content);
61
92
  if (!generatedResult) {
62
- console.warn('No generated result for block', block.uri);
63
93
  return;
64
94
  }
65
95
 
@@ -68,24 +98,41 @@ export class StormCodegen {
68
98
  // Send all the non-ai files to the stream
69
99
  this.emitFiles(block.uri, allFiles);
70
100
 
71
- const implementFiles = [AIFileTypes.SERVICE, AIFileTypes.WEB_SCREEN];
101
+ const relevantFiles: StormFileInfo[] = allFiles.filter(
102
+ (file) => file.type !== AIFileTypes.IGNORE && file.type !== AIFileTypes.WEB_SCREEN
103
+ );
104
+ const uiTemplates: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.WEB_SCREEN);
105
+ if (uiTemplates.length > 0) {
106
+ const uiStream = await stormClient.createUIImplementation({
107
+ events: this.events,
108
+ templates: uiTemplates,
109
+ context: relevantFiles,
110
+ blockName: block.aiName,
111
+ prompt: this.userPrompt,
112
+ });
113
+
114
+ uiStream.on('data', (evt) => {
115
+ this.handleUiOutput(block.uri, evt);
116
+ });
117
+
118
+ await uiStream.waitForDone();
119
+ }
72
120
 
73
- // Gather the context files. These will be all be passed to the AI
74
- const contextFiles: StormFileInfo[] = allFiles.filter(
75
- (file) => file.type !== AIFileTypes.IGNORE && !implementFiles.includes(file.type)
121
+ // Gather the context files for implementation. These will be all be passed to the AI
122
+ const contextFiles: StormFileInfo[] = relevantFiles.filter(
123
+ (file) => ![AIFileTypes.SERVICE, AIFileTypes.WEB_SCREEN].includes(file.type)
76
124
  );
77
125
 
78
126
  // Send the service and UI templates to the AI. These will be send one-by-one in addition to the context files
79
127
  const serviceFiles: StormFileInfo[] = allFiles.filter((file) => file.type === AIFileTypes.SERVICE);
80
- await this.processTemplates(
81
- block.uri,
82
- stormClient.createServiceImplementation.bind(stormClient),
83
- serviceFiles,
84
- contextFiles
85
- );
86
-
87
- //const uiTemplates: StormFileInfo[] = allFiles.filter((file) => file.type === 'ui');
88
- //await this.processTemplates(stormClient.createUIImplementation, uiTemplates, contextFiles);
128
+ if (serviceFiles.length > 0) {
129
+ await this.processTemplates(
130
+ block.uri,
131
+ stormClient.createServiceImplementation.bind(stormClient),
132
+ serviceFiles,
133
+ contextFiles
134
+ );
135
+ }
89
136
  }
90
137
 
91
138
  /**
@@ -129,7 +176,7 @@ export class StormCodegen {
129
176
  /**
130
177
  * Sends the template to the AI and processes the response
131
178
  */
132
- private processTemplates(
179
+ private async processTemplates(
133
180
  blockUri: KapetaURI,
134
181
  generator: ImplementationGenerator,
135
182
  templates: StormFileInfo[],
@@ -142,12 +189,22 @@ export class StormCodegen {
142
189
  prompt: this.userPrompt,
143
190
  });
144
191
 
145
- stream.on('data', (evt) => this.handleFileOutput(blockUri, templateFile, evt));
192
+ const files: StormEventFile[] = [];
146
193
 
147
- return stream.waitForDone();
194
+ stream.on('data', (evt) => {
195
+ const file = this.handleTemplateFileOutput(blockUri, templateFile, evt);
196
+ if (file) {
197
+ files.push(file);
198
+ }
199
+ });
200
+
201
+ await stream.waitForDone();
202
+ return files;
148
203
  });
149
204
 
150
- return Promise.all(promises);
205
+ const fileChunks = await Promise.all(promises);
206
+
207
+ return fileChunks.flat();
151
208
  }
152
209
 
153
210
  /**
@@ -191,7 +248,7 @@ export class StormCodegen {
191
248
  /**
192
249
  * Generates the code using codegen for a given block.
193
250
  */
194
- private async generateBlock(yamlContent: Definition, screens: ScreenTemplate[] | undefined) {
251
+ private async generateBlock(yamlContent: Definition) {
195
252
  if (!yamlContent.spec.target?.kind) {
196
253
  //Not all block types have targets
197
254
  return;
@@ -203,7 +260,6 @@ export class StormCodegen {
203
260
 
204
261
  const codeGenerator = new BlockCodeGenerator(yamlContent as BlockDefinition);
205
262
  codeGenerator.withOption('AIContext', STORM_ID);
206
- codeGenerator.withOption('AIScreens', screens ?? []);
207
263
 
208
264
  return codeGenerator.generate();
209
265
  }