cyberia 3.0.2 → 3.1.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.
Files changed (182) hide show
  1. package/{.env.production → .env.example} +20 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +41 -10
  3. package/.github/workflows/engine-cyberia.ci.yml +53 -14
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/gitlab.ci.yml +1 -1
  6. package/.github/workflows/hardhat.ci.yml +82 -0
  7. package/.github/workflows/npmpkg.ci.yml +37 -8
  8. package/.github/workflows/publish.ci.yml +5 -5
  9. package/.github/workflows/publish.cyberia.ci.yml +5 -5
  10. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
  11. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  12. package/.github/workflows/release.cd.yml +3 -2
  13. package/.vscode/extensions.json +9 -8
  14. package/.vscode/settings.json +3 -2
  15. package/CHANGELOG.md +533 -290
  16. package/CLI-HELP.md +79 -53
  17. package/WHITE-PAPER.md +1540 -0
  18. package/bin/build.js +16 -11
  19. package/bin/cyberia.js +959 -8
  20. package/bin/deploy.js +103 -270
  21. package/bin/file.js +2 -1
  22. package/bin/index.js +959 -8
  23. package/bin/vs.js +3 -3
  24. package/conf.js +277 -77
  25. package/deployment.yaml +218 -4
  26. package/hardhat/.env.example +31 -0
  27. package/hardhat/README.md +531 -0
  28. package/hardhat/WHITE-PAPER.md +1540 -0
  29. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  30. package/hardhat/deployments/.gitkeep +0 -0
  31. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  32. package/hardhat/hardhat.config.js +136 -0
  33. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  34. package/hardhat/networks/besu-object-layer.network.json +138 -0
  35. package/hardhat/package-lock.json +7628 -0
  36. package/hardhat/package.json +45 -0
  37. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  38. package/hardhat/test/ObjectLayerToken.js +590 -0
  39. package/jsdoc.dd-cyberia.json +59 -0
  40. package/jsdoc.json +20 -13
  41. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  42. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  43. package/manifests/deployment/dd-cyberia-development/deployment.yaml +490 -0
  44. package/manifests/deployment/dd-cyberia-development/proxy.yaml +261 -0
  45. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
  46. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  47. package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
  48. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  49. package/manifests/pv-pvc-dd.yaml +1 -1
  50. package/package.json +60 -50
  51. package/proxy.yaml +128 -9
  52. package/pv-pvc.yaml +132 -0
  53. package/scripts/k3s-node-setup.sh +1 -1
  54. package/scripts/ports-ls.sh +2 -0
  55. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +3 -1
  56. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +1 -2
  57. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +40 -7
  58. package/src/api/document/document.service.js +1 -1
  59. package/src/api/file/file.controller.js +3 -1
  60. package/src/api/file/file.service.js +28 -5
  61. package/src/api/ipfs/ipfs.service.js +2 -2
  62. package/src/api/object-layer/object-layer.controller.js +6 -2
  63. package/src/api/object-layer/object-layer.model.js +67 -21
  64. package/src/api/object-layer/object-layer.router.js +668 -42
  65. package/src/api/object-layer/object-layer.service.js +10 -16
  66. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
  67. package/src/api/user/user.router.js +10 -5
  68. package/src/api/user/user.service.js +7 -7
  69. package/src/cli/baremetal.js +6 -10
  70. package/src/cli/cloud-init.js +0 -3
  71. package/src/cli/db.js +54 -71
  72. package/src/cli/deploy.js +64 -12
  73. package/src/cli/env.js +5 -5
  74. package/src/cli/fs.js +0 -2
  75. package/src/cli/image.js +0 -3
  76. package/src/cli/index.js +41 -13
  77. package/src/cli/monitor.js +5 -6
  78. package/src/cli/repository.js +329 -46
  79. package/src/cli/run.js +210 -122
  80. package/src/cli/secrets.js +1 -3
  81. package/src/cli/ssh.js +1 -1
  82. package/src/client/Itemledger.index.js +1 -959
  83. package/src/client/Underpost.index.js +36 -0
  84. package/src/client/components/core/AgGrid.js +20 -5
  85. package/src/client/components/core/Alert.js +2 -2
  86. package/src/client/components/core/Content.js +22 -3
  87. package/src/client/components/core/Docs.js +30 -6
  88. package/src/client/components/core/FileExplorer.js +71 -4
  89. package/src/client/components/core/Input.js +1 -1
  90. package/src/client/components/core/Modal.js +22 -6
  91. package/src/client/components/core/PublicProfile.js +3 -3
  92. package/src/client/components/core/RichText.js +1 -2
  93. package/src/client/components/core/Router.js +34 -1
  94. package/src/client/components/core/Worker.js +1 -1
  95. package/src/client/components/cryptokoyn/CssCryptokoyn.js +63 -1
  96. package/src/client/components/cyberia/ObjectLayerEngineModal.js +145 -119
  97. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +64 -6
  98. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +1 -0
  99. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
  100. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +0 -1
  101. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +64 -2
  102. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +1 -0
  103. package/src/client/components/itemledger/CssItemledger.js +62 -0
  104. package/src/client/components/underpost/CommonUnderpost.js +29 -0
  105. package/src/client/components/underpost/CssUnderpost.js +281 -0
  106. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
  107. package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
  108. package/src/client/components/underpost/ElementsUnderpost.js +38 -0
  109. package/src/client/components/underpost/LabGalleryUnderpost.js +82 -0
  110. package/src/client/components/underpost/LogInUnderpost.js +23 -0
  111. package/src/client/components/underpost/LogOutUnderpost.js +15 -0
  112. package/src/client/components/underpost/MenuUnderpost.js +691 -0
  113. package/src/client/components/underpost/RoutesUnderpost.js +47 -0
  114. package/src/client/components/underpost/SettingsUnderpost.js +16 -0
  115. package/src/client/components/underpost/SignUpUnderpost.js +9 -0
  116. package/src/client/components/underpost/SocketIoUnderpost.js +54 -0
  117. package/src/client/components/underpost/TranslateUnderpost.js +10 -0
  118. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  119. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  120. package/src/client/public/cryptokoyn/microdata.json +85 -0
  121. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  122. package/src/client/public/cryptokoyn/sitemap +3 -3
  123. package/src/client/public/default/sitemap +3 -3
  124. package/src/client/public/itemledger/browserconfig.xml +2 -2
  125. package/src/client/public/itemledger/manifest.webmanifest +4 -4
  126. package/src/client/public/itemledger/microdata.json +71 -0
  127. package/src/client/public/itemledger/sitemap +3 -3
  128. package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
  129. package/src/client/public/test/sitemap +3 -3
  130. package/src/client/services/object-layer/object-layer.management.js +23 -4
  131. package/src/client/ssr/body/404.js +15 -11
  132. package/src/client/ssr/body/500.js +15 -11
  133. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  134. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +83 -0
  135. package/src/client/ssr/head/PwaItemledger.js +60 -0
  136. package/src/client/ssr/head/UnderpostScripts.js +6 -0
  137. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  138. package/src/client/ssr/pages/Test.js +11 -10
  139. package/src/client.build.js +0 -3
  140. package/src/client.dev.js +0 -3
  141. package/src/db/DataBaseProvider.js +17 -2
  142. package/src/db/mariadb/MariaDB.js +14 -9
  143. package/src/db/mongo/MongooseDB.js +17 -1
  144. package/src/index.js +1 -1
  145. package/src/proxy.js +0 -3
  146. package/src/runtime/express/Express.js +15 -9
  147. package/src/runtime/lampp/Lampp.js +6 -13
  148. package/src/server/auth.js +12 -14
  149. package/src/server/backup.js +2 -3
  150. package/src/server/besu-genesis-generator.js +1630 -0
  151. package/src/server/client-build-docs.js +126 -17
  152. package/src/server/client-build-live.js +9 -18
  153. package/src/server/client-build.js +203 -75
  154. package/src/server/client-dev-server.js +14 -13
  155. package/src/server/conf.js +376 -164
  156. package/src/server/cron.js +2 -1
  157. package/src/server/dns.js +28 -12
  158. package/src/server/downloader.js +0 -2
  159. package/src/server/logger.js +27 -9
  160. package/src/server/object-layer.js +92 -16
  161. package/src/server/peer.js +0 -2
  162. package/src/server/process.js +1 -50
  163. package/src/server/proxy.js +4 -8
  164. package/src/server/runtime.js +5 -8
  165. package/src/server/semantic-layer-generator.js +1 -0
  166. package/src/server/ssr.js +0 -3
  167. package/src/server/start.js +19 -12
  168. package/src/server/tls.js +0 -2
  169. package/src/server.js +0 -4
  170. package/.env.development +0 -43
  171. package/.env.test +0 -43
  172. package/hardhat/contracts/CryptoKoyn.sol +0 -59
  173. package/hardhat/contracts/ItemLedger.sol +0 -73
  174. package/hardhat/contracts/Lock.sol +0 -34
  175. package/hardhat/hardhat.config.cjs +0 -45
  176. package/hardhat/ignition/modules/Lock.js +0 -18
  177. package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
  178. package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
  179. package/hardhat/scripts/deployItemledger.cjs +0 -25
  180. package/hardhat/test/Lock.js +0 -126
  181. package/hardhat/white-paper.md +0 -581
  182. package/white-paper.md +0 -581
package/src/cli/run.js CHANGED
@@ -4,13 +4,14 @@
4
4
  * @namespace UnderpostRun
5
5
  */
6
6
 
7
- import { daemonProcess, getTerminalPid, openTerminal, shellCd, shellExec } from '../server/process.js';
7
+ import { daemonProcess, getTerminalPid, shellCd, shellExec } from '../server/process.js';
8
8
  import {
9
9
  awaitDeployMonitor,
10
10
  buildKindPorts,
11
11
  Config,
12
12
  getNpmRootPath,
13
13
  isDeployRunnerContext,
14
+ loadConfServerJson,
14
15
  writeEnv,
15
16
  } from '../server/conf.js';
16
17
  import { actionInitLog, loggerFactory } from '../server/logger.js';
@@ -32,7 +33,6 @@ const logger = loggerFactory(import.meta);
32
33
  * @property {string} podName - The name of the pod to run.
33
34
  * @property {string} nodeName - The name of the node to run.
34
35
  * @property {number} port - Custom port to use.
35
- * @property {boolean} etcHosts - Whether to modify /etc/hosts.
36
36
  * @property {string} volumeHostPath - The host path for the volume.
37
37
  * @property {string} volumeMountPath - The mount path for the volume.
38
38
  * @property {string} imageName - The name of the image to run.
@@ -56,7 +56,6 @@ const logger = loggerFactory(import.meta);
56
56
  * @property {string} apiVersion - The API version for the container.
57
57
  * @property {string} claimName - The claim name for the volume.
58
58
  * @property {string} kindType - The kind of resource to create.
59
- * @property {boolean} terminal - Whether to open a terminal.
60
59
  * @property {number} devProxyPortOffset - The port offset for the development proxy.
61
60
  * @property {boolean} hostNetwork - Whether to use host networking.
62
61
  * @property {string} requestsMemory - The memory request for the container.
@@ -85,9 +84,13 @@ const logger = loggerFactory(import.meta);
85
84
  * @property {string} monitorStatusKindType - The monitor status kind type option.
86
85
  * @property {string} monitorStatusDeltaMs - The monitor status delta in milliseconds.
87
86
  * @property {string} monitorStatusMaxAttempts - The maximum number of attempts for monitor status.
87
+ * @property {boolean} logs - Whether to enable logs.
88
88
  * @property {boolean} dryRun - Whether to perform a dry run.
89
89
  * @property {boolean} createJobNow - Whether to create the job immediately.
90
- * @property {boolean} logs - Whether to enable logs.
90
+ * @property {number} fromNCommit - Number of commits back to use for message propagation (default: 1, last commit only).
91
+ * @property {string|Array<{ip: string, hostnames: string[]}>} hostAliases - Adds entries to the Pod /etc/hosts via Kubernetes hostAliases.
92
+ * As a string (CLI): semicolon-separated entries of "ip=hostname1,hostname2" (e.g., "127.0.0.1=foo.local,bar.local;10.1.2.3=foo.remote").
93
+ * As an array (programmatic): objects with `ip` and `hostnames` fields (e.g., [{ ip: "127.0.0.1", hostnames: ["foo.local"] }]).
91
94
  * @memberof UnderpostRun
92
95
  */
93
96
  const DEFAULT_OPTION = {
@@ -118,7 +121,6 @@ const DEFAULT_OPTION = {
118
121
  apiVersion: '',
119
122
  claimName: '',
120
123
  kindType: '',
121
- terminal: false,
122
124
  devProxyPortOffset: 0,
123
125
  hostNetwork: false,
124
126
  requestsMemory: '',
@@ -150,6 +152,8 @@ const DEFAULT_OPTION = {
150
152
  logs: false,
151
153
  dryRun: false,
152
154
  createJobNow: false,
155
+ fromNCommit: 0,
156
+ hostAliases: '',
153
157
  };
154
158
 
155
159
  /**
@@ -192,7 +196,7 @@ class UnderpostRun {
192
196
  }
193
197
 
194
198
  {
195
- // Detect MongoDB primary pod using centralized method
199
+ // Detect MongoDB primary pod using method
196
200
  let primaryMongoHost = 'mongodb-0.mongodb-service';
197
201
  try {
198
202
  const primaryPodName = Underpost.db.getMongoPrimaryPodName({
@@ -352,58 +356,87 @@ class UnderpostRun {
352
356
  },
353
357
  /**
354
358
  * @method template-deploy
355
- * @description Cleans up, pushes `engine-private` and `engine` repositories with a commit tag `ci package-pwa-microservices-template`.
356
- * @param {string} path - The input value, identifier, or path for the operation.
359
+ * @description Pushes `engine-private`, dispatches CI workflow to build `pwa-microservices-template`,
360
+ * and optionally triggers engine-<conf-id> CI with sync/init which in turn dispatches the CD workflow
361
+ * after the build chain completes (template → ghpkg → engine-<conf-id> → CD).
362
+ * @param {string} path - The deployment path identifier (e.g., 'sync-engine-core', 'init-engine-core', or empty for build-only).
357
363
  * @param {Object} options - The default underpost runner options for customizing workflow
358
364
  * @memberof UnderpostRun
359
365
  */
360
366
  'template-deploy': (path = '', options = DEFAULT_OPTION) => {
361
367
  const baseCommand = options.dev ? 'node bin' : 'underpost';
362
- const message = shellExec(`node bin cmt --changelog --changelog-no-hash`, { silent: true, stdout: true }).trim();
363
- shellExec(`${baseCommand} run clean`);
368
+ shellExec(`npm run security:secrets`);
369
+ const reportPath = './gitleaks-report.json';
370
+ if (fs.existsSync(reportPath) && JSON.parse(fs.readFileSync(reportPath, 'utf8')).length > 0) {
371
+ logger.error('Secrets detected in gitleaks-report.json, aborting template-deploy');
372
+ return;
373
+ }
374
+ shellExec(`${baseCommand} run pull`);
375
+
376
+ // Capture last N commit messages for propagation (default: last 1 commit)
377
+ const fromN = options.fromNCommit && parseInt(options.fromNCommit) > 0 ? parseInt(options.fromNCommit) : 1;
378
+ const message = shellExec(`node bin cmt --changelog ${fromN} --changelog-no-hash`, {
379
+ silent: true,
380
+ stdout: true,
381
+ }).trim();
382
+
364
383
  shellExec(
365
384
  `${baseCommand} push ./engine-private ${options.force ? '-f ' : ''}${
366
385
  process.env.GITHUB_USERNAME
367
386
  }/engine-private`,
368
387
  );
369
388
  shellCd('/home/dd/engine');
389
+
390
+ const sanitizedMessage = Underpost.repo.sanitizeChangelogMessage(message);
391
+
392
+ // Push engine repo so workflow YAML changes reach GitHub
370
393
  shellExec(`git reset`);
371
- function replaceNthNewline(str, n, replacement = ' ') {
372
- let count = 0;
373
- return str.replace(/\r\n?|\n/g, (match) => {
374
- count++;
375
- return count === n ? replacement : match;
376
- });
377
- }
378
- shellExec(
379
- `${baseCommand} cmt . --empty ci package-pwa-microservices-template${
380
- path.startsWith('sync') ? `-${path}` : ''
381
- }${
382
- message
383
- ? ` "${replaceNthNewline(
384
- message.replaceAll('"', '').replaceAll('`', '').replaceAll('#', '').replaceAll('- ', ''),
385
- 2,
386
- )}"`
387
- : ''
388
- }`,
389
- );
390
394
  shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
395
+
396
+ // Determine deploy conf and type from path (sync-engine-core, init-engine-core, etc.)
397
+ let deployConfId = '';
398
+ let deployType = '';
399
+ if (path.startsWith('sync-')) {
400
+ deployConfId = path.replace(/^sync-/, '');
401
+ deployType = 'sync-and-deploy';
402
+ } else if (path.startsWith('init-')) {
403
+ deployConfId = path.replace(/^init-/, '');
404
+ deployType = 'init';
405
+ }
406
+
407
+ // Dispatch npmpkg CI workflow — this builds pwa-microservices-template first.
408
+ // If deployConfId is set, npmpkg.ci.yml will dispatch the engine-<conf-id> CI
409
+ // with sync=true after template build completes. The engine CI then dispatches
410
+ // the CD workflow after the engine repo build finishes — ensuring correct sequence:
411
+ // npmpkg.ci → engine-<id>.ci → engine-<id>.cd
412
+ const repo = `${process.env.GITHUB_USERNAME}/engine`;
413
+ const inputs = {};
414
+ if (sanitizedMessage) inputs.message = sanitizedMessage;
415
+ if (deployConfId) inputs.deploy_conf_id = deployConfId;
416
+ if (deployType) inputs.deploy_type = deployType;
417
+
418
+ Underpost.repo.dispatchWorkflow({
419
+ repo,
420
+ workflowFile: 'npmpkg.ci.yml',
421
+ ref: 'master',
422
+ inputs,
423
+ });
391
424
  },
392
425
 
393
426
  /**
394
427
  * @method template-deploy-image
395
- * @description Commits and pushes a Docker image deployment for the `engine` repository.
428
+ * @description Dispatches the Docker image CI workflow for the `engine` repository.
396
429
  * @param {string} path - The input value, identifier, or path for the operation.
397
430
  * @param {Object} options - The default underpost runner options for customizing workflow
398
431
  * @memberof UnderpostRun
399
432
  */
400
433
  'template-deploy-image': (path, options = DEFAULT_OPTION) => {
401
- // const baseCommand = options.dev ? 'node bin' : 'underpost';
402
- shellExec(
403
- `cd /home/dd/engine && git reset && underpost cmt . --empty ci docker-image 'underpost-engine:${
404
- Underpost.version
405
- }' && underpost push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`,
406
- );
434
+ Underpost.repo.dispatchWorkflow({
435
+ repo: `${process.env.GITHUB_USERNAME}/engine`,
436
+ workflowFile: 'docker-image.ci.yml',
437
+ ref: 'master',
438
+ inputs: {},
439
+ });
407
440
  },
408
441
  /**
409
442
  * @method clean
@@ -464,18 +497,30 @@ class UnderpostRun {
464
497
  },
465
498
  /**
466
499
  * @method ssh-deploy
467
- * @description Performs a Git reset, commits with a message `cd ssh-${path}`, and pushes the `engine` repository, likely triggering an SSH-based CD pipeline.
468
- * @param {string} path - The input value, identifier, or path for the operation (used as the deployment identifier for the commit message).
500
+ * @description Dispatches the corresponding CD workflow for SSH-based deployment, replacing empty commits with workflow_dispatch.
501
+ * @param {string} path - The deployment identifier (e.g., 'engine-core', 'sync-engine-core', 'init-engine-core').
469
502
  * @param {Object} options - The default underpost runner options for customizing workflow
470
503
  * @memberof UnderpostRun
471
504
  */
472
505
  'ssh-deploy': (path, options = DEFAULT_OPTION) => {
473
506
  actionInitLog();
474
- const baseCommand = options.dev ? 'node bin' : 'underpost';
475
- shellCd('/home/dd/engine');
476
- shellExec(`git reset`);
477
- shellExec(`${baseCommand} cmt . --empty cd ssh-${path}`);
478
- shellExec(`${baseCommand} push . ${options.force ? '-f ' : ''}${process.env.GITHUB_USERNAME}/engine`);
507
+
508
+ let job = 'deploy';
509
+ let confId = path;
510
+ if (path.startsWith('sync-')) {
511
+ job = 'sync-and-deploy';
512
+ confId = path.replace(/^sync-/, '');
513
+ } else if (path.startsWith('init-')) {
514
+ job = 'init';
515
+ confId = path.replace(/^init-/, '');
516
+ }
517
+
518
+ Underpost.repo.dispatchWorkflow({
519
+ repo: `${process.env.GITHUB_USERNAME}/engine`,
520
+ workflowFile: `${confId}.cd.yml`,
521
+ ref: 'master',
522
+ inputs: { job },
523
+ });
479
524
  },
480
525
  /**
481
526
  * @method ide
@@ -485,15 +530,25 @@ class UnderpostRun {
485
530
  * @param {Object} options - The default underpost runner options for customizing workflow
486
531
  * @memberof UnderpostRun
487
532
  */
488
- ide: (path, options = DEFAULT_OPTION) => {
489
- const { underpostRoot } = options;
490
- if (path === 'install') {
491
- shellExec(`sudo curl -f https://zed.dev/install.sh | sh`);
492
- shellExec(
493
- `sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo`,
494
- );
495
- shellExec(`sudo dnf install -y sublime-text`);
496
- } else shellExec(`node ${underpostRoot}/bin/zed ${path}`);
533
+ ide: (path = '', options = DEFAULT_OPTION) => {
534
+ const underpostRoot = options.dev ? '.' : options.underpostRoot;
535
+ const [projectPath, customIde] = path.split(',');
536
+ if (projectPath === 'install') {
537
+ if (customIde === 'zed') shellExec(`sudo curl -f https://zed.dev/install.sh | sh`);
538
+ else if (customIde === 'subl') {
539
+ shellExec(
540
+ `sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo`,
541
+ );
542
+ shellExec(`sudo dnf install -y sublime-text`);
543
+ } else {
544
+ shellExec(`sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc &&
545
+ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\nautorefresh=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" | sudo tee /etc/yum.repos.d/vscode.repo > /dev/null`);
546
+ shellExec(`sudo dnf install -y code`);
547
+ }
548
+ return;
549
+ }
550
+ if (customIde === 'zed') shellExec(`node ${underpostRoot}/bin/zed ${projectPath}`);
551
+ else shellExec(`node ${underpostRoot}/bin/vs ${projectPath}`);
497
552
  },
498
553
  /**
499
554
  * @method crypto-policy
@@ -522,7 +577,7 @@ class UnderpostRun {
522
577
  options.replicas,
523
578
  ``,
524
579
  ``,
525
- options.dev || !isDeployRunnerContext(path, options) ? 'kind-control-plane' : os.hostname(),
580
+ !options.kubeadm && !options.k3s ? 'kind-control-plane' : os.hostname(),
526
581
  ];
527
582
  let [deployId, replicas, versions, image, node] = path ? path.split(',') : defaultPath;
528
583
  deployId = deployId ? deployId : defaultPath[0];
@@ -556,7 +611,7 @@ class UnderpostRun {
556
611
  image ? ` --image ${image}` : ''
557
612
  }${versions ? ` --versions ${versions}` : ''}${
558
613
  options.namespace ? ` --namespace ${options.namespace}` : ''
559
- }${timeoutFlags}${cmdString} dd ${env}`,
614
+ }${timeoutFlags}${cmdString} ${deployId} ${env}`,
560
615
  );
561
616
 
562
617
  if (isDeployRunnerContext(path, options)) {
@@ -1005,9 +1060,7 @@ EOF
1005
1060
  volumeMountPath: volumeHostPath,
1006
1061
  ...(options.dev ? { volumeHostPath } : { claimName }),
1007
1062
  on: {
1008
- init: async () => {
1009
- // openTerminal(`kubectl logs -f ${podName}`);
1010
- },
1063
+ init: async () => {},
1011
1064
  },
1012
1065
  args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
1013
1066
  };
@@ -1142,7 +1195,7 @@ EOF
1142
1195
  const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
1143
1196
  let hosts = [];
1144
1197
  for (const deployId of deployList) {
1145
- const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
1198
+ const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
1146
1199
  hosts = hosts.concat(Object.keys(confServer));
1147
1200
  }
1148
1201
  shellExec(`node bin cluster --prom ${hosts.join(',')}`);
@@ -1315,34 +1368,31 @@ EOF
1315
1368
  if (!subConf) subConf = 'local';
1316
1369
  if (options.reset && fs.existsSync(`./engine-private/conf/${deployId}`))
1317
1370
  fs.removeSync(`./engine-private/conf/${deployId}`);
1318
- if (!fs.existsSync(`./engine-private/conf/${deployId}`)) Config.deployIdFactory(deployId, { subConf });
1319
1371
  if (options.devProxyPortOffset) {
1320
1372
  const envPath = `./engine-private/conf/${deployId}/.env.development`;
1321
1373
  const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
1322
1374
  envObj.DEV_PROXY_PORT_OFFSET = options.devProxyPortOffset;
1323
1375
  writeEnv(envPath, envObj);
1324
1376
  }
1377
+ dotenv.config({ path: `./engine-private/conf/${deployId}/.env.development`, override: true });
1325
1378
  shellExec(`node bin run dev-cluster --expose --namespace ${options.namespace}`, { async: true });
1326
1379
  {
1327
- const cmd = `npm run dev-api ${deployId} ${subConf} ${host} ${_path} ${clientHostPort}${
1380
+ const cmd = `npm run dev:api ${deployId} ${subConf} ${host} ${_path} ${clientHostPort} proxy${
1328
1381
  options.tls ? ' tls' : ''
1329
1382
  }`;
1330
- options.terminal ? openTerminal(cmd) : shellExec(cmd, { async: true });
1383
+ shellExec(cmd, { async: true });
1331
1384
  }
1332
1385
  await awaitDeployMonitor(true);
1333
1386
  {
1334
- const cmd = `npm run dev-client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
1335
- options.terminal
1336
- ? openTerminal(cmd)
1337
- : shellExec(cmd, {
1338
- async: true,
1339
- });
1387
+ const cmd = `npm run dev:client ${deployId} ${subConf} ${host} ${_path} proxy${options.tls ? ' tls' : ''}`;
1388
+
1389
+ shellExec(cmd, {
1390
+ async: true,
1391
+ });
1340
1392
  }
1341
1393
  await awaitDeployMonitor(true);
1342
1394
  shellExec(
1343
- `./node_modules/.bin/env-cmd -f .env.development node src/proxy proxy ${deployId} ${subConf} ${host} ${_path}${
1344
- options.tls ? ' tls' : ''
1345
- }`,
1395
+ `NODE_ENV=development node src/proxy proxy ${deployId} ${subConf} ${host} ${_path}${options.tls ? ' tls' : ''}`,
1346
1396
  );
1347
1397
  },
1348
1398
 
@@ -1361,7 +1411,7 @@ EOF
1361
1411
  let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
1362
1412
  if (!replicas) replicas = options.replicas;
1363
1413
  // const confClient = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
1364
- const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
1414
+ const confServer = loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`);
1365
1415
  // const confSSR = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
1366
1416
  // const packageData = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
1367
1417
  const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
@@ -1452,9 +1502,7 @@ EOF
1452
1502
  'etc-hosts': async (path = '', options = DEFAULT_OPTION) => {
1453
1503
  const hosts = path ? path.split(',') : [];
1454
1504
  if (options.deployId) {
1455
- const confServer = JSON.parse(
1456
- fs.readFileSync(`./engine-private/conf/${options.deployId}/conf.server.json`, 'utf8'),
1457
- );
1505
+ const confServer = loadConfServerJson(`./engine-private/conf/${options.deployId}/conf.server.json`);
1458
1506
  hosts.push(...Object.keys(confServer));
1459
1507
  }
1460
1508
  const hostListenResult = Underpost.deploy.etcHostFactory(hosts);
@@ -1524,29 +1572,75 @@ EOF
1524
1572
  },
1525
1573
 
1526
1574
  /**
1527
- * @method ptls
1528
- * @description Set on ~/.bashrc alias: ports <port> Command to list listening ports that match the given keyword.
1529
- * @param {string} path - The input value, identifier, or path for the operation (used as a keyword to filter listening ports).
1575
+ * @method pid-info
1576
+ * @description Displays detailed information about a process by PID, including service details, command line, executable path, working directory, environment variables, and parent process tree.
1577
+ * @param {string} path - The PID of the process to inspect.
1530
1578
  * @param {Object} options - The default underpost runner options for customizing workflow
1531
1579
  * @memberof UnderpostRun
1532
1580
  */
1533
- ptls: async (path = '', options = DEFAULT_OPTION) => {
1534
- shellExec(`chmod +x ${options.underpostRoot}/scripts/ports-ls.sh`);
1535
- shellExec(`${options.underpostRoot}/scripts/ports-ls.sh`);
1581
+ 'pid-info': (path, options = DEFAULT_OPTION) => {
1582
+ const pid = path;
1583
+ if (!pid) {
1584
+ logger.error('PID is required. Usage: underpost run pid-info <pid>');
1585
+ return;
1586
+ }
1587
+
1588
+ // Services
1589
+ logger.info('Process info');
1590
+ shellExec(`sudo ps -p ${pid} -o pid,ppid,user,stime,etime,cmd`);
1591
+ logger.info('Command line');
1592
+ shellExec(`sudo cat /proc/${pid}/cmdline | tr '\\0' ' ' ; echo`);
1593
+ logger.info('Executable path');
1594
+ shellExec(`sudo readlink -f /proc/${pid}/exe`);
1595
+ logger.info('Working directory');
1596
+ shellExec(`sudo readlink -f /proc/${pid}/cwd`);
1597
+ logger.info('Environment variables (first 200)');
1598
+ shellExec(`sudo tr '\\0' '\\n' </proc/${pid}/environ | head -200`);
1599
+
1600
+ // Parent
1601
+ logger.info('Parent process');
1602
+ const parentInfo = shellExec(`sudo ps -o pid,ppid,user,cmd -p ${pid}`, { stdout: true, silent: true });
1603
+ console.log(parentInfo);
1604
+ const ppidMatch = parentInfo.split('\n').find((l) => l.trim().startsWith(pid));
1605
+ if (ppidMatch) {
1606
+ const ppid = ppidMatch.trim().split(/\s+/)[1];
1607
+ logger.info(`Parent PID: ${ppid}`);
1608
+ shellExec(`ps -fp ${ppid}`);
1609
+ }
1610
+ logger.info('Process tree');
1611
+ shellExec(`pstree -s ${pid}`);
1536
1612
  },
1613
+
1537
1614
  /**
1538
- * @method release-cmt
1539
- * @description Commits and pushes a new release for the `engine` repository with a message indicating the new version.
1540
- * @param {string} path - The input value, identifier, or path for the operation.
1615
+ * @method background
1616
+ * @description Runs a custom command in the background using nohup, logging output to `/var/log/<id>.log` and saving the PID to `/var/run/<id>.pid`.
1617
+ * @param {string} path - The command to run in the background (e.g. 'npm run prod:container dd-cyberia-r3').
1541
1618
  * @param {Object} options - The default underpost runner options for customizing workflow
1542
1619
  * @memberof UnderpostRun
1543
1620
  */
1544
- 'release-cmt': async (path, options = DEFAULT_OPTION) => {
1545
- shellExec(`underpost run pull`);
1546
- shellExec(`underpost run secret`);
1547
- shellCd(`/home/dd/engine`);
1548
- shellExec(`underpost cmt --empty . ci engine ' New engine release $(underpost --version)'`);
1549
- shellExec(`underpost push . ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
1621
+ background: (path, options = DEFAULT_OPTION) => {
1622
+ if (!path) {
1623
+ logger.error('Command is required. Usage: underpost run background <command>');
1624
+ return;
1625
+ }
1626
+ const id = path.split(/\s+/).pop();
1627
+ const logFile = `/var/log/${id}.log`;
1628
+ const pidFile = `/var/run/${id}.pid`;
1629
+ logger.info(`Starting background process`, { id, logFile, pidFile });
1630
+ shellExec(`nohup ${path} > ${logFile} 2>&1 & pid=$!; echo $pid > ${pidFile}; disown`);
1631
+ logger.info(`Background process started for '${id}'`);
1632
+ },
1633
+
1634
+ /**
1635
+ * @method ports
1636
+ * @description Set on ~/.bashrc alias: ports <port> Command to list listening ports that match the given keyword.
1637
+ * @param {string} path - The input value, identifier, or path for the operation (used as a keyword to filter listening ports).
1638
+ * @param {Object} options - The default underpost runner options for customizing workflow
1639
+ * @memberof UnderpostRun
1640
+ */
1641
+ ports: async (path = '', options = DEFAULT_OPTION) => {
1642
+ shellExec(`chmod +x ${options.underpostRoot}/scripts/ports-ls.sh`);
1643
+ shellExec(`${options.underpostRoot}/scripts/ports-ls.sh`);
1550
1644
  },
1551
1645
 
1552
1646
  /**
@@ -1569,42 +1663,11 @@ EOF
1569
1663
  `npm install -g npm@11.2.0`,
1570
1664
  `npm install -g underpost`,
1571
1665
  `${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
1572
- `${baseCommand} start --build --run ${deployId} ${env} --underpost-quickly-install`,
1666
+ `${baseCommand} start --build --run ${deployId} ${env}`,
1573
1667
  ];
1574
1668
  shellExec(`node bin run sync${baseClusterCommand} --deploy-id-cron-jobs none dd-test --cmd "${cmd}"`);
1575
1669
  },
1576
1670
 
1577
- /**
1578
- * @method sync-replica
1579
- * @description Syncs a replica for the dd.router
1580
- * @param {string} path - The input value, identifier, or path for the operation.
1581
- * @param {Object} options - The default underpost runner options for customizing workflow
1582
- * @memberof UnderpostRun
1583
- */
1584
- 'sync-replica': async (path, options = DEFAULT_OPTION) => {
1585
- const env = options.dev ? 'development' : 'production';
1586
- const baseCommand = options.dev ? 'node bin' : 'underpost';
1587
-
1588
- for (let deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
1589
- deployId = deployId.trim();
1590
- const _path = '/single-replica';
1591
- const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
1592
- shellExec(`${baseCommand} env ${deployId} ${env}`);
1593
- for (const host of Object.keys(confServer))
1594
- if (_path in confServer[host]) shellExec(`node bin/deploy build-single-replica ${deployId} ${host} ${_path}`);
1595
- const node = options.nodeName
1596
- ? options.nodeName
1597
- : options.dev || !isDeployRunnerContext(path, options)
1598
- ? 'kind-control-plane'
1599
- : os.hostname();
1600
- // deployId, replicas, versions, image, node
1601
- let defaultPath = [deployId, 1, ``, ``, node];
1602
- shellExec(`${baseCommand} run${options.dev === true ? ' --dev' : ''} --build sync ${defaultPath}`);
1603
- shellExec(`node bin/deploy build-full-client ${deployId}`);
1604
- }
1605
- if (isDeployRunnerContext(path, options)) shellExec(`${baseCommand} run promote ${path} production`);
1606
- },
1607
-
1608
1671
  /**
1609
1672
  * @method tf-vae-test
1610
1673
  * @description Creates and runs a job pod (`tf-vae-test`) that installs TensorFlow dependencies, clones the TensorFlow docs, and runs the CVAE tutorial script, with a terminal monitor attached.
@@ -1677,7 +1740,7 @@ EOF
1677
1740
  shellExec(`sudo kubectl cp ${nameSpace}/${podName}:${basePath}/docs${fromPath} ${toPath}`);
1678
1741
  }
1679
1742
 
1680
- openTerminal(`firefox ${outsPaths.join(' ')}`, { single: true });
1743
+ shellExec(`firefox ${outsPaths.join(' ')}`);
1681
1744
  process.exit(0);
1682
1745
  }
1683
1746
  })();
@@ -1840,6 +1903,30 @@ EOF
1840
1903
  const imagePullPolicy = options.imagePullPolicy || 'IfNotPresent';
1841
1904
  const hostNetwork = options.hostNetwork ? options.hostNetwork : '';
1842
1905
  const apiVersion = options.apiVersion || 'v1';
1906
+ // Parse hostAliases option:
1907
+ // - string from CLI: "ip1=host1,host2;ip2=host3,host4"
1908
+ // - array from programmatic callers: [{ ip: "127.0.0.1", hostnames: ["foo.local"] }]
1909
+ const hostAliases = options.hostAliases
1910
+ ? Array.isArray(options.hostAliases)
1911
+ ? options.hostAliases
1912
+ : options.hostAliases
1913
+ .split(';')
1914
+ .filter((entry) => entry.trim())
1915
+ .map((entry) => {
1916
+ const [ip, hostnamesStr] = entry.split('=');
1917
+ const hostnames = hostnamesStr ? hostnamesStr.split(',').map((h) => h.trim()) : [];
1918
+ return { ip: ip.trim(), hostnames };
1919
+ })
1920
+ : [];
1921
+ const hostAliasesYaml =
1922
+ hostAliases.length > 0
1923
+ ? ` hostAliases:\n${hostAliases
1924
+ .map(
1925
+ (alias) =>
1926
+ ` - ip: "${alias.ip}"\n hostnames:\n${alias.hostnames.map((h) => ` - "${h}"`).join('\n')}`,
1927
+ )
1928
+ .join('\n')}`
1929
+ : '';
1843
1930
  const labels = options.labels
1844
1931
  ? options.labels
1845
1932
  .split(',')
@@ -1870,6 +1957,7 @@ spec:
1870
1957
  restartPolicy: ${restartPolicy}
1871
1958
  ${runtimeClassName ? ` runtimeClassName: ${runtimeClassName}` : ''}
1872
1959
  ${hostNetwork ? ` hostNetwork: ${hostNetwork}` : ''}
1960
+ ${hostAliasesYaml}
1873
1961
  containers:
1874
1962
  - name: ${containerName}
1875
1963
  image: ${imageName}
@@ -4,13 +4,11 @@
4
4
  * @namespace UnderpostSecret
5
5
  */
6
6
 
7
- import dotenv from 'dotenv';
8
7
  import { shellExec } from '../server/process.js';
9
8
  import fs from 'fs-extra';
9
+ import dotenv from 'dotenv';
10
10
  import Underpost from '../index.js';
11
11
 
12
- dotenv.config();
13
-
14
12
  /**
15
13
  * @class UnderpostSecret
16
14
  * @description Manages the secrets of the application.
package/src/cli/ssh.js CHANGED
@@ -497,7 +497,7 @@ EOF`);
497
497
  },
498
498
 
499
499
  /**
500
- * Generic SSH remote command runner that centralizes SSH execution logic.
500
+ * Generic SSH remote command runner that SSH execution logic.
501
501
  * Executes arbitrary shell commands on a remote server via SSH with proper credential handling.
502
502
  * @async
503
503
  * @function sshRemoteRunner