nano-pow 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -1,7 +1,67 @@
1
1
  // SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
2
2
  // SPDX-License-Identifier: GPL-3.0-or-later
3
3
 
4
- import "@webgpu/types"
4
+ import '@webgpu/types'
5
+
6
+ /**
7
+ * Used by work server for inbound requests to `work_generate`.
8
+ *
9
+ * @param {string} action - Method to call
10
+ * @param {string} hash - Block hash used to generate work
11
+ * @param {string} [difficulty=FFFFFFF800000000] - Minimum threshold for a nonce to be valid
12
+ */
13
+ type WorkGenerateRequest = {
14
+ action: 'work_generate'
15
+ hash: string
16
+ difficulty?: string
17
+ }
18
+
19
+ /**
20
+ * Used by work server for outbound responses to `work_generate`.
21
+ *
22
+ * @param {string} hash - Block hash used to generate or validate work
23
+ * @param {string} work - Valid proof-of-work nonce generated for input hash
24
+ * @param {string} difficulty - BLAKE2b hash result which was compared to specified minimum threshold
25
+ */
26
+ type WorkGenerateResponse = {
27
+ hash: string
28
+ work: string
29
+ difficulty: string
30
+ }
31
+
32
+ /**
33
+ * Used by work server for inbound requests to `work_validate`.
34
+ *
35
+ * @param {string} action - Method to call
36
+ * @param {string} hash - Block hash used to validate work
37
+ * @param {string} work - Existing nonce to check against hash
38
+ * @param {string} [difficulty=FFFFFFF800000000] - Minimum threshold for a nonce to be valid
39
+ */
40
+ type WorkValidateRequest = {
41
+ action: 'work_validate'
42
+ hash: string
43
+ work: string
44
+ difficulty?: string
45
+ }
46
+
47
+ /**
48
+ * Used by work server for outbound responses to `work_validate`.
49
+ *
50
+ * @param {string} hash - Hash from validate request
51
+ * @param {string} work - Nonce from validate request
52
+ * @param {string} difficulty - BLAKE2b hash result which is compared to specified minimum threshold
53
+ * @param {string} [valid] - Excluded if optional difficulty was not included in the request. 1 for true if nonce is valid for requested difficulty, else 0 for false
54
+ * @param {string} valid_all - 1 for true if nonce is valid for send blocks, else 0 for false
55
+ * @param {string} valid_receive - 1 for true if nonce is valid for receive blocks, else 0 for false
56
+ */
57
+ type WorkValidateResponse = {
58
+ hash: string
59
+ work: string
60
+ difficulty: string
61
+ valid?: '0' | '1'
62
+ valid_all: '0' | '1'
63
+ valid_receive: '0' | '1'
64
+ }
5
65
 
6
66
  export declare const NanoPowGlDownsampleShader: string
7
67
  export declare const NanoPowGlDrawShader: string
@@ -36,24 +96,41 @@ export type FBO = {
36
96
  export type NanoPowOptions = {
37
97
  debug?: boolean
38
98
  effort?: number
39
- threshold?: number
99
+ threshold?: bigint | number
40
100
  }
41
101
 
42
102
  /**
43
103
  * Nano proof-of-work using WebGL 2.0.
44
104
  */
45
105
  export declare class NanoPowGl {
46
- /** Compile */
106
+ #private
107
+ /** Drawing buffer width in pixels. */
108
+ static get size (): number | undefined
109
+ /**
110
+ * Constructs canvas, gets WebGL context, initializes buffers, and compiles
111
+ * shaders.
112
+ */
47
113
  static init (): Promise<void>
114
+ /**
115
+ * On WebGL context loss, attempts to clear all program variables and then
116
+ * reinitialize them by calling `init()`.
117
+ */
48
118
  static reset (): void
49
119
  /**
50
120
  * Finds a nonce that satisfies the Nano proof-of-work requirements.
51
121
  *
52
122
  * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
53
- * @param {NanoPowOptions} options - Options used to configure search execution
123
+ * @param {NanoPowOptions} options - Used to configure search execution
54
124
  */
55
125
  static search (hash: string, options?: NanoPowOptions): Promise<string>
56
126
  /**
127
+ * Finds a nonce that satisfies the Nano proof-of-work requirements.
128
+ *
129
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
130
+ * @param {NanoPowOptions} options - Options used to configure search execution
131
+ */
132
+ static work_generate (hash: string, options?: NanoPowOptions): Promise<WorkGenerateResponse>
133
+ /**
57
134
  * Validates that a nonce satisfies Nano proof-of-work requirements.
58
135
  *
59
136
  * @param {string} work - Hexadecimal proof-of-work value to validate
@@ -61,12 +138,21 @@ export declare class NanoPowGl {
61
138
  * @param {NanoPowOptions} options - Options used to configure search execution
62
139
  */
63
140
  static validate (work: string, hash: string, options?: NanoPowOptions): Promise<boolean>
141
+ /**
142
+ * Validates that a nonce satisfies Nano proof-of-work requirements.
143
+ *
144
+ * @param {string} work - Hexadecimal proof-of-work value to validate
145
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
146
+ * @param {NanoPowOptions} options - Options used to configure search execution
147
+ */
148
+ static work_validate (work: string, hash: string, options?: NanoPowOptions): Promise<WorkValidateResponse>
64
149
  }
65
150
 
66
151
  /**
67
152
  * Nano proof-of-work using WebGPU.
68
153
  */
69
154
  export declare class NanoPowGpu {
155
+ #private
70
156
  static init (): Promise<void>
71
157
  static setup (): void
72
158
  static reset (): void
@@ -78,6 +164,13 @@ export declare class NanoPowGpu {
78
164
  */
79
165
  static search (hash: string, options?: NanoPowOptions): Promise<string>
80
166
  /**
167
+ * Finds a nonce that satisfies the Nano proof-of-work requirements.
168
+ *
169
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
170
+ * @param {NanoPowOptions} options - Used to configure search execution
171
+ */
172
+ static work_generate (hash: string, options?: NanoPowOptions): Promise<WorkGenerateResponse>
173
+ /**
81
174
  * Validates that a nonce satisfies Nano proof-of-work requirements.
82
175
  *
83
176
  * @param {string} work - Hexadecimal proof-of-work value to validate
@@ -85,4 +178,12 @@ export declare class NanoPowGpu {
85
178
  * @param {NanoPowOptions} options - Options used to configure search execution
86
179
  */
87
180
  static validate (work: string, hash: string, options?: NanoPowOptions): Promise<boolean>
181
+ /**
182
+ * Validates that a nonce satisfies Nano proof-of-work requirements.
183
+ *
184
+ * @param {string} work - Hexadecimal proof-of-work value to validate
185
+ * @param {string} hash - Hexadecimal hash of previous block, or public key for new accounts
186
+ * @param {NanoPowOptions} options - Options used to configure search execution
187
+ */
188
+ static work_validate (work: string, hash: string, options?: NanoPowOptions): Promise<WorkValidateResponse>
88
189
  }
@@ -0,0 +1,98 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
3
+ SPDX-License-Identifier: GPL-3.0-or-later
4
+ -->
5
+
6
+ # Benchmarks to compute 16,777,216 nonces
7
+ _Each test is 128 samples of one pass (dispatch or frame) at zero threshold with no early exit_
8
+
9
+ ## Summary
10
+ - Chromium WebGPU and Firefox WebGL are the clear winners
11
+ - Chromium WebGL seems to suffer from an Nvidia driver issue
12
+ - Firefox WebGPU exhibits a strange implementation bottleneck
13
+ - It seems to restricts each pass to a minimum of 200ms
14
+ - Not shown here: This minimum is higher or lower depending on dispatch size
15
+ - Safari WebGPU performance was maintained between versions
16
+ - WebGL downsampling shader minimized readback lag and thus enabled much larger frames
17
+ - WebGPU improved dramatically on non-mobile platforms, almost halving frame times
18
+ - Maximum WebGL canvas size varies
19
+ - Safari only supports up to 4096x4096
20
+ - Chromium supports up to 5760x5760
21
+ - Firefox supports up to a whopping 8192x8192 which actually makes it competitive with WebGPU
22
+
23
+
24
+ ## All Results
25
+ | Version | System | Browser | API | Total | Rate | Median | Mean |
26
+ |-----------|--------------|-------------|-----------|-----------|----------|----------|----------|
27
+ | RC | RTX 3070 | Chromium N | WebGPU | 747 | 218.23 | 4.5 | 4.58 |
28
+ | RC | RTX 3070 | Firefox N | WebGL | 1096 | 117.06 | 8.55 | 8.54 |
29
+ | RC | RTX 3070 | Firefox | WebGL | 1174 | 116.57 | 9 | 8.58 |
30
+ | 2.0.0 | RTX 3070 | Chromium N | WebGPU | 1339 | 112.02 | ? | 10.47 |
31
+ | RC | Intel Xe | Chromium N | WebGPU | 5107 | 25.20 | 39.5 | 39.69 |
32
+ | RC | Intel Xe | Firefox | WebGL | 7166 | 18.84 | 52 | 53.07 |
33
+ | RC | Intel Xe | Firefox N | WebGL | 8060 | 16.71 | 63 | 59.83 |
34
+ | RC | iPhone 12 | Safari | WebGPU | 8586 | 14.97 | 67 | 66.79 |
35
+ | 2.0.0 | iPhone 12 | Safari | WebGPU | 8765 | 14.69 | 68 | 68.48 |
36
+ | RC | Intel Xe | Chromium N | WebGL | 9764 | 15.42 | 62.8 | 64.85 |
37
+ | 2.0.0 | Intel Xe | Chromium N | WebGPU | 10103 | 12.63 | ? | 78.93 |
38
+ | RC | RTX 3070 | Chromium N | WebGL | 10681 | 19.81 | 50.60 | 50.47 |
39
+ | RC | iPhone 12 | Safari | WebGL | 12631 | 10.54 | 95 | 94.86 |
40
+ | RC | iPad Mini 5 | Safari | WebGPU | 14232 | 8.78 | 114 | 113.85 |
41
+ | 2.0.0 | iPad Mini 5 | Safari | WebGPU | 14903 | 8.59 | 118 | 116.41 |
42
+ | RC | iPad Mini 5 | Safari | WebGL | 18928 | 6.97 | 145 | 143.40 |
43
+ | RC | Intel Xe | Firefox N | WebGPU | 25679 | 4.99 | 200 | 200.47 |
44
+ | 2.0.0 | Intel Xe | Firefox N | WebGPU | 25805 | 4.94 | ? | 201.60 |
45
+ | 2.0.0 | RTX 3070 | Firefox N | WebGPU | 25629 | 4.97 | ? | 200.23 |
46
+ | RC | RTX 3070 | Firefox N | WebGPU | 25633 | 5.00 | 200 | 200.15 |
47
+ | 2.0.0 | RTX 3070 | Firefox | WebGL | 35224 | 3.72 | ? | 275.19 |
48
+ | 2.0.0 | RTX 3070 | Chromium N | WebGL | 47603 | 3.06 | ? | 371.90 |
49
+ | 2.0.0 | RTX 3070 | Firefox N | WebGL | Unusable | N/A | ? | N/A |
50
+ | 2.0.0 | Intel Xe | Firefox | WebGL | Unusable | N/A | ? | N/A |
51
+ | 2.0.0 | Intel Xe | Firefox N | WebGL | Unusable | N/A | ? | N/A |
52
+ | 2.0.0 | Intel Xe | Chromium N | WebGL | Unusable | N/A | ? | N/A |
53
+ | 2.0.0 | iPhone 12 | Safari | WebGL | Unusable | N/A | ? | N/A |
54
+ | 2.0.0 | iPad Mini 5 | Safari | WebGL | Unusable | N/A | ? | N/A |
55
+
56
+ ## RTX 3070
57
+ | Version | Browser | API | Total | Rate | Median | Mean |
58
+ |-----------|-------------|-----------|-----------|----------|----------|----------|
59
+ | RC | Chromium N | WebGPU | 747 | 218.23 | 4.5 | 4.58 |
60
+ | RC | Firefox N | WebGL | 1096 | 117.06 | 8.55 | 8.54 |
61
+ | RC | Firefox | WebGL | 1174 | 116.57 | 9 | 8.58 |
62
+ | 2.0.0 | Chromium N | WebGPU | 1339 | 112.02 | ? | 10.47 |
63
+ | RC | Chromium N | WebGL | 10681 | 19.81 | 50.60 | 50.47 |
64
+ | 2.0.0 | Firefox N | WebGPU | 25629 | 4.97 | ? | 200.23 |
65
+ | RC | Firefox N | WebGPU | 25633 | 5.00 | 200 | 200.15 |
66
+ | 2.0.0 | Firefox | WebGL | 35224 | 3.72 | ? | 275.19 |
67
+ | 2.0.0 | Chromium N | WebGL | 47603 | 3.06 | ? | 371.90 |
68
+ | 2.0.0 | Firefox N | WebGL | Unusable | N/A | ? | N/A |
69
+
70
+ ## Intel Xe integrated graphics
71
+ | Version | Browser | API | Total | Rate | Median | Mean |
72
+ |-----------|-------------|-----------|-----------|----------|----------|----------|
73
+ | RC | Chromium N | WebGPU | 5107 | 25.20 | 39.5 | 39.69 |
74
+ | RC | Firefox | WebGL | 7166 | 18.84 | 52 | 53.07 |
75
+ | RC | Firefox N | WebGL | 8060 | 16.71 | 63 | 59.83 |
76
+ | RC | Chromium N | WebGL | 9764 | 15.42 | 62.8 | 64.85 |
77
+ | 2.0.0 | Chromium N | WebGPU | 10103 | 12.63 | ? | 78.93 |
78
+ | RC | Firefox N | WebGPU | 25679 | 4.99 | 200 | 200.47 |
79
+ | 2.0.0 | Firefox N | WebGPU | 25805 | 4.94 | ? | 201.60 |
80
+ | 2.0.0 | Firefox | WebGL | Unusable | N/A | ? | N/A |
81
+ | 2.0.0 | Firefox N | WebGL | Unusable | N/A | ? | N/A |
82
+ | 2.0.0 | Chromium N | WebGL | Unusable | N/A | ? | N/A |
83
+
84
+ ## iPhone 12 (A14 Bionic, ??? 4-core GPU)
85
+ | Version | Browser | API | Total | Rate | Median | Mean |
86
+ |-----------|-------------|-----------|-----------|----------|----------|----------|
87
+ | RC | Safari | WebGPU | 8586 | 14.97 | 67 | 66.79 |
88
+ | 2.0.0 | Safari | WebGPU | 8765 | 14.69 | 68 | 68.48 |
89
+ | RC | Safari | WebGL | 12631 | 10.54 | 95 | 94.86 |
90
+ | 2.0.0 | Safari | WebGL | Unusable | N/A | ? | N/A |
91
+
92
+ ## iPad Mini 5 (A12 Bionic, G11P 4-core GPU)
93
+ | Version | Browser | API | Total | Rate | Median | Mean |
94
+ |-----------|-------------|-----------|-----------|----------|----------|----------|
95
+ | RC | Safari | WebGPU | 14232 | 8.78 | 114 | 113.85 |
96
+ | 2.0.0 | Safari | WebGPU | 14903 | 8.59 | 118 | 116.41 |
97
+ | RC | Safari | WebGL | 18928 | 6.97 | 145 | 143.40 |
98
+ | 2.0.0 | Safari | WebGL | Unusable | N/A | ? | N/A |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nano-pow",
3
- "version": "3.1.3",
3
+ "version": "3.2.0",
4
4
  "description": "Proof-of-work generation and validation with WebGPU/WebGL for Nano cryptocurrency.",
5
5
  "keywords": [
6
6
  "nemo",
@@ -27,29 +27,31 @@
27
27
  },
28
28
  "files": [
29
29
  "/dist",
30
+ "/docs",
30
31
  "/LICENSES",
31
32
  "AUTHORS.md",
32
33
  "package.json.license"
33
34
  ],
34
- "main": "dist/main.min.js",
35
+ "main": "./dist/main.min.js",
35
36
  "browser": {
36
37
  "./dist/main.min.js": true
37
38
  },
38
- "bin": "./dist/cli.js",
39
- "man": "./dist/nano-pow.1",
39
+ "bin": {
40
+ "nano-pow": "dist/bin/cli.js"
41
+ },
42
+ "man": "./docs/nano-pow.1",
40
43
  "repository": {
41
44
  "type": "git",
42
45
  "url": "git+https://zoso.dev/nano-pow.git"
43
46
  },
44
47
  "scripts": {
45
- "build": "rm -rf {dist,types} && tsc && node esbuild.mjs && npm run fix-copyright && cp cli.js nano-pow.1 types.d.ts dist",
46
- "fix-copyright": "sed -i '/\\/\\/ src\\/shaders\\/compute\\.wgsl/a //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>\\n//! SPDX-License-Identifier: GPL-3.0-or-later' dist/main.min.js"
48
+ "build": "rm -rf {dist,types} && tsc && node esbuild.mjs"
47
49
  },
48
50
  "devDependencies": {
49
51
  "@types/node": "^22.13.10",
50
- "@webgpu/types": "^0.1.55",
52
+ "@webgpu/types": "^0.1.57",
51
53
  "esbuild": "^0.25.1",
52
- "esbuild-plugin-glsl": "^1.2.3",
54
+ "esbuild-plugin-glsl": "^1.4.0",
53
55
  "typescript": "^5.8.2"
54
56
  },
55
57
  "type": "module",
package/dist/cli.js DELETED
@@ -1,185 +0,0 @@
1
- #!/usr/bin/env node
2
- //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@zoso.dev>
3
- //! SPDX-License-Identifier: GPL-3.0-or-later
4
-
5
- import * as fs from 'node:fs/promises'
6
- import * as readline from 'node:readline/promises'
7
- import * as puppeteer from 'puppeteer'
8
-
9
- const hashes = []
10
-
11
- const stdinErrors = []
12
- if (!process.stdin.isTTY) {
13
- const stdin = readline.createInterface({
14
- input: process.stdin
15
- })
16
- for await (const line of stdin) {
17
- if (/^[0-9A-Fa-f]{64}$/.test(line)) {
18
- hashes.push(line)
19
- } else {
20
- stdinErrors.push(`Skipping invalid stdin input: ${line}`)
21
- }
22
- }
23
- }
24
-
25
- const args = process.argv.slice(2)
26
- if ((hashes.length === 0 && args.length === 0) || (args.some(v => v === '--help' || v === '-h'))) {
27
- console.log(`Usage: nano-pow [OPTION]... BLOCKHASH...
28
- Generate work for BLOCKHASH, or multiple work values for BLOCKHASH(es)
29
- BLOCKHASH is a 64-character hexadecimal string. Multiple blockhashes must be separated by whitespace or line breaks.
30
- Prints a 16-character hexadecimal work value to standard output. If using --validate, prints 'true' or 'false' to standard output instead.
31
-
32
- -h, --help show this dialog
33
- -d, --debug enable additional logging output
34
- -j, --json format output as JSON
35
- -e, --effort=<value> increase demand on GPU processing
36
- -t, --threshold=<value> override the minimum threshold value
37
- -v, --validate=<value> check an existing work value instead of searching for one
38
-
39
- If validating a nonce, it must be a 16-character hexadecimal value.
40
- Effort must be a decimal number between 1-32.
41
- Threshold must be a hexadecimal string between 0-FFFFFFFF.
42
-
43
- Report bugs: <bug-nano-pow@zoso.dev>
44
- Full documentation: <https://www.npmjs.com/package/nano-pow>
45
- `)
46
- process.exit()
47
- }
48
-
49
- const inArgs = []
50
- while (/^[0-9A-Fa-f]{64}$/.test(args[args.length - 1] ?? '')) {
51
- inArgs.unshift(args.pop())
52
- }
53
- hashes.push(...inArgs)
54
-
55
- let fn = 'search'
56
- let work = ''
57
- let isJson = false
58
- const options = {}
59
-
60
- for (let i = 0; i < args.length; i++) {
61
- switch (args[i]) {
62
- case ('--validate'):
63
- case ('-v'): {
64
- if (args[i + 1] == null) throw new Error('Missing argument for work validation')
65
- if (!/^[0-9A-Fa-f]{16}$/.test(args[i + 1])) throw new Error('Invalid work to validate')
66
- fn = 'validate'
67
- work = `'${args[i + 1]}', `
68
- break
69
- }
70
- case ('--threshold'):
71
- case ('-t'): {
72
- if (args[i + 1] == null) throw new Error('Missing argument for threshold')
73
- if (!/^[0-9A-Fa-f]{0,8}$/.test(args[i + 1])) throw new Error('Invalid threshold')
74
- options['threshold'] = parseInt(args[i + 1], 16)
75
- break
76
- }
77
- case ('--effort'):
78
- case ('-e'): {
79
- if (args[i + 1] == null) throw new Error('Missing argument for effort')
80
- if (!/^[0-9]{0,2}$/.test(args[i + 1])) throw new Error('Invalid effort')
81
- options['effort'] = parseInt(args[i + 1], 10)
82
- break
83
- }
84
- case ('--debug'):
85
- case ('-d'): {
86
- options['debug'] = true
87
- break
88
- }
89
- case ('--json'):
90
- case ('-j'): {
91
- isJson = true
92
- break
93
- }
94
- }
95
- }
96
-
97
- if (options['debug']) {
98
- console.log(`NanoPowCli.${fn}()`)
99
- console.log(`${fn} options`, JSON.stringify(options))
100
- for (const stdinErr of stdinErrors) {
101
- console.warn(stdinErr)
102
- }
103
- }
104
-
105
- if (hashes.length === 0) {
106
- console.error('Invalid block hash input')
107
- process.exit(1)
108
- }
109
-
110
- /**
111
- * Main
112
- */
113
- (async () => {
114
- const NanoPow = await fs.readFile(`${import.meta.dirname}/main.min.js`, 'utf-8')
115
- const browser = await puppeteer.launch({
116
- headless: true,
117
- args: [
118
- '--no-sandbox',
119
- '--headless=new',
120
- '--use-angle=vulkan',
121
- '--enable-features=Vulkan',
122
- '--disable-vulkan-surface',
123
- '--enable-unsafe-webgpu',
124
- '--enable-vulkan'
125
- ]
126
- })
127
- const page = await browser.newPage()
128
- await page.setBypassCSP(true)
129
- await page.goto('chrome://terms')
130
-
131
- let start = performance.now()
132
- page.on('console', async (msg) => {
133
- const output = msg.text().split(' ')
134
- if (output[0] === 'cli') {
135
- if (output[1] === 'exit') {
136
- if (isJson) {
137
- const results = await page.evaluate(() => {
138
- return window.results
139
- })
140
- for (let i = 0; i < results.length; i++) {
141
- results[i] = {
142
- blockhash: hashes[i],
143
- work: results[i]
144
- }
145
- }
146
- console.log(JSON.stringify(results, null, 4))
147
- }
148
- const end = performance.now()
149
- if (options['debug']) console.log(end - start, 'ms total |', (end - start) / hashes.length, 'ms avg')
150
- await browser.close()
151
- } else if (!isJson) {
152
- console.log(output[1])
153
- }
154
- } else if (options['debug']) {
155
- console.log(msg.text())
156
- }
157
- })
158
- await page.waitForFunction(async () => {
159
- return await navigator.gpu.requestAdapter()
160
- })
161
- start = performance.now()
162
- await page.addScriptTag({
163
- type: 'module',
164
- content: `
165
- window.trustedTypes?.createPolicy?.('default', {
166
- createHTML: string => string,
167
- createScriptURL: string => string,
168
- createScript: string => string,
169
- })
170
- ${NanoPow}
171
- window.results = []
172
- const hashes = ["${hashes.join('","')}"]
173
- for (const hash of hashes) {
174
- try {
175
- const work = await NanoPow.${fn}(${work}hash, ${JSON.stringify(options)})
176
- window.results.push(work)
177
- console.log(\`cli \${work}\`)
178
- } catch (err) {
179
- console.error(\`cli \${err}\`)
180
- }
181
- }
182
- console.log('cli exit')
183
- `
184
- })
185
- })()
File without changes