@kapeta/local-cluster-service 0.48.1 → 0.48.3

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.48.3](https://github.com/kapetacom/local-cluster-service/compare/v0.48.2...v0.48.3) (2024-06-03)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Added missing instance and block refs ([dc77a7c](https://github.com/kapetacom/local-cluster-service/commit/dc77a7c480d4ed70e1dc8dc5c1b13093d739e20c))
7
+
8
+ ## [0.48.2](https://github.com/kapetacom/local-cluster-service/compare/v0.48.1...v0.48.2) (2024-06-03)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Include resource name for api and model ([#157](https://github.com/kapetacom/local-cluster-service/issues/157)) ([b79a704](https://github.com/kapetacom/local-cluster-service/commit/b79a704b74d11cb0ec0fc8346e29ed754b39fb12))
14
+
1
15
  ## [0.48.1](https://github.com/kapetacom/local-cluster-service/compare/v0.48.0...v0.48.1) (2024-06-03)
2
16
 
3
17
 
@@ -10,12 +10,14 @@ export declare class StormCodegen {
10
10
  private readonly blocks;
11
11
  private readonly out;
12
12
  private readonly events;
13
+ private readonly tmpDir;
13
14
  constructor(userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]);
14
15
  process(): Promise<void>;
15
16
  getStream(): StormStream;
16
17
  private handleTemplateFileOutput;
17
18
  private handleUiOutput;
18
19
  private handleFileOutput;
20
+ private getBasePath;
19
21
  /**
20
22
  * Generates the code for a block and sends it to the AI
21
23
  */
@@ -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 event_parser_1 = require("./event-parser");
37
38
  const stream_1 = require("./stream");
38
39
  const promises_1 = require("fs/promises");
39
40
  const path_1 = __importStar(require("path"));
@@ -43,10 +44,12 @@ class StormCodegen {
43
44
  blocks;
44
45
  out = new stream_1.StormStream();
45
46
  events;
47
+ tmpDir;
46
48
  constructor(userPrompt, blocks, events) {
47
49
  this.userPrompt = userPrompt;
48
50
  this.blocks = blocks;
49
51
  this.events = events;
52
+ this.tmpDir = node_os_1.default.tmpdir();
50
53
  }
51
54
  async process() {
52
55
  for (const block of this.blocks) {
@@ -68,6 +71,7 @@ class StormCodegen {
68
71
  handleUiOutput(blockUri, aiName, data) {
69
72
  switch (data.type) {
70
73
  case 'SCREEN':
74
+ const ref = blockUri.toNormalizedString();
71
75
  this.out.emit('data', {
72
76
  type: 'SCREEN',
73
77
  reason: data.reason,
@@ -75,6 +79,8 @@ class StormCodegen {
75
79
  payload: {
76
80
  ...data.payload,
77
81
  blockName: aiName,
82
+ blockRef: ref,
83
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
78
84
  },
79
85
  });
80
86
  case 'FILE':
@@ -84,6 +90,7 @@ class StormCodegen {
84
90
  handleFileOutput(blockUri, aiName, data) {
85
91
  switch (data.type) {
86
92
  case 'FILE':
93
+ const ref = blockUri.toNormalizedString();
87
94
  this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
88
95
  return {
89
96
  type: 'FILE',
@@ -91,10 +98,15 @@ class StormCodegen {
91
98
  payload: {
92
99
  filename: data.payload.filename,
93
100
  content: data.payload.content,
101
+ blockRef: ref,
102
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
94
103
  },
95
104
  };
96
105
  }
97
106
  }
107
+ getBasePath(blockName) {
108
+ return path_1.default.join(this.tmpDir, blockName);
109
+ }
98
110
  /**
99
111
  * Generates the code for a block and sends it to the AI
100
112
  */
@@ -129,7 +141,7 @@ class StormCodegen {
129
141
  if (serviceFiles.length > 0) {
130
142
  await this.processTemplates(block.uri, block.aiName, stormClient_1.stormClient.createServiceImplementation.bind(stormClient_1.stormClient), serviceFiles, contextFiles);
131
143
  }
132
- const basePath = path_1.default.join(node_os_1.default.tmpdir(), block.content.metadata.name);
144
+ const basePath = this.getBasePath(block.content.metadata.name);
133
145
  for (const serviceFile of serviceFiles) {
134
146
  const filePath = (0, path_1.join)(basePath, serviceFile.filename);
135
147
  await (0, promises_1.writeFile)(filePath, serviceFile.content);
@@ -165,15 +177,19 @@ class StormCodegen {
165
177
  });
166
178
  }
167
179
  emitFile(uri, blockName, filename, content, reason = 'File generated') {
180
+ const basePath = this.getBasePath(uri.fullName);
181
+ const ref = uri.toNormalizedString();
168
182
  this.out.emit('data', {
169
183
  type: 'FILE',
170
184
  reason,
171
185
  created: Date.now(),
172
186
  payload: {
173
187
  filename: filename,
188
+ path: (0, path_1.join)(basePath, filename),
174
189
  content: content,
175
190
  blockName,
176
- blockRef: uri.toNormalizedString(),
191
+ blockRef: ref,
192
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
177
193
  },
178
194
  });
179
195
  }
@@ -245,7 +261,7 @@ class StormCodegen {
245
261
  if (!(await codeGeneratorManager_1.codeGeneratorManager.ensureTarget(yamlContent.spec.target?.kind))) {
246
262
  return;
247
263
  }
248
- const basePath = path_1.default.join(node_os_1.default.tmpdir(), yamlContent.metadata.name);
264
+ const basePath = this.getBasePath(yamlContent.metadata.name);
249
265
  const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
250
266
  codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
251
267
  const generatedResult = await codeGenerator.generate();
@@ -41,6 +41,10 @@ export interface StormOptions {
41
41
  }
42
42
  export declare function resolveOptions(): Promise<StormOptions>;
43
43
  export declare class StormEventParser {
44
+ static toInstanceId(handle: string, blockName: string): string;
45
+ static toInstanceIdFromRef(ref: string): string;
46
+ static toSafeName(name: string): string;
47
+ static toRef(handle: string, name: string): KapetaURI;
44
48
  private events;
45
49
  private planName;
46
50
  private planDescription;
@@ -58,11 +62,7 @@ export declare class StormEventParser {
58
62
  getEvents(): StormEvent[];
59
63
  isValid(): boolean;
60
64
  getError(): string;
61
- private toInstanceId;
62
- private toInstanceIdFromRef;
63
65
  toResult(handle: string): StormDefinitions;
64
- private toSafeName;
65
- private toRef;
66
66
  toBlockDefinitions(handle: string): {
67
67
  [key: string]: BlockDefinitionInfo;
68
68
  };
@@ -105,6 +105,19 @@ async function resolveOptions() {
105
105
  }
106
106
  exports.resolveOptions = resolveOptions;
107
107
  class StormEventParser {
108
+ static toInstanceId(handle, blockName) {
109
+ const ref = this.toRef(handle, blockName);
110
+ return this.toInstanceIdFromRef(ref.toNormalizedString());
111
+ }
112
+ static toInstanceIdFromRef(ref) {
113
+ return (0, uuid_1.v5)((0, nodejs_utils_1.normalizeKapetaUri)(ref), uuid_1.v5.URL);
114
+ }
115
+ static toSafeName(name) {
116
+ return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
117
+ }
118
+ static toRef(handle, name) {
119
+ return (0, nodejs_utils_1.parseKapetaUri)(handle + '/' + this.toSafeName(name) + ':local');
120
+ }
108
121
  events = [];
109
122
  planName = '';
110
123
  planDescription = '';
@@ -126,7 +139,9 @@ class StormEventParser {
126
139
  * Builds plan and block definitions - and enriches events with relevant refs and ids
127
140
  */
128
141
  processEvent(handle, evt) {
142
+ let blockInfo;
129
143
  this.events.push(evt);
144
+ console.log('Processing event: %s', evt.type);
130
145
  switch (evt.type) {
131
146
  case 'CREATE_PLAN_PROPERTIES':
132
147
  this.planName = evt.payload.name;
@@ -139,8 +154,8 @@ class StormEventParser {
139
154
  models: [],
140
155
  types: [],
141
156
  };
142
- evt.payload.blockRef = this.toRef(handle, evt.payload.name).toNormalizedString();
143
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
157
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.name).toNormalizedString();
158
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
144
159
  break;
145
160
  case 'PLAN_RETRY':
146
161
  this.reset();
@@ -150,23 +165,29 @@ class StormEventParser {
150
165
  this.error = evt.payload.error;
151
166
  break;
152
167
  case 'CREATE_API':
153
- this.blocks[evt.payload.blockName].apis.push(prettifyKaplang(evt.payload.content));
154
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
155
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
168
+ blockInfo = this.blocks[evt.payload.blockName];
169
+ blockInfo.apis.push(prettifyKaplang(evt.payload.content));
170
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
171
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
172
+ const api = blockInfo.resources.find((r) => r.type == 'API');
173
+ evt.payload.resourceName = api?.name;
174
+ break;
175
+ case 'CREATE_MODEL':
176
+ blockInfo = this.blocks[evt.payload.blockName];
177
+ blockInfo.models.push(prettifyKaplang(evt.payload.content));
178
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
179
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
180
+ const database = blockInfo.resources.find((r) => r.type == 'DATABASE');
181
+ evt.payload.resourceName = database?.name;
156
182
  break;
157
183
  case 'CREATE_TYPE':
158
184
  this.blocks[evt.payload.blockName].types.push(prettifyKaplang(evt.payload.content));
159
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
160
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
161
- break;
162
- case 'CREATE_MODEL':
163
- this.blocks[evt.payload.blockName].models.push(prettifyKaplang(evt.payload.content));
164
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
165
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
185
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
186
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
166
187
  break;
167
188
  case 'CREATE_CONNECTION':
168
- evt.payload.fromBlockId = this.toInstanceId(handle, evt.payload.fromComponent);
169
- evt.payload.toBlockId = this.toInstanceId(handle, evt.payload.toComponent);
189
+ evt.payload.fromBlockId = StormEventParser.toInstanceId(handle, evt.payload.fromComponent);
190
+ evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
170
191
  this.connections.push(evt.payload);
171
192
  break;
172
193
  default:
@@ -188,20 +209,13 @@ class StormEventParser {
188
209
  getError() {
189
210
  return this.error;
190
211
  }
191
- toInstanceId(handle, blockName) {
192
- const ref = this.toRef(handle, blockName);
193
- return this.toInstanceIdFromRef(ref.toNormalizedString());
194
- }
195
- toInstanceIdFromRef(ref) {
196
- return (0, uuid_1.v5)((0, nodejs_utils_1.normalizeKapetaUri)(ref), uuid_1.v5.URL);
197
- }
198
212
  toResult(handle) {
199
- const planRef = this.toRef(handle, this.planName ?? 'undefined');
213
+ const planRef = StormEventParser.toRef(handle, this.planName ?? 'undefined');
200
214
  const blockDefinitions = this.toBlockDefinitions(handle);
201
215
  const refIdMap = {};
202
216
  const blocks = Object.entries(blockDefinitions).map(([ref, block]) => {
203
217
  // Create a deterministic uuid
204
- const id = this.toInstanceIdFromRef(ref);
218
+ const id = StormEventParser.toInstanceIdFromRef(ref);
205
219
  refIdMap[ref] = id;
206
220
  return {
207
221
  id,
@@ -221,8 +235,8 @@ class StormEventParser {
221
235
  this.connections
222
236
  .filter((connection) => connection.fromResourceType === 'API' && connection.toResourceType === 'CLIENT')
223
237
  .forEach((apiConnection) => {
224
- const apiProviderRef = this.toRef(handle, apiConnection.fromComponent);
225
- const clientConsumerRef = this.toRef(handle, apiConnection.toComponent);
238
+ const apiProviderRef = StormEventParser.toRef(handle, apiConnection.fromComponent);
239
+ const clientConsumerRef = StormEventParser.toRef(handle, apiConnection.toComponent);
226
240
  const apiProviderBlock = blockDefinitions[apiProviderRef.toNormalizedString()];
227
241
  if (!apiProviderBlock) {
228
242
  console.warn('API provider not found: %s', apiConnection.fromComponent, apiConnection);
@@ -275,8 +289,8 @@ class StormEventParser {
275
289
  clientResource.spec.source = apiResource.spec.source;
276
290
  });
277
291
  const connections = this.connections.map((connection) => {
278
- const fromRef = this.toRef(handle, connection.fromComponent);
279
- const toRef = this.toRef(handle, connection.toComponent);
292
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
293
+ const toRef = StormEventParser.toRef(handle, connection.toComponent);
280
294
  return {
281
295
  port: {
282
296
  type: this.toPortType(connection.fromResourceType),
@@ -309,16 +323,10 @@ class StormEventParser {
309
323
  blocks: Object.values(blockDefinitions),
310
324
  };
311
325
  }
312
- toSafeName(name) {
313
- return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
314
- }
315
- toRef(handle, name) {
316
- return (0, nodejs_utils_1.parseKapetaUri)(handle + '/' + this.toSafeName(name) + ':local');
317
- }
318
326
  toBlockDefinitions(handle) {
319
327
  const result = {};
320
328
  Object.entries(this.blocks).forEach(([, blockInfo]) => {
321
- const blockRef = this.toRef(handle, blockInfo.name);
329
+ const blockRef = StormEventParser.toRef(handle, blockInfo.name);
322
330
  const blockDefinitionInfo = {
323
331
  uri: blockRef,
324
332
  aiName: blockInfo.name,
@@ -522,7 +530,7 @@ class StormEventParser {
522
530
  if (connection.fromResourceType !== 'API') {
523
531
  return;
524
532
  }
525
- const fromRef = this.toRef(handle, connection.fromComponent);
533
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
526
534
  const apiProviderBlock = blockDefinitions[fromRef.toNormalizedString()];
527
535
  if (!apiProviderBlock) {
528
536
  console.warn('Provider block not found: %s', connection.fromComponent, connection);
@@ -577,8 +585,8 @@ class StormEventParser {
577
585
  }
578
586
  let options = {};
579
587
  if (kind.includes('java')) {
580
- const groupId = `ai.${this.toSafeName(handle)}`;
581
- const artifactId = this.toSafeName(this.planName);
588
+ const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
589
+ const artifactId = StormEventParser.toSafeName(this.planName);
582
590
  options = {
583
591
  groupId,
584
592
  artifactId,
@@ -70,7 +70,7 @@ export interface StormEventPlanRetry {
70
70
  };
71
71
  }
72
72
  export interface StormEventCreateDSL {
73
- type: 'CREATE_API' | 'CREATE_TYPE' | 'CREATE_MODEL';
73
+ type: 'CREATE_TYPE';
74
74
  reason: string;
75
75
  created: number;
76
76
  payload: {
@@ -80,6 +80,18 @@ export interface StormEventCreateDSL {
80
80
  instanceId?: string;
81
81
  };
82
82
  }
83
+ export interface StormEventCreateDSLResource extends Omit<StormEventCreateDSL, 'type'> {
84
+ type: 'CREATE_API' | 'CREATE_MODEL';
85
+ reason: string;
86
+ created: number;
87
+ payload: {
88
+ blockName: string;
89
+ content: string;
90
+ blockRef?: string;
91
+ instanceId?: string;
92
+ resourceName?: string;
93
+ };
94
+ }
83
95
  export interface StormEventError {
84
96
  type: 'INVALID_RESPONSE' | 'ERROR_INTERNAL';
85
97
  reason: string;
@@ -100,6 +112,8 @@ export interface StormEventScreen {
100
112
  created: number;
101
113
  payload: {
102
114
  blockName: string;
115
+ blockRef?: string;
116
+ instanceId?: string;
103
117
  name: string;
104
118
  template: string;
105
119
  description: string;
@@ -122,9 +136,11 @@ export interface StormEventFile {
122
136
  created: number;
123
137
  payload: {
124
138
  filename: string;
139
+ path: string;
125
140
  content: string;
126
141
  blockName: string;
127
142
  blockRef: string;
143
+ instanceId: string;
128
144
  };
129
145
  }
130
146
  export interface StormEventDone {
@@ -137,4 +153,4 @@ export interface StormEventDefinitionChange {
137
153
  created: number;
138
154
  payload: StormDefinitions;
139
155
  }
140
- export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFile | StormEventDone | StormEventDefinitionChange;
156
+ export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFile | StormEventDone | StormEventDefinitionChange;
@@ -10,12 +10,14 @@ export declare class StormCodegen {
10
10
  private readonly blocks;
11
11
  private readonly out;
12
12
  private readonly events;
13
+ private readonly tmpDir;
13
14
  constructor(userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]);
14
15
  process(): Promise<void>;
15
16
  getStream(): StormStream;
16
17
  private handleTemplateFileOutput;
17
18
  private handleUiOutput;
18
19
  private handleFileOutput;
20
+ private getBasePath;
19
21
  /**
20
22
  * Generates the code for a block and sends it to the AI
21
23
  */
@@ -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 event_parser_1 = require("./event-parser");
37
38
  const stream_1 = require("./stream");
38
39
  const promises_1 = require("fs/promises");
39
40
  const path_1 = __importStar(require("path"));
@@ -43,10 +44,12 @@ class StormCodegen {
43
44
  blocks;
44
45
  out = new stream_1.StormStream();
45
46
  events;
47
+ tmpDir;
46
48
  constructor(userPrompt, blocks, events) {
47
49
  this.userPrompt = userPrompt;
48
50
  this.blocks = blocks;
49
51
  this.events = events;
52
+ this.tmpDir = node_os_1.default.tmpdir();
50
53
  }
51
54
  async process() {
52
55
  for (const block of this.blocks) {
@@ -68,6 +71,7 @@ class StormCodegen {
68
71
  handleUiOutput(blockUri, aiName, data) {
69
72
  switch (data.type) {
70
73
  case 'SCREEN':
74
+ const ref = blockUri.toNormalizedString();
71
75
  this.out.emit('data', {
72
76
  type: 'SCREEN',
73
77
  reason: data.reason,
@@ -75,6 +79,8 @@ class StormCodegen {
75
79
  payload: {
76
80
  ...data.payload,
77
81
  blockName: aiName,
82
+ blockRef: ref,
83
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
78
84
  },
79
85
  });
80
86
  case 'FILE':
@@ -84,6 +90,7 @@ class StormCodegen {
84
90
  handleFileOutput(blockUri, aiName, data) {
85
91
  switch (data.type) {
86
92
  case 'FILE':
93
+ const ref = blockUri.toNormalizedString();
87
94
  this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
88
95
  return {
89
96
  type: 'FILE',
@@ -91,10 +98,15 @@ class StormCodegen {
91
98
  payload: {
92
99
  filename: data.payload.filename,
93
100
  content: data.payload.content,
101
+ blockRef: ref,
102
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
94
103
  },
95
104
  };
96
105
  }
97
106
  }
107
+ getBasePath(blockName) {
108
+ return path_1.default.join(this.tmpDir, blockName);
109
+ }
98
110
  /**
99
111
  * Generates the code for a block and sends it to the AI
100
112
  */
@@ -129,7 +141,7 @@ class StormCodegen {
129
141
  if (serviceFiles.length > 0) {
130
142
  await this.processTemplates(block.uri, block.aiName, stormClient_1.stormClient.createServiceImplementation.bind(stormClient_1.stormClient), serviceFiles, contextFiles);
131
143
  }
132
- const basePath = path_1.default.join(node_os_1.default.tmpdir(), block.content.metadata.name);
144
+ const basePath = this.getBasePath(block.content.metadata.name);
133
145
  for (const serviceFile of serviceFiles) {
134
146
  const filePath = (0, path_1.join)(basePath, serviceFile.filename);
135
147
  await (0, promises_1.writeFile)(filePath, serviceFile.content);
@@ -165,15 +177,19 @@ class StormCodegen {
165
177
  });
166
178
  }
167
179
  emitFile(uri, blockName, filename, content, reason = 'File generated') {
180
+ const basePath = this.getBasePath(uri.fullName);
181
+ const ref = uri.toNormalizedString();
168
182
  this.out.emit('data', {
169
183
  type: 'FILE',
170
184
  reason,
171
185
  created: Date.now(),
172
186
  payload: {
173
187
  filename: filename,
188
+ path: (0, path_1.join)(basePath, filename),
174
189
  content: content,
175
190
  blockName,
176
- blockRef: uri.toNormalizedString(),
191
+ blockRef: ref,
192
+ instanceId: event_parser_1.StormEventParser.toInstanceIdFromRef(ref),
177
193
  },
178
194
  });
179
195
  }
@@ -245,7 +261,7 @@ class StormCodegen {
245
261
  if (!(await codeGeneratorManager_1.codeGeneratorManager.ensureTarget(yamlContent.spec.target?.kind))) {
246
262
  return;
247
263
  }
248
- const basePath = path_1.default.join(node_os_1.default.tmpdir(), yamlContent.metadata.name);
264
+ const basePath = this.getBasePath(yamlContent.metadata.name);
249
265
  const codeGenerator = new codegen_1.BlockCodeGenerator(yamlContent);
250
266
  codeGenerator.withOption('AIContext', stormClient_1.STORM_ID);
251
267
  const generatedResult = await codeGenerator.generate();
@@ -41,6 +41,10 @@ export interface StormOptions {
41
41
  }
42
42
  export declare function resolveOptions(): Promise<StormOptions>;
43
43
  export declare class StormEventParser {
44
+ static toInstanceId(handle: string, blockName: string): string;
45
+ static toInstanceIdFromRef(ref: string): string;
46
+ static toSafeName(name: string): string;
47
+ static toRef(handle: string, name: string): KapetaURI;
44
48
  private events;
45
49
  private planName;
46
50
  private planDescription;
@@ -58,11 +62,7 @@ export declare class StormEventParser {
58
62
  getEvents(): StormEvent[];
59
63
  isValid(): boolean;
60
64
  getError(): string;
61
- private toInstanceId;
62
- private toInstanceIdFromRef;
63
65
  toResult(handle: string): StormDefinitions;
64
- private toSafeName;
65
- private toRef;
66
66
  toBlockDefinitions(handle: string): {
67
67
  [key: string]: BlockDefinitionInfo;
68
68
  };
@@ -105,6 +105,19 @@ async function resolveOptions() {
105
105
  }
106
106
  exports.resolveOptions = resolveOptions;
107
107
  class StormEventParser {
108
+ static toInstanceId(handle, blockName) {
109
+ const ref = this.toRef(handle, blockName);
110
+ return this.toInstanceIdFromRef(ref.toNormalizedString());
111
+ }
112
+ static toInstanceIdFromRef(ref) {
113
+ return (0, uuid_1.v5)((0, nodejs_utils_1.normalizeKapetaUri)(ref), uuid_1.v5.URL);
114
+ }
115
+ static toSafeName(name) {
116
+ return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
117
+ }
118
+ static toRef(handle, name) {
119
+ return (0, nodejs_utils_1.parseKapetaUri)(handle + '/' + this.toSafeName(name) + ':local');
120
+ }
108
121
  events = [];
109
122
  planName = '';
110
123
  planDescription = '';
@@ -126,7 +139,9 @@ class StormEventParser {
126
139
  * Builds plan and block definitions - and enriches events with relevant refs and ids
127
140
  */
128
141
  processEvent(handle, evt) {
142
+ let blockInfo;
129
143
  this.events.push(evt);
144
+ console.log('Processing event: %s', evt.type);
130
145
  switch (evt.type) {
131
146
  case 'CREATE_PLAN_PROPERTIES':
132
147
  this.planName = evt.payload.name;
@@ -139,8 +154,8 @@ class StormEventParser {
139
154
  models: [],
140
155
  types: [],
141
156
  };
142
- evt.payload.blockRef = this.toRef(handle, evt.payload.name).toNormalizedString();
143
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
157
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.name).toNormalizedString();
158
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
144
159
  break;
145
160
  case 'PLAN_RETRY':
146
161
  this.reset();
@@ -150,23 +165,29 @@ class StormEventParser {
150
165
  this.error = evt.payload.error;
151
166
  break;
152
167
  case 'CREATE_API':
153
- this.blocks[evt.payload.blockName].apis.push(prettifyKaplang(evt.payload.content));
154
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
155
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
168
+ blockInfo = this.blocks[evt.payload.blockName];
169
+ blockInfo.apis.push(prettifyKaplang(evt.payload.content));
170
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
171
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
172
+ const api = blockInfo.resources.find((r) => r.type == 'API');
173
+ evt.payload.resourceName = api?.name;
174
+ break;
175
+ case 'CREATE_MODEL':
176
+ blockInfo = this.blocks[evt.payload.blockName];
177
+ blockInfo.models.push(prettifyKaplang(evt.payload.content));
178
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
179
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
180
+ const database = blockInfo.resources.find((r) => r.type == 'DATABASE');
181
+ evt.payload.resourceName = database?.name;
156
182
  break;
157
183
  case 'CREATE_TYPE':
158
184
  this.blocks[evt.payload.blockName].types.push(prettifyKaplang(evt.payload.content));
159
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
160
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
161
- break;
162
- case 'CREATE_MODEL':
163
- this.blocks[evt.payload.blockName].models.push(prettifyKaplang(evt.payload.content));
164
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
165
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
185
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
186
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
166
187
  break;
167
188
  case 'CREATE_CONNECTION':
168
- evt.payload.fromBlockId = this.toInstanceId(handle, evt.payload.fromComponent);
169
- evt.payload.toBlockId = this.toInstanceId(handle, evt.payload.toComponent);
189
+ evt.payload.fromBlockId = StormEventParser.toInstanceId(handle, evt.payload.fromComponent);
190
+ evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
170
191
  this.connections.push(evt.payload);
171
192
  break;
172
193
  default:
@@ -188,20 +209,13 @@ class StormEventParser {
188
209
  getError() {
189
210
  return this.error;
190
211
  }
191
- toInstanceId(handle, blockName) {
192
- const ref = this.toRef(handle, blockName);
193
- return this.toInstanceIdFromRef(ref.toNormalizedString());
194
- }
195
- toInstanceIdFromRef(ref) {
196
- return (0, uuid_1.v5)((0, nodejs_utils_1.normalizeKapetaUri)(ref), uuid_1.v5.URL);
197
- }
198
212
  toResult(handle) {
199
- const planRef = this.toRef(handle, this.planName ?? 'undefined');
213
+ const planRef = StormEventParser.toRef(handle, this.planName ?? 'undefined');
200
214
  const blockDefinitions = this.toBlockDefinitions(handle);
201
215
  const refIdMap = {};
202
216
  const blocks = Object.entries(blockDefinitions).map(([ref, block]) => {
203
217
  // Create a deterministic uuid
204
- const id = this.toInstanceIdFromRef(ref);
218
+ const id = StormEventParser.toInstanceIdFromRef(ref);
205
219
  refIdMap[ref] = id;
206
220
  return {
207
221
  id,
@@ -221,8 +235,8 @@ class StormEventParser {
221
235
  this.connections
222
236
  .filter((connection) => connection.fromResourceType === 'API' && connection.toResourceType === 'CLIENT')
223
237
  .forEach((apiConnection) => {
224
- const apiProviderRef = this.toRef(handle, apiConnection.fromComponent);
225
- const clientConsumerRef = this.toRef(handle, apiConnection.toComponent);
238
+ const apiProviderRef = StormEventParser.toRef(handle, apiConnection.fromComponent);
239
+ const clientConsumerRef = StormEventParser.toRef(handle, apiConnection.toComponent);
226
240
  const apiProviderBlock = blockDefinitions[apiProviderRef.toNormalizedString()];
227
241
  if (!apiProviderBlock) {
228
242
  console.warn('API provider not found: %s', apiConnection.fromComponent, apiConnection);
@@ -275,8 +289,8 @@ class StormEventParser {
275
289
  clientResource.spec.source = apiResource.spec.source;
276
290
  });
277
291
  const connections = this.connections.map((connection) => {
278
- const fromRef = this.toRef(handle, connection.fromComponent);
279
- const toRef = this.toRef(handle, connection.toComponent);
292
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
293
+ const toRef = StormEventParser.toRef(handle, connection.toComponent);
280
294
  return {
281
295
  port: {
282
296
  type: this.toPortType(connection.fromResourceType),
@@ -309,16 +323,10 @@ class StormEventParser {
309
323
  blocks: Object.values(blockDefinitions),
310
324
  };
311
325
  }
312
- toSafeName(name) {
313
- return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
314
- }
315
- toRef(handle, name) {
316
- return (0, nodejs_utils_1.parseKapetaUri)(handle + '/' + this.toSafeName(name) + ':local');
317
- }
318
326
  toBlockDefinitions(handle) {
319
327
  const result = {};
320
328
  Object.entries(this.blocks).forEach(([, blockInfo]) => {
321
- const blockRef = this.toRef(handle, blockInfo.name);
329
+ const blockRef = StormEventParser.toRef(handle, blockInfo.name);
322
330
  const blockDefinitionInfo = {
323
331
  uri: blockRef,
324
332
  aiName: blockInfo.name,
@@ -522,7 +530,7 @@ class StormEventParser {
522
530
  if (connection.fromResourceType !== 'API') {
523
531
  return;
524
532
  }
525
- const fromRef = this.toRef(handle, connection.fromComponent);
533
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
526
534
  const apiProviderBlock = blockDefinitions[fromRef.toNormalizedString()];
527
535
  if (!apiProviderBlock) {
528
536
  console.warn('Provider block not found: %s', connection.fromComponent, connection);
@@ -577,8 +585,8 @@ class StormEventParser {
577
585
  }
578
586
  let options = {};
579
587
  if (kind.includes('java')) {
580
- const groupId = `ai.${this.toSafeName(handle)}`;
581
- const artifactId = this.toSafeName(this.planName);
588
+ const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
589
+ const artifactId = StormEventParser.toSafeName(this.planName);
582
590
  options = {
583
591
  groupId,
584
592
  artifactId,
@@ -70,7 +70,7 @@ export interface StormEventPlanRetry {
70
70
  };
71
71
  }
72
72
  export interface StormEventCreateDSL {
73
- type: 'CREATE_API' | 'CREATE_TYPE' | 'CREATE_MODEL';
73
+ type: 'CREATE_TYPE';
74
74
  reason: string;
75
75
  created: number;
76
76
  payload: {
@@ -80,6 +80,18 @@ export interface StormEventCreateDSL {
80
80
  instanceId?: string;
81
81
  };
82
82
  }
83
+ export interface StormEventCreateDSLResource extends Omit<StormEventCreateDSL, 'type'> {
84
+ type: 'CREATE_API' | 'CREATE_MODEL';
85
+ reason: string;
86
+ created: number;
87
+ payload: {
88
+ blockName: string;
89
+ content: string;
90
+ blockRef?: string;
91
+ instanceId?: string;
92
+ resourceName?: string;
93
+ };
94
+ }
83
95
  export interface StormEventError {
84
96
  type: 'INVALID_RESPONSE' | 'ERROR_INTERNAL';
85
97
  reason: string;
@@ -100,6 +112,8 @@ export interface StormEventScreen {
100
112
  created: number;
101
113
  payload: {
102
114
  blockName: string;
115
+ blockRef?: string;
116
+ instanceId?: string;
103
117
  name: string;
104
118
  template: string;
105
119
  description: string;
@@ -122,9 +136,11 @@ export interface StormEventFile {
122
136
  created: number;
123
137
  payload: {
124
138
  filename: string;
139
+ path: string;
125
140
  content: string;
126
141
  blockName: string;
127
142
  blockRef: string;
143
+ instanceId: string;
128
144
  };
129
145
  }
130
146
  export interface StormEventDone {
@@ -137,4 +153,4 @@ export interface StormEventDefinitionChange {
137
153
  created: number;
138
154
  payload: StormDefinitions;
139
155
  }
140
- export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFile | StormEventDone | StormEventDefinitionChange;
156
+ export type StormEvent = StormEventCreateBlock | StormEventCreateConnection | StormEventCreatePlanProperties | StormEventInvalidResponse | StormEventPlanRetry | StormEventCreateDSL | StormEventCreateDSLResource | StormEventError | StormEventScreen | StormEventScreenCandidate | StormEventFile | StormEventDone | StormEventDefinitionChange;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.48.1",
3
+ "version": "0.48.3",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -9,7 +9,7 @@ import { BlockDefinition } from '@kapeta/schemas';
9
9
  import { codeGeneratorManager } from '../codeGeneratorManager';
10
10
  import { STORM_ID, stormClient } from './stormClient';
11
11
  import { StormEvent, StormEventFile } from './events';
12
- import { BlockDefinitionInfo } from './event-parser';
12
+ import { BlockDefinitionInfo, StormEventParser } from './event-parser';
13
13
  import { ConversationItem, StormFileImplementationPrompt, StormFileInfo, StormStream } from './stream';
14
14
  import { KapetaURI } from '@kapeta/nodejs-utils';
15
15
  import { writeFile } from 'fs/promises';
@@ -23,11 +23,13 @@ export class StormCodegen {
23
23
  private readonly blocks: BlockDefinitionInfo[];
24
24
  private readonly out = new StormStream();
25
25
  private readonly events: StormEvent[];
26
+ private readonly tmpDir: string;
26
27
 
27
28
  constructor(userPrompt: string, blocks: BlockDefinitionInfo[], events: StormEvent[]) {
28
29
  this.userPrompt = userPrompt;
29
30
  this.blocks = blocks;
30
31
  this.events = events;
32
+ this.tmpDir = os.tmpdir();
31
33
  }
32
34
 
33
35
  public async process() {
@@ -54,6 +56,7 @@ export class StormCodegen {
54
56
  private handleUiOutput(blockUri: KapetaURI, aiName: string, data: StormEvent) {
55
57
  switch (data.type) {
56
58
  case 'SCREEN':
59
+ const ref = blockUri.toNormalizedString();
57
60
  this.out.emit('data', {
58
61
  type: 'SCREEN',
59
62
  reason: data.reason,
@@ -61,6 +64,8 @@ export class StormCodegen {
61
64
  payload: {
62
65
  ...data.payload,
63
66
  blockName: aiName,
67
+ blockRef: ref,
68
+ instanceId: StormEventParser.toInstanceIdFromRef(ref),
64
69
  },
65
70
  });
66
71
  case 'FILE':
@@ -71,6 +76,7 @@ export class StormCodegen {
71
76
  private handleFileOutput(blockUri: KapetaURI, aiName: string, data: StormEvent) {
72
77
  switch (data.type) {
73
78
  case 'FILE':
79
+ const ref = blockUri.toNormalizedString();
74
80
  this.emitFile(blockUri, aiName, data.payload.filename, data.payload.content, data.reason);
75
81
  return {
76
82
  type: 'FILE',
@@ -78,11 +84,17 @@ export class StormCodegen {
78
84
  payload: {
79
85
  filename: data.payload.filename,
80
86
  content: data.payload.content,
87
+ blockRef: ref,
88
+ instanceId: StormEventParser.toInstanceIdFromRef(ref),
81
89
  },
82
90
  } as StormEventFile;
83
91
  }
84
92
  }
85
93
 
94
+ private getBasePath(blockName: string) {
95
+ return path.join(this.tmpDir, blockName);
96
+ }
97
+
86
98
  /**
87
99
  * Generates the code for a block and sends it to the AI
88
100
  */
@@ -135,7 +147,7 @@ export class StormCodegen {
135
147
  );
136
148
  }
137
149
 
138
- const basePath = path.join(os.tmpdir(), block.content.metadata.name);
150
+ const basePath = this.getBasePath(block.content.metadata.name);
139
151
 
140
152
  for (const serviceFile of serviceFiles) {
141
153
  const filePath = join(basePath, serviceFile.filename);
@@ -185,15 +197,19 @@ export class StormCodegen {
185
197
  content: string,
186
198
  reason: string = 'File generated'
187
199
  ) {
200
+ const basePath = this.getBasePath(uri.fullName);
201
+ const ref = uri.toNormalizedString();
188
202
  this.out.emit('data', {
189
203
  type: 'FILE',
190
204
  reason,
191
205
  created: Date.now(),
192
206
  payload: {
193
207
  filename: filename,
208
+ path: join(basePath, filename),
194
209
  content: content,
195
210
  blockName,
196
- blockRef: uri.toNormalizedString(),
211
+ blockRef: ref,
212
+ instanceId: StormEventParser.toInstanceIdFromRef(ref),
197
213
  },
198
214
  } satisfies StormEventFile);
199
215
  }
@@ -283,7 +299,7 @@ export class StormCodegen {
283
299
  if (!(await codeGeneratorManager.ensureTarget(yamlContent.spec.target?.kind))) {
284
300
  return;
285
301
  }
286
- const basePath = path.join(os.tmpdir(), yamlContent.metadata.name);
302
+ const basePath = this.getBasePath(yamlContent.metadata.name);
287
303
 
288
304
  const codeGenerator = new BlockCodeGenerator(yamlContent as BlockDefinition);
289
305
  codeGenerator.withOption('AIContext', STORM_ID);
@@ -201,6 +201,23 @@ export async function resolveOptions(): Promise<StormOptions> {
201
201
  }
202
202
 
203
203
  export class StormEventParser {
204
+ public static toInstanceId(handle: string, blockName: string) {
205
+ const ref = this.toRef(handle, blockName);
206
+ return this.toInstanceIdFromRef(ref.toNormalizedString());
207
+ }
208
+
209
+ public static toInstanceIdFromRef(ref: string) {
210
+ return uuid(normalizeKapetaUri(ref), uuid.URL);
211
+ }
212
+
213
+ public static toSafeName(name: string): string {
214
+ return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
215
+ }
216
+
217
+ public static toRef(handle: string, name: string) {
218
+ return parseKapetaUri(handle + '/' + this.toSafeName(name) + ':local');
219
+ }
220
+
204
221
  private events: StormEvent[] = [];
205
222
  private planName: string = '';
206
223
  private planDescription: string = '';
@@ -225,7 +242,9 @@ export class StormEventParser {
225
242
  * Builds plan and block definitions - and enriches events with relevant refs and ids
226
243
  */
227
244
  public processEvent(handle: string, evt: StormEvent): StormDefinitions {
245
+ let blockInfo;
228
246
  this.events.push(evt);
247
+ console.log('Processing event: %s', evt.type);
229
248
  switch (evt.type) {
230
249
  case 'CREATE_PLAN_PROPERTIES':
231
250
  this.planName = evt.payload.name;
@@ -238,8 +257,8 @@ export class StormEventParser {
238
257
  models: [],
239
258
  types: [],
240
259
  };
241
- evt.payload.blockRef = this.toRef(handle, evt.payload.name).toNormalizedString();
242
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
260
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.name).toNormalizedString();
261
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
243
262
  break;
244
263
  case 'PLAN_RETRY':
245
264
  this.reset();
@@ -249,23 +268,32 @@ export class StormEventParser {
249
268
  this.error = evt.payload.error;
250
269
  break;
251
270
  case 'CREATE_API':
252
- this.blocks[evt.payload.blockName].apis.push(prettifyKaplang(evt.payload.content));
253
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
254
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
271
+ blockInfo = this.blocks[evt.payload.blockName];
272
+ blockInfo.apis.push(prettifyKaplang(evt.payload.content));
273
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
274
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
275
+
276
+ const api = blockInfo.resources.find((r) => r.type == 'API');
277
+ evt.payload.resourceName = api?.name;
278
+ break;
279
+ case 'CREATE_MODEL':
280
+ blockInfo = this.blocks[evt.payload.blockName];
281
+ blockInfo.models.push(prettifyKaplang(evt.payload.content));
282
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
283
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
284
+
285
+ const database = blockInfo.resources.find((r) => r.type == 'DATABASE');
286
+ evt.payload.resourceName = database?.name;
255
287
  break;
288
+
256
289
  case 'CREATE_TYPE':
257
290
  this.blocks[evt.payload.blockName].types.push(prettifyKaplang(evt.payload.content));
258
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
259
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
260
- break;
261
- case 'CREATE_MODEL':
262
- this.blocks[evt.payload.blockName].models.push(prettifyKaplang(evt.payload.content));
263
- evt.payload.blockRef = this.toRef(handle, evt.payload.blockName).toNormalizedString();
264
- evt.payload.instanceId = this.toInstanceIdFromRef(evt.payload.blockRef);
291
+ evt.payload.blockRef = StormEventParser.toRef(handle, evt.payload.blockName).toNormalizedString();
292
+ evt.payload.instanceId = StormEventParser.toInstanceIdFromRef(evt.payload.blockRef);
265
293
  break;
266
294
  case 'CREATE_CONNECTION':
267
- evt.payload.fromBlockId = this.toInstanceId(handle, evt.payload.fromComponent);
268
- evt.payload.toBlockId = this.toInstanceId(handle, evt.payload.toComponent);
295
+ evt.payload.fromBlockId = StormEventParser.toInstanceId(handle, evt.payload.fromComponent);
296
+ evt.payload.toBlockId = StormEventParser.toInstanceId(handle, evt.payload.toComponent);
269
297
  this.connections.push(evt.payload);
270
298
  break;
271
299
 
@@ -293,22 +321,13 @@ export class StormEventParser {
293
321
  return this.error;
294
322
  }
295
323
 
296
- private toInstanceId(handle: string, blockName: string) {
297
- const ref = this.toRef(handle, blockName);
298
- return this.toInstanceIdFromRef(ref.toNormalizedString());
299
- }
300
-
301
- private toInstanceIdFromRef(ref: string) {
302
- return uuid(normalizeKapetaUri(ref), uuid.URL);
303
- }
304
-
305
324
  public toResult(handle: string): StormDefinitions {
306
- const planRef = this.toRef(handle, this.planName ?? 'undefined');
325
+ const planRef = StormEventParser.toRef(handle, this.planName ?? 'undefined');
307
326
  const blockDefinitions = this.toBlockDefinitions(handle);
308
327
  const refIdMap: { [key: string]: string } = {};
309
328
  const blocks = Object.entries(blockDefinitions).map(([ref, block]) => {
310
329
  // Create a deterministic uuid
311
- const id = this.toInstanceIdFromRef(ref);
330
+ const id = StormEventParser.toInstanceIdFromRef(ref);
312
331
  refIdMap[ref] = id;
313
332
  return {
314
333
  id,
@@ -329,8 +348,8 @@ export class StormEventParser {
329
348
  this.connections
330
349
  .filter((connection) => connection.fromResourceType === 'API' && connection.toResourceType === 'CLIENT')
331
350
  .forEach((apiConnection) => {
332
- const apiProviderRef = this.toRef(handle, apiConnection.fromComponent);
333
- const clientConsumerRef = this.toRef(handle, apiConnection.toComponent);
351
+ const apiProviderRef = StormEventParser.toRef(handle, apiConnection.fromComponent);
352
+ const clientConsumerRef = StormEventParser.toRef(handle, apiConnection.toComponent);
334
353
  const apiProviderBlock = blockDefinitions[apiProviderRef.toNormalizedString()];
335
354
  if (!apiProviderBlock) {
336
355
  console.warn('API provider not found: %s', apiConnection.fromComponent, apiConnection);
@@ -407,8 +426,8 @@ export class StormEventParser {
407
426
  });
408
427
 
409
428
  const connections: Connection[] = this.connections.map((connection) => {
410
- const fromRef = this.toRef(handle, connection.fromComponent);
411
- const toRef = this.toRef(handle, connection.toComponent);
429
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
430
+ const toRef = StormEventParser.toRef(handle, connection.toComponent);
412
431
 
413
432
  return {
414
433
  port: {
@@ -445,19 +464,11 @@ export class StormEventParser {
445
464
  };
446
465
  }
447
466
 
448
- private toSafeName(name: string): string {
449
- return name.toLowerCase().replace(/[^0-9a-z-]/gi, '');
450
- }
451
-
452
- private toRef(handle: string, name: string) {
453
- return parseKapetaUri(handle + '/' + this.toSafeName(name) + ':local');
454
- }
455
-
456
467
  public toBlockDefinitions(handle: string): { [key: string]: BlockDefinitionInfo } {
457
468
  const result: { [key: string]: BlockDefinitionInfo } = {};
458
469
 
459
470
  Object.entries(this.blocks).forEach(([, blockInfo]) => {
460
- const blockRef = this.toRef(handle, blockInfo.name);
471
+ const blockRef = StormEventParser.toRef(handle, blockInfo.name);
461
472
 
462
473
  const blockDefinitionInfo: BlockDefinitionInfo = {
463
474
  uri: blockRef,
@@ -679,7 +690,7 @@ export class StormEventParser {
679
690
  return;
680
691
  }
681
692
 
682
- const fromRef = this.toRef(handle, connection.fromComponent);
693
+ const fromRef = StormEventParser.toRef(handle, connection.fromComponent);
683
694
 
684
695
  const apiProviderBlock = blockDefinitions[fromRef.toNormalizedString()];
685
696
  if (!apiProviderBlock) {
@@ -760,8 +771,8 @@ export class StormEventParser {
760
771
  let options: { [key: string]: any } = {};
761
772
 
762
773
  if (kind.includes('java')) {
763
- const groupId = `ai.${this.toSafeName(handle)}`;
764
- const artifactId = this.toSafeName(this.planName);
774
+ const groupId = `ai.${StormEventParser.toSafeName(handle)}`;
775
+ const artifactId = StormEventParser.toSafeName(this.planName);
765
776
  options = {
766
777
  groupId,
767
778
  artifactId,
@@ -94,7 +94,7 @@ export interface StormEventPlanRetry {
94
94
  }
95
95
 
96
96
  export interface StormEventCreateDSL {
97
- type: 'CREATE_API' | 'CREATE_TYPE' | 'CREATE_MODEL';
97
+ type: 'CREATE_TYPE';
98
98
  reason: string;
99
99
  created: number;
100
100
  payload: {
@@ -105,6 +105,19 @@ export interface StormEventCreateDSL {
105
105
  };
106
106
  }
107
107
 
108
+ export interface StormEventCreateDSLResource extends Omit<StormEventCreateDSL, 'type'> {
109
+ type: 'CREATE_API' | 'CREATE_MODEL';
110
+ reason: string;
111
+ created: number;
112
+ payload: {
113
+ blockName: string;
114
+ content: string;
115
+ blockRef?: string;
116
+ instanceId?: string;
117
+ resourceName?: string;
118
+ };
119
+ }
120
+
108
121
  export interface StormEventError {
109
122
  type: 'INVALID_RESPONSE' | 'ERROR_INTERNAL';
110
123
  reason: string;
@@ -127,6 +140,8 @@ export interface StormEventScreen {
127
140
  created: number;
128
141
  payload: {
129
142
  blockName: string;
143
+ blockRef?: string;
144
+ instanceId?: string;
130
145
  name: string;
131
146
  template: string;
132
147
  description: string;
@@ -151,9 +166,11 @@ export interface StormEventFile {
151
166
  created: number;
152
167
  payload: {
153
168
  filename: string;
169
+ path: string;
154
170
  content: string;
155
171
  blockName: string;
156
172
  blockRef: string;
173
+ instanceId: string;
157
174
  };
158
175
  }
159
176
 
@@ -176,6 +193,7 @@ export type StormEvent =
176
193
  | StormEventInvalidResponse
177
194
  | StormEventPlanRetry
178
195
  | StormEventCreateDSL
196
+ | StormEventCreateDSLResource
179
197
  | StormEventError
180
198
  | StormEventScreen
181
199
  | StormEventScreenCandidate