@kumologica/sdk 3.5.5 → 3.6.0-alpha7

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 (36) hide show
  1. package/cli/cli.js +31 -8
  2. package/cli/commands/open.js +88 -15
  3. package/cli/commands/run.js +167 -0
  4. package/cli/commands/serve.js +139 -0
  5. package/package.json +5 -5
  6. package/src/app/main-process/main-window.js +1 -0
  7. package/src/app/main-process/modal-home.js +1 -0
  8. package/src/app/main-process/modal-newproject.js +1 -0
  9. package/src/app/main-process/modal-newtab.js +1 -0
  10. package/src/app/main-process/modal-nodelibrary.js +1 -0
  11. package/src/app/main-process/modal-renameTab.js +1 -0
  12. package/src/app/main-process/modal-welcome.js +1 -0
  13. package/src/app/main.js +179 -141
  14. package/src/app/preload.js +225 -139
  15. package/src/app/ui/editor-client/public/red/red.js +1943 -783
  16. package/src/app/ui/editor-client/public/red/red.min.js +2 -2
  17. package/src/app/ui/editor-client/public/red/style.min.css +1 -1
  18. package/src/app/ui/editor-client/public/vendor/ace-linters/javascript-service.js +10 -2
  19. package/src/app/ui/editor-client/src/js/red.js +183 -179
  20. package/src/app/ui/editor-client/src/js/ui/common/commandBox.js +107 -0
  21. package/src/app/ui/editor-client/src/js/ui/common/searchBox.js +91 -90
  22. package/src/app/ui/editor-client/src/js/ui/modules.js +164 -0
  23. package/src/app/ui/editor-client/src/js/ui/search.js +171 -123
  24. package/src/app/ui/editor-client/src/js/ui/sidebar.js +1 -1
  25. package/src/app/ui/editor-client/src/js/ui/ui-settings.js +419 -410
  26. package/src/app/ui/editor-client/src/sass/editor.scss +745 -746
  27. package/src/app/ui/editor-client/src/sass/forms.scss +1 -1
  28. package/src/app/ui/editor-client/src/sass/search.scss +16 -2
  29. package/src/app/ui/editor-client/src/sass/sidebar.scss +1 -1
  30. package/src/app/ui/editor-client/src/sass/style.scss +72 -69
  31. package/src/app/ui/editor-client/src/sass/ui/common/commandBox.scss +100 -0
  32. package/src/app/ui/editor-client/src/sass/ui/common/searchBox.scss +3 -2
  33. package/src/app/ui/editor-client/src/sass/ui-settings.scss +14 -14
  34. package/src/app/ui/editor-client/src/vendor/ace-linters/build/javascript-service.js +10 -2
  35. package/src/app/ui/editor-client/templates/index.mst +2 -2
  36. package/src/server/DesignerServer.js +152 -153
@@ -5,52 +5,53 @@
5
5
  * main process (electron), kumologica runtime and itself (node part)
6
6
  */
7
7
 
8
-
9
8
  // const { AppServer, lambdify } = require('./lib/runtime-loader');
10
- const { lambdify } = require('@kumologica/runtime');
11
- const { codegen } = require('@kumologica/builder');
12
-
13
- const { DesignerServer } = require('../server/DesignerServer')
14
-
15
- const { Terminal } = require('xterm');
16
- const { FitAddon } = require('xterm-addon-fit');
17
- const electron = require('electron');
18
- const remote = require('@electron/remote');
9
+ const { lambdify } = require("@kumologica/runtime");
10
+ const { codegen } = require("@kumologica/builder");
11
+ const { DesignerServer } = require("../server/DesignerServer");
12
+ const { Terminal } = require("xterm");
13
+ const { FitAddon } = require("xterm-addon-fit");
14
+ const electron = require("electron");
15
+ const remote = require("@electron/remote");
16
+ const { exec, spawn } = require("child_process");
17
+ const chalk = require("chalk");
19
18
 
20
19
  // Parse arguments from: webPreferences.additionalArguments
21
- const argv = require('yargs/yargs')(process.argv.slice(2)).parse();
20
+ const argv = require("yargs/yargs")(process.argv.slice(2)).parse();
22
21
  const port = argv.port || 1880;
23
22
 
24
- const events = require('events');
25
- const debounce = require('debounce');
26
- const { promisify } = require('util');
23
+ const events = require("events");
24
+ const debounce = require("debounce");
25
+ const { promisify } = require("util");
27
26
 
28
- const dagre = require('dagre');
29
- const simpleGit = require('simple-git');
30
- const request = require('request');
27
+ const dagre = require("dagre");
28
+ const simpleGit = require("simple-git");
29
+ const request = require("request");
31
30
  const requestAsync = promisify(request);
32
31
 
33
- const CloudConfig = require('./lib/stores/aws-cloud-config-store');
34
- const TestConfig = require('./lib/stores/test-config-store');
35
- const KumohubConfig = require('./lib/stores/kumohub-config-store');
36
- const AzureConfig = require('./lib/stores/azure-config-store');
37
- const ProjectInfoConfig = require('./lib/stores/project-info-config-store');
38
- const { CloudConfigStore } = require('./lib/stores/settings-cloud-store');
39
- const { NetworkConfigStore } = require('./lib/stores/settings-network-store');
40
- const { OpenAIClient } = require('./lib/ai/openai');
32
+ const CloudConfig = require("./lib/stores/aws-cloud-config-store");
33
+ const TestConfig = require("./lib/stores/test-config-store");
34
+ const KumohubConfig = require("./lib/stores/kumohub-config-store");
35
+ const AzureConfig = require("./lib/stores/azure-config-store");
36
+ const ProjectInfoConfig = require("./lib/stores/project-info-config-store");
37
+ const { CloudConfigStore } = require("./lib/stores/settings-cloud-store");
38
+ const { NetworkConfigStore } = require("./lib/stores/settings-network-store");
39
+ const { OpenAIClient } = require("./lib/ai/openai");
41
40
 
42
- const AWSProfile = require('./lib/aws/aws-profile');
43
- const AWSDeployer = require('./lib/aws');
44
- const ServerlessDeployer = require('./lib/serverless');
45
- const GithubDeployer = require('./lib/github');
41
+ const AWSProfile = require("./lib/aws/aws-profile");
42
+ const AWSDeployer = require("./lib/aws");
43
+ const ServerlessDeployer = require("./lib/serverless");
44
+ const GithubDeployer = require("./lib/github");
46
45
 
47
- const { WorkspacePreferenceStore } = require('./lib/stores/workspace-preference-store');
46
+ const {
47
+ WorkspacePreferenceStore,
48
+ } = require("./lib/stores/workspace-preference-store");
48
49
 
49
- const Kumohub = require('./lib/kumohub');
50
- const deployCli = require('@kumologica/builder');
51
- const Azure = require('./lib/azure');
50
+ const Kumohub = require("./lib/kumohub");
51
+ const deployCli = require("@kumologica/builder");
52
+ const Azure = require("./lib/azure");
52
53
 
53
- const { openFileOnEditor, openFolder } = require('./lib/utils/editor');
54
+ const { openFileOnEditor, openFolder } = require("./lib/utils/editor");
54
55
 
55
56
  const terminalEmitter = new events.EventEmitter();
56
57
  const awsDeployer = new AWSDeployer(terminalEmitter);
@@ -64,14 +65,13 @@ const azure = new Azure(terminalEmitter);
64
65
 
65
66
  const DESIGNER_DEBUGGER_URL = `http://127.0.0.1:${port}/__debugger__`;
66
67
 
67
- const KUMOLOGICA_NODE_LIB_BASEURL =
68
- 'https://library.kumohub.io';
68
+ const KUMOLOGICA_NODE_LIB_BASEURL = "https://library.kumohub.io";
69
69
  const KUMOLOGICA_NODE_LIB_URL = `${KUMOLOGICA_NODE_LIB_BASEURL}/library.json`;
70
70
 
71
71
  const cloudConfigStore = new CloudConfigStore();
72
72
  const networkConfigStore = new NetworkConfigStore();
73
73
 
74
- const openAIClient = new OpenAIClient({ version: 'gpt-3.5-turbo' }); //'gpt-4'
74
+ const openAIClient = new OpenAIClient({ version: "gpt-3.5-turbo" }); //'gpt-4'
75
75
 
76
76
  // function to be called each time
77
77
  // project changes - either new project created or old project opened.
@@ -83,9 +83,10 @@ function loadConfigs() {
83
83
  dataPath: window.__kumologica.settings.projectDir,
84
84
  });
85
85
 
86
- window.__kumologica.settings.kumohubConfig = new KumohubConfig.KumohubConfigStore({
87
- dataPath: window.__kumologica.settings.projectDir,
88
- });
86
+ window.__kumologica.settings.kumohubConfig =
87
+ new KumohubConfig.KumohubConfigStore({
88
+ dataPath: window.__kumologica.settings.projectDir,
89
+ });
89
90
 
90
91
  window.__kumologica.settings.azureConfig = new AzureConfig.AzureConfigStore({
91
92
  dataPath: window.__kumologica.settings.projectDir,
@@ -95,30 +96,31 @@ function loadConfigs() {
95
96
  dataPath: window.__kumologica.settings.projectDir,
96
97
  });
97
98
 
98
- window.__kumologica.settings.projectInfoConfig = new ProjectInfoConfig.ProjectInfoConfigStore({
99
- dataPath: window.__kumologica.settings.projectDir,
100
- });
99
+ window.__kumologica.settings.projectInfoConfig =
100
+ new ProjectInfoConfig.ProjectInfoConfigStore({
101
+ dataPath: window.__kumologica.settings.projectDir,
102
+ });
101
103
  }
102
104
 
103
105
  function deploy(projectInfo, params) {
104
- const alias = cloudConfigStore.getAWSAliasInfo(window.__kumologica.cloud.profile);
106
+ const alias = cloudConfigStore.getAWSAliasInfo(
107
+ window.__kumologica.cloud.profile
108
+ );
105
109
 
106
110
  return awsDeployer.deploy(projectInfo, params, alias.profile);
107
111
  }
108
112
 
109
113
  async function kumohubBuild(projectInfo) {
110
- const { build } = require('@kumologica/builder');
114
+ const { build } = require("@kumologica/builder");
111
115
  const params = {
112
116
  "project-directory": projectInfo.projectDir,
113
117
  "flow-file-name": projectInfo.projectFlowName,
114
- "zip-file-name": "lambda.zip"
115
- }
116
-
117
- build('kumohub', params, terminalEmitter); // default options
118
+ "zip-file-name": "lambda.zip",
119
+ };
118
120
 
121
+ build("kumohub", params, terminalEmitter); // default options
119
122
  }
120
123
  async function kumohubDeploy(projectInfo, params) {
121
-
122
124
  const alias = cloudConfigStore.getKumohubAliasInfo(params.profile);
123
125
 
124
126
  params.username = alias.username;
@@ -127,7 +129,7 @@ async function kumohubDeploy(projectInfo, params) {
127
129
  params["flow-file-name"] = projectInfo.projectFlowName;
128
130
  params["project-directory"] = projectInfo.projectDir;
129
131
 
130
- return await deployCli.deploy('kumohub', params, terminalEmitter);
132
+ return await deployCli.deploy("kumohub", params, terminalEmitter);
131
133
  }
132
134
 
133
135
  async function azureDeploy(projectInfo, params) {
@@ -138,42 +140,34 @@ async function azureDeploy(projectInfo, params) {
138
140
  }
139
141
 
140
142
  async function generateScript(provider, projectInfo, params) {
141
- const alias = cloudConfigStore.getAWSAliasInfo(window.__kumologica.cloud.profile);
143
+ const alias = cloudConfigStore.getAWSAliasInfo(
144
+ window.__kumologica.cloud.profile
145
+ );
142
146
 
143
147
  if (provider == window.__kumologica.cloud.provider.aws) {
144
- await awsDeployer.generateScript(
145
- projectInfo,
146
- params,
147
- alias.profile
148
- );
148
+ await awsDeployer.generateScript(projectInfo, params, alias.profile);
149
149
  } else if (provider == window.__kumologica.cloud.provider.serverless) {
150
- await serverlessDeployer.generateScript(
151
- projectInfo,
152
- params,
153
- alias.profile
154
- );
150
+ await serverlessDeployer.generateScript(projectInfo, params, alias.profile);
155
151
  } else if (provider == window.__kumologica.cloud.provider.github) {
156
- await githubDeployer.generateScript(
157
- projectInfo,
158
- params,
159
- alias.profile
160
- );
152
+ await githubDeployer.generateScript(projectInfo, params, alias.profile);
161
153
  }
162
154
  }
163
155
 
164
156
  async function listServices(type) {
165
- const alias = cloudConfigStore.getAWSAliasInfo(window.__kumologica.cloud.profile);
157
+ const alias = cloudConfigStore.getAWSAliasInfo(
158
+ window.__kumologica.cloud.profile
159
+ );
166
160
 
167
161
  let lServices = await awsDeployer.listServices(type, alias.profile);
168
162
  return lServices;
169
163
  }
170
164
 
171
165
  function hasJsonStructure(str) {
172
- if (typeof str !== 'string') return false;
166
+ if (typeof str !== "string") return false;
173
167
  try {
174
168
  const result = JSON.parse(str);
175
169
  const type = Object.prototype.toString.call(result);
176
- return type === '[object Object]' || type === '[object Array]';
170
+ return type === "[object Object]" || type === "[object Array]";
177
171
  } catch (err) {
178
172
  return false;
179
173
  }
@@ -189,10 +183,9 @@ async function getRegion(profile) {
189
183
  }
190
184
 
191
185
  async function testFlow(testEvent, targetNode, environmentVariables) {
192
-
193
186
  let event;
194
187
 
195
- targetNode = targetNode || '*';
188
+ targetNode = targetNode || "*";
196
189
  try {
197
190
  // TODO: we should check not only if data is json parsable, but also if it is well-formed JSON structure
198
191
  // Eg. 1234, "hello world"
@@ -203,13 +196,13 @@ async function testFlow(testEvent, targetNode, environmentVariables) {
203
196
  throw err;
204
197
  }
205
198
 
206
- headers = { ...headers, 'x-kumologica-testcasenode': targetNode };
199
+ headers = { ...headers, "x-kumologica-testcasenode": targetNode };
207
200
 
208
201
  if (environmentVariables) {
209
202
  if (Object.keys(environmentVariables).length > 0) {
210
203
  headers = {
211
204
  ...headers,
212
- 'x-kumologica-aws-env': JSON.stringify(environmentVariables),
205
+ "x-kumologica-aws-env": JSON.stringify(environmentVariables),
213
206
  };
214
207
  }
215
208
  }
@@ -217,53 +210,71 @@ async function testFlow(testEvent, targetNode, environmentVariables) {
217
210
  if (environmentVariables && environmentVariables["AWS_PROFILE"]) {
218
211
  headers = {
219
212
  ...headers,
220
- 'x-kumologica-aws-profile': environmentVariables["AWS_PROFILE"],
213
+ "x-kumologica-aws-profile": environmentVariables["AWS_PROFILE"],
221
214
  };
222
215
 
223
216
  const region = await new AWSProfile().getRegion(
224
217
  environmentVariables["AWS_PROFILE"]
225
218
  );
226
219
 
227
- headers = { ...headers, 'x-kumologica-aws-region': region };
220
+ headers = { ...headers, "x-kumologica-aws-region": region };
228
221
  } else {
229
- terminalEmitter.emit('terminal-output', " ");
230
- terminalEmitter.emit('terminal-output', "AWS_PROFILE property not defined on test tab, default aws cli precedence will be used.");
231
- terminalEmitter.emit('terminal-output', "For details see: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html");
232
- terminalEmitter.emit('terminal-output', " ");
233
- terminalEmitter.emit('terminal-output', "Your environment variables:");
234
- terminalEmitter.emit('terminal-output', ` AWS_PROFILE: ${process.env.AWS_PROFILE}`);
235
- terminalEmitter.emit('terminal-output', ` AWS_REGION: ${process.env.AWS_REGION}`);
236
- terminalEmitter.emit('terminal-output', ` AWS_ACCESS_KEY_ID: ${process.env.AWS_ACCESS_KEY_ID}`);
237
- terminalEmitter.emit('terminal-output', ` AWS_SECRET_ACCESS_KEY: ${process.env.AWS_SECRET_ACCESS_KEY}`);
238
- terminalEmitter.emit('terminal-output', " ");
222
+ terminalEmitter.emit("terminal-output", " ");
223
+ terminalEmitter.emit(
224
+ "terminal-output",
225
+ "AWS_PROFILE property not defined on test tab, default aws cli precedence will be used."
226
+ );
227
+ terminalEmitter.emit(
228
+ "terminal-output",
229
+ "For details see: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html"
230
+ );
231
+ terminalEmitter.emit("terminal-output", " ");
232
+ terminalEmitter.emit("terminal-output", "Your environment variables:");
233
+ terminalEmitter.emit(
234
+ "terminal-output",
235
+ ` AWS_PROFILE: ${process.env.AWS_PROFILE}`
236
+ );
237
+ terminalEmitter.emit(
238
+ "terminal-output",
239
+ ` AWS_REGION: ${process.env.AWS_REGION}`
240
+ );
241
+ terminalEmitter.emit(
242
+ "terminal-output",
243
+ ` AWS_ACCESS_KEY_ID: ${process.env.AWS_ACCESS_KEY_ID}`
244
+ );
245
+ terminalEmitter.emit(
246
+ "terminal-output",
247
+ ` AWS_SECRET_ACCESS_KEY: ${process.env.AWS_SECRET_ACCESS_KEY}`
248
+ );
249
+ terminalEmitter.emit("terminal-output", " ");
239
250
  }
240
- console.log('[preload] Invoking the testFlow...');
251
+ console.log("[preload] Invoking the testFlow...");
241
252
  try {
242
253
  let resp = await requestAsync({
243
254
  uri: `http://127.0.0.1:${port}/`,
244
- method: 'POST',
255
+ method: "POST",
245
256
  headers: headers,
246
257
  body: event,
247
258
  json: true,
248
259
  });
249
- console.log('[preload] Response:', resp.body);
260
+ console.log("[preload] Response:", resp.body);
250
261
  return resp;
251
262
  } catch (err) {
252
- console.log('[preload] Request end with errors...', e);
263
+ console.log("[preload] Request end with errors...", e);
253
264
  throw e;
254
265
  }
255
266
  }
256
267
 
257
- /**
268
+ /**
258
269
  * Debugger API Client endpoints
259
270
  */
260
271
 
261
272
  async function addBreakpoint(id) {
262
- const url = `${DESIGNER_DEBUGGER_URL}/add-breakpoint/${id}`
273
+ const url = `${DESIGNER_DEBUGGER_URL}/add-breakpoint/${id}`;
263
274
 
264
275
  let options = {
265
276
  uri: url,
266
- method: 'GET',
277
+ method: "GET",
267
278
  json: true,
268
279
  };
269
280
 
@@ -275,7 +286,7 @@ async function addBreakpoint(id) {
275
286
  console.log(
276
287
  `Received a "${statusCode}" from Kumologica Node Library host`
277
288
  );
278
- return '';
289
+ return "";
279
290
  }
280
291
  } catch (err) {
281
292
  throw err;
@@ -283,11 +294,11 @@ async function addBreakpoint(id) {
283
294
  }
284
295
 
285
296
  async function removeAllBreakpoints() {
286
- const url = `${DESIGNER_DEBUGGER_URL}/remove-all-breakpoints`
297
+ const url = `${DESIGNER_DEBUGGER_URL}/remove-all-breakpoints`;
287
298
 
288
299
  let options = {
289
300
  uri: url,
290
- method: 'GET',
301
+ method: "GET",
291
302
  json: true,
292
303
  };
293
304
 
@@ -296,15 +307,14 @@ async function removeAllBreakpoints() {
296
307
  } catch (err) {
297
308
  throw err;
298
309
  }
299
-
300
310
  }
301
311
 
302
312
  async function isBreakpointFound(id) {
303
- const url = `${DESIGNER_DEBUGGER_URL}/contains-breakpoint/${id}`
313
+ const url = `${DESIGNER_DEBUGGER_URL}/contains-breakpoint/${id}`;
304
314
 
305
315
  let options = {
306
316
  uri: url,
307
- method: 'GET',
317
+ method: "GET",
308
318
  json: true,
309
319
  };
310
320
 
@@ -313,15 +323,14 @@ async function isBreakpointFound(id) {
313
323
  } catch (err) {
314
324
  throw err;
315
325
  }
316
-
317
326
  }
318
327
 
319
328
  async function toggleBreakpoint(id) {
320
- const url = `${DESIGNER_DEBUGGER_URL}/toggle-breakpoint/${id}`
329
+ const url = `${DESIGNER_DEBUGGER_URL}/toggle-breakpoint/${id}`;
321
330
 
322
331
  let options = {
323
332
  uri: url,
324
- method: 'GET',
333
+ method: "GET",
325
334
  json: true,
326
335
  };
327
336
 
@@ -330,15 +339,14 @@ async function toggleBreakpoint(id) {
330
339
  } catch (err) {
331
340
  throw err;
332
341
  }
333
-
334
342
  }
335
343
 
336
344
  async function enableDebugger() {
337
- const url = `${DESIGNER_DEBUGGER_URL}/enable`
345
+ const url = `${DESIGNER_DEBUGGER_URL}/enable`;
338
346
 
339
347
  let options = {
340
348
  uri: url,
341
- method: 'GET',
349
+ method: "GET",
342
350
  json: true,
343
351
  };
344
352
 
@@ -349,13 +357,12 @@ async function enableDebugger() {
349
357
  }
350
358
  }
351
359
 
352
-
353
360
  async function listBreakpoints() {
354
- const url = `${DESIGNER_DEBUGGER_URL}/list-breakpoints`
361
+ const url = `${DESIGNER_DEBUGGER_URL}/list-breakpoints`;
355
362
 
356
363
  let options = {
357
364
  uri: url,
358
- method: 'GET',
365
+ method: "GET",
359
366
  json: true,
360
367
  };
361
368
 
@@ -367,11 +374,11 @@ async function listBreakpoints() {
367
374
  }
368
375
 
369
376
  async function redrawBreakpoints() {
370
- const url = `${DESIGNER_DEBUGGER_URL}/redraw-breakpoints`
377
+ const url = `${DESIGNER_DEBUGGER_URL}/redraw-breakpoints`;
371
378
 
372
379
  let options = {
373
380
  uri: url,
374
- method: 'GET',
381
+ method: "GET",
375
382
  json: true,
376
383
  };
377
384
 
@@ -383,11 +390,11 @@ async function redrawBreakpoints() {
383
390
  }
384
391
 
385
392
  async function disableDebugger() {
386
- const url = `${DESIGNER_DEBUGGER_URL}/disable`
393
+ const url = `${DESIGNER_DEBUGGER_URL}/disable`;
387
394
 
388
395
  let options = {
389
396
  uri: url,
390
- method: 'GET',
397
+ method: "GET",
391
398
  json: true,
392
399
  };
393
400
 
@@ -399,11 +406,11 @@ async function disableDebugger() {
399
406
  }
400
407
 
401
408
  async function continueDebugger() {
402
- const url = `${DESIGNER_DEBUGGER_URL}/continue`
409
+ const url = `${DESIGNER_DEBUGGER_URL}/continue`;
403
410
 
404
411
  let options = {
405
412
  uri: url,
406
- method: 'GET',
413
+ method: "GET",
407
414
  json: true,
408
415
  };
409
416
 
@@ -415,11 +422,11 @@ async function continueDebugger() {
415
422
  }
416
423
 
417
424
  async function stopDebugger() {
418
- const url = `${DESIGNER_DEBUGGER_URL}/stop`
425
+ const url = `${DESIGNER_DEBUGGER_URL}/stop`;
419
426
 
420
427
  let options = {
421
428
  uri: url,
422
- method: 'GET',
429
+ method: "GET",
423
430
  json: true,
424
431
  };
425
432
 
@@ -431,11 +438,11 @@ async function stopDebugger() {
431
438
  }
432
439
 
433
440
  async function nextDebugger() {
434
- const url = `${DESIGNER_DEBUGGER_URL}/next`
441
+ const url = `${DESIGNER_DEBUGGER_URL}/next`;
435
442
 
436
443
  let options = {
437
444
  uri: url,
438
- method: 'GET',
445
+ method: "GET",
439
446
  json: true,
440
447
  };
441
448
 
@@ -447,11 +454,11 @@ async function nextDebugger() {
447
454
  }
448
455
 
449
456
  async function terminateDebugger() {
450
- const url = `${DESIGNER_DEBUGGER_URL}/terminate`
457
+ const url = `${DESIGNER_DEBUGGER_URL}/terminate`;
451
458
 
452
459
  let options = {
453
460
  uri: url,
454
- method: 'GET',
461
+ method: "GET",
455
462
  json: true,
456
463
  };
457
464
 
@@ -470,14 +477,14 @@ async function fetchAvailableNodes() {
470
477
 
471
478
  let options = {
472
479
  uri: KUMOLOGICA_NODE_LIB_URL,
473
- method: 'GET',
480
+ method: "GET",
474
481
  json: true,
475
482
  };
476
483
 
477
484
  // Inject proxy header if required
478
485
  let proxyHeader = RED.uiSettings.getProxyHeader();
479
486
  if (proxyHeader) {
480
- options.proxy = proxyHeader
487
+ options.proxy = proxyHeader;
481
488
  }
482
489
 
483
490
  try {
@@ -528,11 +535,11 @@ function kumohubIsLoggedIn(profile) {
528
535
  function validateAlias(alias) {
529
536
  let msg = undefined;
530
537
  if (!alias.username) {
531
- msg = 'Invalid kumohub profile, missing username.';
538
+ msg = "Invalid kumohub profile, missing username.";
532
539
  } else if (!alias.password) {
533
- msg = 'Invalid kumohub profile, missing password.';
540
+ msg = "Invalid kumohub profile, missing password.";
534
541
  } else if (!alias.subscription) {
535
- msg = 'Invalid kumohub profile, missing subscription';
542
+ msg = "Invalid kumohub profile, missing subscription";
536
543
  }
537
544
 
538
545
  if (msg) {
@@ -563,25 +570,104 @@ function dispatch(type, payload) {
563
570
  ipcRenderer.send(type, payload);
564
571
  }
565
572
 
573
+ function includeNodePathIntoPath() {
574
+ // Include the node_path into the path, otherwise the npm wont be found if dynamically exported
575
+ if (process.env.NODE_PATH) {
576
+ const shellEnvSeparator = process.platform === "win32" ? ";" : ":";
577
+ return process.env.NODE_PATH + shellEnvSeparator + process.env.PATH;
578
+ } else {
579
+ return process.env.PATH;
580
+ }
581
+ }
582
+
583
+ async function npmInstall(dependency) {
584
+ return new Promise((resolve, reject) => {
585
+ window.__kumologica.editor.terminal.eventEmitter.emit(
586
+ "terminal-output",
587
+ `Running ${dependency} in directory: ${window.__kumologica.settings.projectDir}...`
588
+ );
589
+
590
+ // Break the dependency (string) into command + args
591
+ const parts = dependency.trim().split(" ");
592
+ let command = parts[0];
593
+ const args = parts.slice(1);
594
+
595
+ const child = spawn(command, args, {
596
+ cwd: window.__kumologica.settings.projectDir,
597
+ env: {
598
+ ...process.env,
599
+ PATH: includeNodePathIntoPath(),
600
+ },
601
+ shell: true,
602
+ });
603
+
604
+ // Stream stdout data
605
+ child.stdout.on("data", (data) => {
606
+ window.__kumologica.editor.terminal.eventEmitter.emit(
607
+ "terminal-output",
608
+ data.toString()
609
+ );
610
+ });
611
+
612
+ // Stream stderr data
613
+ child.stderr.on("data", (data) => {
614
+ window.__kumologica.editor.terminal.eventEmitter.emit(
615
+ "terminal-output",
616
+ data.toString()
617
+ );
618
+ });
619
+
620
+ // Handle process exit
621
+ child.on("close", (code) => {
622
+ console.log("preload: close with code:", code);
623
+
624
+ if (code !== 0) {
625
+ let message =
626
+ code === 127
627
+ ? `The task failed with exit code ${code}. Please ensure that the NODE_PATH environment variable is correctly set and exported in your system's environment.`
628
+ : `The task failed with exit code ${code}`;
629
+
630
+ window.__kumologica.editor.terminal.eventEmitter.emit(
631
+ "terminal-output",
632
+ `❌ Error: ${message}`
633
+ );
634
+ reject(new Error(message));
635
+ } else {
636
+ window.__kumologica.editor.terminal.eventEmitter.emit(
637
+ "terminal-output",
638
+ `✅ Done.`
639
+ );
640
+ resolve();
641
+ }
642
+ });
643
+
644
+ // Handle execution errors
645
+ child.on("error", (error) => {
646
+ window.__kumologica.editor.terminal.eventEmitter.emit(
647
+ "terminal-output",
648
+ `Error: ${error.message}`
649
+ );
650
+ });
651
+ });
652
+ }
566
653
 
567
654
  window.__kumologica = {};
568
655
  window.__kumologica.electron = electron;
569
656
  window.__kumologica.electron.remote = remote;
570
657
 
571
-
572
658
  // Present a contract to interact with main process
573
659
  window.__kumologica.main = {};
574
660
  window.__kumologica.main.dispatch = dispatch;
575
661
 
576
662
  // Present a contract to interact with editor project (itself)
577
663
  window.__kumologica.editor = {};
578
- window.__kumologica.editor.runner = require('./ui/editor-api/lib/runner');
664
+ window.__kumologica.editor.runner = require("./ui/editor-api/lib/runner");
579
665
 
580
666
  // terminal section
581
667
  window.__kumologica.editor.terminal = {};
582
668
  window.__kumologica.editor.terminal.opts = {
583
669
  fontSize: 13,
584
- fontFamily: 'Ubuntu Mono, courier-new, courier, monospace',
670
+ fontFamily: "Ubuntu Mono, courier-new, courier, monospace",
585
671
  };
586
672
  window.__kumologica.editor.terminal.Terminal = Terminal;
587
673
  window.__kumologica.editor.terminal.FitAddon = FitAddon;
@@ -594,13 +680,13 @@ window.__kumologica.settings.loadConfigs = loadConfigs;
594
680
 
595
681
  window.__kumologica.settings.cloudConfigStore = cloudConfigStore;
596
682
  window.__kumologica.settings.networkConfigStore = networkConfigStore;
597
- window.__kumologica.settings.workspacePreferenceStore = new WorkspacePreferenceStore();
683
+ window.__kumologica.settings.workspacePreferenceStore =
684
+ new WorkspacePreferenceStore();
598
685
 
599
686
  window.__kumologica.settings.platform = {};
600
- window.__kumologica.settings.platform.isMac = process.platform === 'darwin';
601
- window.__kumologica.settings.platform.isWindows = process.platform === 'win32';
602
- window.__kumologica.settings.platform.isLinux = process.platform === 'linux';
603
-
687
+ window.__kumologica.settings.platform.isMac = process.platform === "darwin";
688
+ window.__kumologica.settings.platform.isWindows = process.platform === "win32";
689
+ window.__kumologica.settings.platform.isLinux = process.platform === "linux";
604
690
 
605
691
  // Present a contract to interact with runtime project
606
692
  window.__kumologica.runtime = {};
@@ -643,7 +729,7 @@ window.__kumologica.azure.deploy = azureDeploy;
643
729
  // Expose utilities and extra libs
644
730
  window.__kumologica.libs = {};
645
731
  window.__kumologica.libs.debounce = debounce;
646
- window.__kumologica.libs.path = require('path');
732
+ window.__kumologica.libs.path = require("path");
647
733
  window.__kumologica.libs.testFlow = testFlow;
648
734
  window.__kumologica.libs.openFileOnEditor = openFileOnEditor;
649
735
  window.__kumologica.libs.openFolder = openFolder;
@@ -655,8 +741,8 @@ window.__kumologica.libs.openAIClient = openAIClient;
655
741
 
656
742
  /**
657
743
  * Return the name of the valid kumologica flow or undefined otherwise.
658
- * @param {} projectDir
659
- * @returns
744
+ * @param {} projectDir
745
+ * @returns
660
746
  */
661
747
  function findValidKumologicaFlowInDir(projectDir) {
662
748
  return codegen.findFlowFile(projectDir);
@@ -686,6 +772,6 @@ window.__kumologica.debugger.terminate = terminateDebugger;
686
772
  window.__kumologica.debugger.next = nextDebugger;
687
773
  window.__kumologica.debugger.stop = stopDebugger;
688
774
 
689
-
690
-
691
-
775
+ // Commands
776
+ window.__kumologica.command = {};
777
+ window.__kumologica.command.npmInstall = npmInstall;