underpost 2.85.7 → 2.89.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.github/workflows/release.cd.yml +3 -1
  2. package/README.md +2 -2
  3. package/bin/build.js +8 -10
  4. package/bin/index.js +8 -1
  5. package/cli.md +3 -2
  6. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  7. package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
  8. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  9. package/package.json +1 -1
  10. package/scripts/rpmfusion-ffmpeg-setup.sh +55 -0
  11. package/src/api/file/file.service.js +29 -3
  12. package/src/cli/baremetal.js +1 -2
  13. package/src/cli/index.js +1 -0
  14. package/src/cli/repository.js +8 -1
  15. package/src/cli/run.js +104 -36
  16. package/src/client/components/core/AgGrid.js +42 -3
  17. package/src/client/components/core/CommonJs.js +4 -0
  18. package/src/client/components/core/Css.js +95 -48
  19. package/src/client/components/core/CssCore.js +0 -1
  20. package/src/client/components/core/LoadingAnimation.js +2 -2
  21. package/src/client/components/core/Logger.js +2 -9
  22. package/src/client/components/core/Modal.js +22 -14
  23. package/src/client/components/core/ObjectLayerEngine.js +300 -9
  24. package/src/client/components/core/ObjectLayerEngineModal.js +686 -148
  25. package/src/client/components/core/ObjectLayerEngineViewer.js +1061 -0
  26. package/src/client/components/core/Pagination.js +57 -12
  27. package/src/client/components/core/Router.js +37 -1
  28. package/src/client/components/core/Translate.js +4 -0
  29. package/src/client/components/core/Worker.js +8 -1
  30. package/src/client/services/default/default.management.js +86 -16
  31. package/src/db/mariadb/MariaDB.js +2 -2
  32. package/src/index.js +1 -1
  33. package/src/server/client-build.js +57 -2
  34. package/src/server/object-layer.js +44 -0
  35. package/src/server/start.js +12 -0
  36. package/src/ws/IoInterface.js +2 -3
  37. package/AUTHORS.md +0 -21
  38. package/src/server/network.js +0 -72
@@ -30,7 +30,9 @@ jobs:
30
30
  echo "Starting remote release deploy"
31
31
  underpost run pull
32
32
  underpost run secret
33
+ npm install -g underpost
33
34
  cd /home/dd/engine
34
- node bin run --dev git-conf admin@underpost.net,underpostnet
35
+ underpost run secret
36
+ node bin run --dev git-conf
35
37
  node bin run --dev template-deploy-image
36
38
  node bin run --dev ssh-deploy sync-engine-test
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  <!-- badges -->
20
20
 
21
- [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.85.7)](https://socket.dev/npm/package/underpost/overview/2.85.7) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
21
+ [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.89.1)](https://socket.dev/npm/package/underpost/overview/2.89.1) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
22
22
 
23
23
  <!-- end-badges -->
24
24
 
@@ -66,7 +66,7 @@ Run dev client server
66
66
  npm run dev
67
67
  ```
68
68
  <!-- -->
69
- ## underpost ci/cd cli v2.85.7
69
+ ## underpost ci/cd cli v2.89.1
70
70
 
71
71
  ### Usage: `underpost [options] [command]`
72
72
  ```
package/bin/build.js CHANGED
@@ -53,14 +53,14 @@ if (process.argv.includes('conf')) {
53
53
  fs.removeSync(toPath);
54
54
  fs.mkdirSync(toPath, { recursive: true });
55
55
  fs.copySync(`./engine-private/conf/${_confName}`, toPath);
56
- if (process.argv.includes('remove-replica') && fs.existsSync(`../${privateRepoName}/replica`)) {
57
- fs.removeSync(`../${privateRepoName}/replica`);
58
- } else if (fs.existsSync(`./engine-private/replica`)) {
56
+ fs.removeSync(`../${privateRepoName}/replica`);
57
+ if (fs.existsSync(`./engine-private/replica`)) {
59
58
  const replicas = await fs.readdir(`./engine-private/replica`);
60
59
  for (const replica of replicas)
61
60
  if (replica.match(_confName))
62
61
  fs.copySync(`./engine-private/replica/${replica}`, `../${privateRepoName}/replica/${replica}`);
63
62
  }
63
+
64
64
  if (fs.existsSync(`./engine-private/itc-scripts`)) {
65
65
  const itcScripts = await fs.readdir(`./engine-private/itc-scripts`);
66
66
  for (const itcScript of itcScripts)
@@ -149,10 +149,6 @@ const { DefaultConf } = await import(`../conf.${confName}.js`);
149
149
  }
150
150
  }
151
151
 
152
- shellExec(`node bin/deploy update-default-conf ${confName}`);
153
-
154
- fs.copyFileSync(`./conf.${confName}.js`, `${basePath}/conf.js`);
155
-
156
152
  if (!fs.existsSync(`${basePath}/.github/workflows`))
157
153
  fs.mkdirSync(`${basePath}/.github/workflows`, {
158
154
  recursive: true,
@@ -170,11 +166,12 @@ const { DefaultConf } = await import(`../conf.${confName}.js`);
170
166
  );
171
167
  delete packageJson.bin.underpost;
172
168
  packageJson.bin.cyberia = 'bin/index.js';
173
- packageJson.keywords = ['cyberia', 'object-layer', 'game-engine', 'assets-management'];
174
-
169
+ packageJson.keywords = ['cyberia', 'object-layer', 'game-engine', 'assets-management', 'web3'];
170
+ packageJson.description = 'Cyberia Engine - Object Layer and Assets Management Microservice';
175
171
  fs.writeFileSync(`${basePath}/bin/index.js`, fs.readFileSync(`./bin/cyberia.js`, 'utf8'), 'utf8');
176
172
  fs.copyFileSync(`./src/api/object-layer/README.md`, `${basePath}/README.md`);
177
-
173
+ fs.copySync(`./hardhat`, `${basePath}/hardhat`);
174
+ fs.copySync(`./hardhat/white-paper.md`, `${basePath}/white-paper.md`);
178
175
  default:
179
176
  break;
180
177
  }
@@ -200,6 +197,7 @@ const { DefaultConf } = await import(`../conf.${confName}.js`);
200
197
  fs.copyFileSync(`./.github/workflows/${repoName}.ci.yml`, `${basePath}/.github/workflows/${repoName}.ci.yml`);
201
198
  fs.copyFileSync(`./.github/workflows/${repoName}.cd.yml`, `${basePath}/.github/workflows/${repoName}.cd.yml`);
202
199
 
200
+ // Copy conf.<deploy-id>.js to conf.js for the respective deployment
203
201
  fs.copyFileSync(`./conf.${confName}.js`, `${basePath}/conf.js`);
204
202
  fs.copyFileSync(`./manifests/deployment/${confName}-development/proxy.yaml`, `${basePath}/proxy.yaml`);
205
203
  fs.copyFileSync(`./manifests/deployment/${confName}-development/deployment.yaml`, `${basePath}/deployment.yaml`);
package/bin/index.js CHANGED
@@ -1,5 +1,12 @@
1
1
  #! /usr/bin/env node
2
2
 
3
3
  import { program } from '../src/cli/index.js';
4
+ import { loggerFactory } from '../src/server/logger.js';
4
5
 
5
- program.parse();
6
+ const logger = loggerFactory(import.meta);
7
+
8
+ try {
9
+ program.parse();
10
+ } catch (error) {
11
+ logger.error(error);
12
+ }
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.85.7
1
+ ## underpost ci/cd cli v2.89.1
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -623,7 +623,7 @@ Options:
623
623
  Runs a script from the specified path.
624
624
 
625
625
  Arguments:
626
- runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, dev-hosts-expose, dev-hosts-restore, cyberia-ide, engine-ide, cluster-build, template-deploy, template-deploy-image, clean, pull, release-deploy, ssh-deploy, ide, sync, ls-deployments, ls-images, host-update, dev-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, dev, service, release-cmt, sync-replica, tf-vae-test, deploy-job.
626
+ runner-id The runner ID to run. Options: spark-template, rmi, kill, secret, underpost-config, gpu-env, tf-gpu-test, dev-cluster, ssh-cluster-info, dev-hosts-expose, dev-hosts-restore, cluster-build, template-deploy, template-deploy-image, clean, pull, release-deploy, ssh-deploy, ide, sync, tz, cron, ls-deployments, ls-images, host-update, dev-container, monitor, db-client, git-conf, promote, metrics, cluster, deploy, dev, service, sh, log, release-cmt, sync-replica, tf-vae-test, deploy-job.
627
627
  path The absolute or relative directory path where the script is located.
628
628
 
629
629
  Options:
@@ -646,6 +646,7 @@ Options:
646
646
  --reset Resets the runner state before execution.
647
647
  --terminal Enables terminal mode for interactive script execution.
648
648
  --dev-proxy-port-offset <port-offset> Sets a custom port offset for development proxy.
649
+ --conf-server-path <conf-server-path> Sets a custom configuration server path.
649
650
  -h, --help display help for command
650
651
 
651
652
  ```
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-default-development-blue
20
- image: localhost/rockylinux9-underpost:v2.85.7
20
+ image: localhost/rockylinux9-underpost:v2.89.1
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -100,7 +100,7 @@ spec:
100
100
  spec:
101
101
  containers:
102
102
  - name: dd-default-development-green
103
- image: localhost/rockylinux9-underpost:v2.85.7
103
+ image: localhost/rockylinux9-underpost:v2.89.1
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-test-development-blue
20
- image: localhost/rockylinux9-underpost:v2.85.7
20
+ image: localhost/rockylinux9-underpost:v2.89.1
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "96294Ki"
@@ -49,41 +49,41 @@ spec:
49
49
  selector:
50
50
  app: dd-test-development-blue
51
51
  ports:
52
- - name: 'tcp-4041'
52
+ - name: 'tcp-4030'
53
53
  protocol: TCP
54
- port: 4041
55
- targetPort: 4041
56
- - name: 'udp-4041'
54
+ port: 4030
55
+ targetPort: 4030
56
+ - name: 'udp-4030'
57
57
  protocol: UDP
58
- port: 4041
59
- targetPort: 4041
58
+ port: 4030
59
+ targetPort: 4030
60
60
 
61
- - name: 'tcp-4042'
61
+ - name: 'tcp-4031'
62
62
  protocol: TCP
63
- port: 4042
64
- targetPort: 4042
65
- - name: 'udp-4042'
63
+ port: 4031
64
+ targetPort: 4031
65
+ - name: 'udp-4031'
66
66
  protocol: UDP
67
- port: 4042
68
- targetPort: 4042
67
+ port: 4031
68
+ targetPort: 4031
69
69
 
70
- - name: 'tcp-4043'
70
+ - name: 'tcp-4032'
71
71
  protocol: TCP
72
- port: 4043
73
- targetPort: 4043
74
- - name: 'udp-4043'
72
+ port: 4032
73
+ targetPort: 4032
74
+ - name: 'udp-4032'
75
75
  protocol: UDP
76
- port: 4043
77
- targetPort: 4043
76
+ port: 4032
77
+ targetPort: 4032
78
78
 
79
- - name: 'tcp-4044'
79
+ - name: 'tcp-4033'
80
80
  protocol: TCP
81
- port: 4044
82
- targetPort: 4044
83
- - name: 'udp-4044'
81
+ port: 4033
82
+ targetPort: 4033
83
+ - name: 'udp-4033'
84
84
  protocol: UDP
85
- port: 4044
86
- targetPort: 4044
85
+ port: 4033
86
+ targetPort: 4033
87
87
  type: LoadBalancer
88
88
  ---
89
89
  apiVersion: apps/v1
@@ -104,7 +104,7 @@ spec:
104
104
  spec:
105
105
  containers:
106
106
  - name: dd-test-development-green
107
- image: localhost/rockylinux9-underpost:v2.85.7
107
+ image: localhost/rockylinux9-underpost:v2.89.1
108
108
  # resources:
109
109
  # requests:
110
110
  # memory: "96294Ki"
@@ -136,39 +136,39 @@ spec:
136
136
  selector:
137
137
  app: dd-test-development-green
138
138
  ports:
139
- - name: 'tcp-4041'
139
+ - name: 'tcp-4030'
140
140
  protocol: TCP
141
- port: 4041
142
- targetPort: 4041
143
- - name: 'udp-4041'
141
+ port: 4030
142
+ targetPort: 4030
143
+ - name: 'udp-4030'
144
144
  protocol: UDP
145
- port: 4041
146
- targetPort: 4041
145
+ port: 4030
146
+ targetPort: 4030
147
147
 
148
- - name: 'tcp-4042'
148
+ - name: 'tcp-4031'
149
149
  protocol: TCP
150
- port: 4042
151
- targetPort: 4042
152
- - name: 'udp-4042'
150
+ port: 4031
151
+ targetPort: 4031
152
+ - name: 'udp-4031'
153
153
  protocol: UDP
154
- port: 4042
155
- targetPort: 4042
154
+ port: 4031
155
+ targetPort: 4031
156
156
 
157
- - name: 'tcp-4043'
157
+ - name: 'tcp-4032'
158
158
  protocol: TCP
159
- port: 4043
160
- targetPort: 4043
161
- - name: 'udp-4043'
159
+ port: 4032
160
+ targetPort: 4032
161
+ - name: 'udp-4032'
162
162
  protocol: UDP
163
- port: 4043
164
- targetPort: 4043
163
+ port: 4032
164
+ targetPort: 4032
165
165
 
166
- - name: 'tcp-4044'
166
+ - name: 'tcp-4033'
167
167
  protocol: TCP
168
- port: 4044
169
- targetPort: 4044
170
- - name: 'udp-4044'
168
+ port: 4033
169
+ targetPort: 4033
170
+ - name: 'udp-4033'
171
171
  protocol: UDP
172
- port: 4044
173
- targetPort: 4044
172
+ port: 4033
173
+ targetPort: 4033
174
174
  type: LoadBalancer
@@ -13,7 +13,7 @@ spec:
13
13
  enableWebsockets: true
14
14
  services:
15
15
  - name: dd-test-development-blue-service
16
- port: 4041
16
+ port: 4030
17
17
  weight: 100
18
18
 
19
19
  - conditions:
@@ -21,7 +21,7 @@ spec:
21
21
  enableWebsockets: true
22
22
  services:
23
23
  - name: dd-test-development-blue-service
24
- port: 4042
24
+ port: 4031
25
25
  weight: 100
26
26
 
27
27
  ---
@@ -38,7 +38,7 @@ spec:
38
38
  enableWebsockets: true
39
39
  services:
40
40
  - name: dd-test-development-blue-service
41
- port: 4043
41
+ port: 4032
42
42
  weight: 100
43
43
 
44
44
  - conditions:
@@ -46,6 +46,6 @@ spec:
46
46
  enableWebsockets: true
47
47
  services:
48
48
  - name: dd-test-development-blue-service
49
- port: 4044
49
+ port: 4033
50
50
  weight: 100
51
51
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "2.85.7",
5
+ "version": "2.89.1",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Purpose: enable required repos (CRB, EPEL, RPM Fusion) and attempt to install ffmpeg on Rocky/Alma/RHEL-9 compatible systems.
5
+
6
+ if [ "${EUID:-$(id -u)}" -ne 0 ]; then
7
+ echo "This script must be run as root or with sudo. Exiting."
8
+ exit 1
9
+ fi
10
+
11
+ echo "1) Ensure dnf-plugins-core is available (for config-manager)"
12
+ dnf -y install dnf-plugins-core || true
13
+
14
+ echo "2) Enable CodeReady / CRB (needed for some deps, e.g. ladspa)"
15
+ # On RHEL you'd use subscription-manager; on CentOS/Rocky/Alma use config-manager
16
+ dnf config-manager --set-enabled crb || true
17
+
18
+ echo "3) Install EPEL release (required by some ffmpeg deps)"
19
+ dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm || true
20
+
21
+ echo "4) Add RPM Fusion (free + nonfree) repositories"
22
+ # Using mirrors.rpmfusion.org recommended links
23
+ dnf -y install https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-9.noarch.rpm \
24
+ https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-9.noarch.rpm || true
25
+
26
+ echo "5) Refresh metadata and update system"
27
+ dnf -y makecache
28
+ # Optional: update system packages (comment out if you don't want a full update)
29
+ # dnf -y update
30
+
31
+ echo "6) Try to install audio helper packages that sometimes block ffmpeg (ladspa, rubberband)"
32
+ # These may be provided by CRB/EPEL or other compatible repos
33
+ dnf -y install ladspa || echo "ladspa not available from enabled repos (will try later)"
34
+ dnf -y install rubberband || echo "rubberband not available from enabled repos (will try later)"
35
+
36
+ echo "7) Try installing ffmpeg (several fallbacks tried)"
37
+ if dnf -y install ffmpeg ffmpeg-devel --allowerasing; then
38
+ echo "ffmpeg installed successfully (used --allowerasing)."
39
+ elif dnf -y install ffmpeg ffmpeg-devel --nobest; then
40
+ echo "ffmpeg installed successfully (used --nobest)."
41
+ elif dnf -y install ffmpeg ffmpeg-devel --skip-broken; then
42
+ echo "ffmpeg installed (skip-broken). Some optional packages may have been skipped."
43
+ else
44
+ echo "Automatic install failed."
45
+ echo "Helpful troubleshooting steps:"
46
+ echo " - Check which repo provides ladspa: dnf repoquery --whatprovides 'ladspa'"
47
+ echo " - Check which package provides librubberband: dnf repoquery --whatprovides 'librubberband.so.2'"
48
+ echo " - Try enabling CRB and EPEL (we already attempted that). If ladspa/rubberband are still missing you can fetch their EL9 rpm from a trusted mirror or build them."
49
+ echo " - Example manual install (ONLY if you trust the source): sudo dnf install /path/to/ladspa-*.el9.rpm /path/to/rubberband-*.el9.rpm"
50
+ echo " - After satisfying ladspa/rubberband, rerun: sudo dnf install ffmpeg ffmpeg-devel"
51
+ exit 2
52
+ fi
53
+
54
+ echo "\nInstallation finished. Verify with: ffmpeg -version"
55
+ exit 0
@@ -7,9 +7,35 @@ const logger = loggerFactory(import.meta);
7
7
  const FileFactory = {
8
8
  filesExtract: (req) => {
9
9
  const files = [];
10
- if (Array.isArray(req.files.file)) for (const file of req.files.file) files.push(file);
11
- else if (Object.keys(req.files).length > 0)
12
- for (const keyFile of Object.keys(req.files)) files.push(req.files[keyFile]);
10
+ if (!req.files || Object.keys(req.files).length === 0) {
11
+ return files;
12
+ }
13
+
14
+ // Handle standard 'file' field
15
+ if (Array.isArray(req.files.file)) {
16
+ for (const file of req.files.file) files.push(file);
17
+ } else if (req.files.file) {
18
+ files.push(req.files.file);
19
+ }
20
+
21
+ // Handle all other fields (like direction codes)
22
+ for (const keyFile of Object.keys(req.files)) {
23
+ if (keyFile === 'file') continue; // Already handled above
24
+
25
+ const fileOrFiles = req.files[keyFile];
26
+ if (Array.isArray(fileOrFiles)) {
27
+ // Multiple files with same field name
28
+ for (const file of fileOrFiles) {
29
+ if (file && file.data) {
30
+ files.push(file);
31
+ }
32
+ }
33
+ } else if (fileOrFiles && fileOrFiles.data) {
34
+ // Single file
35
+ files.push(fileOrFiles);
36
+ }
37
+ }
38
+
13
39
  return files;
14
40
  },
15
41
  upload: async function (req, File) {
@@ -1,6 +1,5 @@
1
1
  /**
2
- * Baremetal module for managing the generation and deployment of cloud-init configuration files
3
- * and associated scripts for baremetal provisioning.
2
+ * Provides baremetal provisioning and configuration functionalities.
4
3
  * @module src/cli/baremetal.js
5
4
  * @namespace UnderpostBaremetal
6
5
  */
package/src/cli/index.js CHANGED
@@ -393,6 +393,7 @@ program
393
393
  .option('--reset', 'Resets the runner state before execution.')
394
394
  .option('--terminal', 'Enables terminal mode for interactive script execution.')
395
395
  .option('--dev-proxy-port-offset <port-offset>', 'Sets a custom port offset for development proxy.')
396
+ .option('--conf-server-path <conf-server-path>', 'Sets a custom configuration server path.')
396
397
  .description('Runs a script from the specified path.')
397
398
  .action(UnderpostRun.API.callback);
398
399
 
@@ -140,13 +140,20 @@ class UnderpostRepository {
140
140
  .join('');
141
141
  if (history[0]) {
142
142
  for (const commit of history) {
143
+ console.log(
144
+ shellExec(`git show -s --format=%ci ${commit.hash}`, {
145
+ stdout: true,
146
+ silent: true,
147
+ disableLog: true,
148
+ }).trim().green,
149
+ );
143
150
  console.log(commit.hash.yellow, commit.message);
144
151
  console.log(
145
152
  shellExec(`git show --name-status --pretty="" ${commit.hash}`, {
146
153
  stdout: true,
147
154
  silent: true,
148
155
  disableLog: true,
149
- }).red,
156
+ }).trim().red,
150
157
  );
151
158
  }
152
159
  if (options.copy) pbcopy(chainCmd);