ic-mops 1.4.0-pre.0 → 1.4.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/CHANGELOG.md CHANGED
@@ -1,9 +1,23 @@
1
1
  # Mops CLI Changelog
2
2
 
3
+ ## 1.4.0
4
+ - Update `mops bench` command output:
5
+ - Print only final results if benchmarks run in a CI environment or there is no vertical space to progressively print the results
6
+ - Hide "Stable Memory" table if it has no data
7
+ - Hide verbose output when running in a CI environment ("Starting replica...", "Running simple.bench.mo...", etc.)
8
+ - Add LaTeX colors to the diffs when running in a CI environment with `--compare` flag
9
+ - CLI now fails if excess arguments are passed to it
10
+
11
+ ## 1.3.0
12
+ - Show error on `mops install <pkg>` command. Use `mops add <pkg>` instead.
13
+ - Added support for pocket-ic replica that comes with dfx in `mops bench` command. To activate it, remove `pocket-ic` from `mops.toml` and run `mops bench --replica pocket-ic`. Requires dfx 0.24.1 or higher.
14
+ - `mops init` now pre-fills package name with current directory name in kebab-case
15
+ - Updated non-major npm dependencies
16
+
3
17
  ## 1.2.0
4
18
  - Removed `mops transfer-ownership` command
5
19
  - Added `mops owner` command to manage package owners ([docs](https://docs.mops.one/cli/mops-owner))
6
- - Added `mops maintainers` command to manage package maintainers ([docs](https://docs.mops.one/cli/mops-maintainers))
20
+ - Added `mops maintainer` command to manage package maintainers ([docs](https://docs.mops.one/cli/mops-maintainer))
7
21
  - Added experimental support for pocket-ic replica that comes with dfx in `mops test` command ([docs](https://docs.mops.one/cli/mops-test#--replica))
8
22
  - Added flag `--verbose` to `mops test` command to show replica logs
9
23
  - Fixed bug where `mops watch` would fail if dfx.json did not exist
package/README.md CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  Mops is a package manager for the Motoko programming language.
4
4
 
5
- See https://mops.one
5
+ - [Motoko Package Registry](https://mops.one)
6
+ - [Documentation](https://docs.mops.one)
7
+ - [Blog](https://blog.mops.one)
8
+ - [CLI](https://cli.mops.one)
6
9
 
7
10
  ## Setup
8
11
 
@@ -12,6 +15,10 @@ See https://mops.one
12
15
 
13
16
  ### 2. Install CLI tool
14
17
  ```
18
+ curl -fsSL cli.mops.one/install.sh | sh
19
+ ```
20
+ or
21
+ ```
15
22
  npm i -g ic-mops
16
23
  ```
17
24
 
@@ -33,8 +40,6 @@ Add `mops` as a packtool to your `dfx.json`
33
40
  ### 2. Initialize
34
41
  Run this command in the root directory of your project (where is `dfx.json` placed)
35
42
 
36
- If there are Vessel config files, mops will migrate packages from `vessel.dhall` to `mops.toml`
37
-
38
43
  ```
39
44
  mops init
40
45
  ```
@@ -110,4 +115,7 @@ Publish package to the mops registry!
110
115
 
111
116
  ```
112
117
  mops publish
113
- ```
118
+ ```
119
+
120
+ ------------
121
+ *Built for the [Supernova Hackathon](https://dfinity.org/supernova/)*
package/bundle/cli.tgz CHANGED
Binary file
package/cli.ts CHANGED
@@ -2,6 +2,7 @@ import process from 'node:process';
2
2
  import fs from 'node:fs';
3
3
  import events from 'node:events';
4
4
  import {Command, Argument, Option} from 'commander';
5
+ import chalk from 'chalk';
5
6
 
6
7
  import {init} from './commands/init.js';
7
8
  import {publish} from './commands/publish.js';
@@ -98,6 +99,11 @@ program
98
99
  .option('--verbose')
99
100
  .addOption(new Option('--lock <action>', 'Lockfile action').choices(['check', 'update', 'ignore']))
100
101
  .action(async (options) => {
102
+ if (process.argv.at(-1) !== 'install') {
103
+ console.log(`${chalk.red('Error:')} ${chalk.yellow('mops install')} command installs all dependencies.\nUse ${chalk.green(`mops add ${process.argv.at(-1)}`)} instead.`);
104
+ process.exit(1);
105
+ }
106
+
101
107
  if (!checkConfigFile()) {
102
108
  process.exit(1);
103
109
  }
@@ -7,33 +7,36 @@ import {PocketIc, PocketIcServer} from 'pic-ic';
7
7
  import {getRootDir, readConfig} from '../mops.js';
8
8
  import {createActor, idlFactory} from '../declarations/bench/index.js';
9
9
  import {toolchain} from './toolchain/index.js';
10
+ import {getDfxVersion} from '../helpers/get-dfx-version.js';
10
11
 
11
12
  export class BenchReplica {
12
- type : 'dfx' | 'pocket-ic';
13
+ type : 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
13
14
  verbose = false;
14
15
  canisters : Record<string, {cwd : string; canisterId : string; actor : any;}> = {};
15
16
  pocketIcServer ?: PocketIcServer;
16
17
  pocketIc ?: PocketIc;
17
18
 
18
- constructor(type : 'dfx' | 'pocket-ic', verbose = false) {
19
+ constructor(type : 'dfx' | 'pocket-ic' | 'dfx-pocket-ic', verbose = false) {
19
20
  this.type = type;
20
21
  this.verbose = verbose;
21
22
  }
22
23
 
23
24
  async start({silent = false} = {}) {
24
- silent || console.log(`Starting ${this.type} replica...`);
25
+ if (!process.env.CI && !silent) {
26
+ console.log(`Starting ${this.type} replica...`);
27
+ }
25
28
 
26
- if (this.type == 'dfx') {
29
+ if (this.type == 'dfx' || this.type === 'dfx-pocket-ic') {
27
30
  await this.stop();
28
31
  let dir = path.join(getRootDir(), '.mops/.bench');
29
32
  fs.writeFileSync(path.join(dir, 'dfx.json'), JSON.stringify(this.dfxJson(''), null, 2));
30
- execSync('dfx start --background --clean --artificial-delay 0' + (this.verbose ? '' : ' -qqqq'), {cwd: dir, stdio: ['inherit', this.verbose ? 'inherit' : 'ignore', 'inherit']});
33
+ execSync('dfx start --background --clean --artificial-delay 0' + (this.type === 'dfx-pocket-ic' ? ' --pocketic' : '') + (this.verbose ? '' : ' -qqqq'), {cwd: dir, stdio: ['inherit', this.verbose ? 'inherit' : 'ignore', 'inherit']});
31
34
  }
32
35
  else {
33
36
  let pocketIcBin = await toolchain.bin('pocket-ic');
34
37
  let config = readConfig();
35
- if (config.toolchain?.['pocket-ic'] !== '6.0.0') {
36
- console.error('Current Mops CLI only supports pocket-ic 6.0.0');
38
+ if (config.toolchain?.['pocket-ic'] !== '4.0.0') {
39
+ console.error('Current Mops CLI only supports pocket-ic 4.0.0');
37
40
  process.exit(1);
38
41
  }
39
42
  this.pocketIcServer = await PocketIcServer.start({
@@ -44,7 +47,7 @@ export class BenchReplica {
44
47
  }
45
48
 
46
49
  async stop() {
47
- if (this.type == 'dfx') {
50
+ if (this.type == 'dfx' || this.type === 'dfx-pocket-ic') {
48
51
  let dir = path.join(getRootDir(), '.mops/.bench');
49
52
  execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), {cwd: dir, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
50
53
  }
@@ -55,7 +58,7 @@ export class BenchReplica {
55
58
  }
56
59
 
57
60
  async deploy(name : string, wasm : string, cwd : string = process.cwd()) {
58
- if (this.type === 'dfx') {
61
+ if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
59
62
  await execaCommand(`dfx deploy ${name} --mode reinstall --yes --identity anonymous`, {cwd, stdio: this.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe']});
60
63
  let canisterId = execSync(`dfx canister id ${name}`, {cwd}).toString().trim();
61
64
  let actor = await createActor(canisterId, {
@@ -96,6 +99,7 @@ export class BenchReplica {
96
99
  return {
97
100
  version: 1,
98
101
  canisters,
102
+ dfx: getDfxVersion(),
99
103
  defaults: {
100
104
  build: {
101
105
  packtool: 'mops sources',
@@ -109,4 +113,4 @@ export class BenchReplica {
109
113
  },
110
114
  };
111
115
  }
112
- }
116
+ }
package/commands/bench.ts CHANGED
@@ -5,9 +5,12 @@ import os from 'node:os';
5
5
  import chalk from 'chalk';
6
6
  import {globSync} from 'glob';
7
7
  import {markdownTable} from 'markdown-table';
8
- import logUpdate from 'log-update';
8
+ import {createLogUpdate} from 'log-update';
9
9
  import {execaCommand} from 'execa';
10
10
  import stringWidth from 'string-width';
11
+ import {filesize} from 'filesize';
12
+ import terminalSize from 'terminal-size';
13
+ import {SemVer} from 'semver';
11
14
 
12
15
  import {getRootDir, readConfig} from '../mops.js';
13
16
  import {parallel} from '../parallel.js';
@@ -20,7 +23,8 @@ import {sources} from './sources.js';
20
23
  import {Benchmark, Benchmarks} from '../declarations/main/main.did.js';
21
24
  import {BenchResult, _SERVICE} from '../declarations/bench/bench.did.js';
22
25
  import {BenchReplica} from './bench-replica.js';
23
- import {filesize} from 'filesize';
26
+
27
+ type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
24
28
 
25
29
  let ignore = [
26
30
  '**/node_modules/**',
@@ -35,7 +39,7 @@ let globConfig = {
35
39
  };
36
40
 
37
41
  type BenchOptions = {
38
- replica : 'dfx' | 'pocket-ic',
42
+ replica : ReplicaName,
39
43
  replicaVersion : string,
40
44
  compiler : 'moc',
41
45
  compilerVersion : string,
@@ -66,16 +70,34 @@ export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}
66
70
 
67
71
  let options : BenchOptions = {...defaultOptions, ...optionsArg};
68
72
 
69
- if (options.replica == 'dfx') {
73
+ let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx' as ReplicaName);
74
+ if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
75
+ let dfxVersion = getDfxVersion();
76
+ if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
77
+ console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
78
+ process.exit(1);
79
+ }
80
+ else {
81
+ replicaType = 'dfx-pocket-ic';
82
+ }
83
+ }
84
+
85
+ options.replica = replicaType;
86
+
87
+ if (process.env.CI) {
88
+ console.log('# Benchmark Results\n\n');
89
+ }
90
+
91
+ if (replicaType == 'dfx') {
70
92
  options.replicaVersion = getDfxVersion();
71
93
  }
72
- else if (options.replica == 'pocket-ic') {
94
+ else if (replicaType == 'pocket-ic') {
73
95
  options.replicaVersion = config.toolchain?.['pocket-ic'] || '';
74
96
  }
75
97
 
76
98
  options.verbose && console.log(options);
77
99
 
78
- let replica = new BenchReplica(options.replica, options.verbose);
100
+ let replica = new BenchReplica(replicaType, options.verbose);
79
101
 
80
102
  let rootDir = getRootDir();
81
103
  let globStr = '**/bench?(mark)/**/*.bench.mo';
@@ -106,14 +128,19 @@ export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}
106
128
  for (let file of files) {
107
129
  console.log(chalk.gray(`• ${absToRel(file)}`));
108
130
  }
109
- console.log('');
110
- console.log('='.repeat(50));
111
- console.log('');
131
+ if (!process.env.CI) {
132
+ console.log('');
133
+ console.log('='.repeat(50));
134
+ console.log('');
135
+ }
112
136
  }
113
137
 
114
138
  await replica.start({silent: options.silent});
115
139
 
116
- options.silent || console.log('Deploying canisters...');
140
+ if (!process.env.CI && !options.silent) {
141
+ console.log('Deploying canisters...');
142
+ }
143
+
117
144
  await parallel(os.cpus().length, files, async (file : string) => {
118
145
  try {
119
146
  await deployBenchFile(file, options, replica);
@@ -128,8 +155,8 @@ export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}
128
155
  let benchResults : Benchmarks = [];
129
156
 
130
157
  await parallel(1, files, async (file : string) => {
131
- if (!options.silent) {
132
- console.log('\n' + ''.repeat(50));
158
+ if (!options.silent && !process.env.CI) {
159
+ console.log('\n' + '-'.repeat(50));
133
160
  console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
134
161
  console.log('');
135
162
  }
@@ -144,7 +171,9 @@ export async function bench(filter = '', optionsArg : Partial<BenchOptions> = {}
144
171
  }
145
172
  });
146
173
 
147
- options.silent || console.log('Stopping replica...');
174
+ if (!process.env.CI && !options.silent) {
175
+ console.log('Stopping replica...');
176
+ }
148
177
  await replica.stop();
149
178
 
150
179
  fs.rmSync(benchDir, {recursive: true, force: true});
@@ -234,6 +263,7 @@ async function runBenchFile(file : string, options : BenchOptions, replica : Ben
234
263
 
235
264
  let getTable = (prop : keyof BenchResult) : string => {
236
265
  let resArr = [['', ...schema.cols]];
266
+ let allZero = true;
237
267
 
238
268
  for (let [_rowIndex, row] of schema.rows.entries()) {
239
269
  let curRow = [row];
@@ -241,6 +271,9 @@ async function runBenchFile(file : string, options : BenchOptions, replica : Ben
241
271
  for (let [_colIndex, col] of schema.cols.entries()) {
242
272
  let res = results.get(`${row}:${col}`);
243
273
  if (res) {
274
+ if (res[prop] != 0n) {
275
+ allZero = false;
276
+ }
244
277
 
245
278
  // compare with previous results
246
279
  let diff = '';
@@ -248,10 +281,18 @@ async function runBenchFile(file : string, options : BenchOptions, replica : Ben
248
281
  let prevRes = prevResults.get(`${row}:${col}`);
249
282
  if (prevRes) {
250
283
  let percent = (Number(res[prop]) - Number(prevRes[prop])) / Number(prevRes[prop]) * 100;
284
+ if (Object.is(percent, NaN)) {
285
+ percent = 0;
286
+ }
251
287
  let sign = percent > 0 ? '+' : '';
252
288
  let percentText = percent == 0 ? '0%' : sign + percent.toFixed(2) + '%';
253
289
  let color : keyof typeof chalk = percent == 0 ? 'gray' : (percent > 0 ? 'red' : 'green');
254
- diff = ` (${chalk[color](percentText)})`;
290
+ if (process.env.CI) {
291
+ diff = ` $({\\color{${color}}${percentText.replace('%', '\\\\%')}})$`;
292
+ }
293
+ else {
294
+ diff = ` (${chalk[color](percentText)})`;
295
+ }
255
296
  }
256
297
  else {
257
298
  diff = chalk.yellow(' (no previous results)');
@@ -278,25 +319,47 @@ async function runBenchFile(file : string, options : BenchOptions, replica : Ben
278
319
  resArr.push(curRow);
279
320
  }
280
321
 
322
+ // don't show Stable Memory table if all values are 0
323
+ if (allZero && prop == 'rts_logical_stable_memory_size') {
324
+ return '';
325
+ }
326
+
281
327
  return markdownTable(resArr, {
282
328
  align: ['l', ...'r'.repeat(schema.cols.length)],
283
329
  stringLength: stringWidth,
284
330
  });
285
331
  };
286
332
 
287
- let printResults = () => {
288
- logUpdate(`
289
- \n${chalk.bold(schema.name)}
290
- ${schema.description ? '\n' + chalk.gray(schema.description) : ''}
333
+ let logUpdate = createLogUpdate(process.stdout, {showCursor: true});
334
+
335
+ let getOutput = () => {
336
+ return `
337
+ \n${process.env.CI ? `## ${schema.name}` : chalk.bold(schema.name)}
338
+ ${schema.description ? '\n' + (process.env.CI ? `_${schema.description}_` : chalk.gray(schema.description)) : ''}
291
339
  \n\n${chalk.blue('Instructions')}\n\n${getTable('instructions')}
292
340
  \n\n${chalk.blue('Heap')}\n\n${getTable('rts_heap_size')}
293
- \n\n${chalk.blue('Stable Memory')}\n\n${getTable('rts_logical_stable_memory_size')}
294
341
  \n\n${chalk.blue('Garbage Collection')}\n\n${getTable('rts_reclaimed')}
295
- `);
342
+ ${getTable('rts_logical_stable_memory_size') ? `\n\n${chalk.blue('Stable Memory')}\n\n${getTable('rts_logical_stable_memory_size')}` : ''}
343
+ `;
296
344
  };
297
345
 
298
- if (!process.env.CI && !options.silent) {
299
- printResults();
346
+ let canUpdateLog = !process.env.CI && !options.silent && terminalSize().rows > getOutput().split('\n').length;
347
+
348
+ let log = () => {
349
+ if (options.silent) {
350
+ return;
351
+ }
352
+ let output = getOutput();
353
+ if (process.env.CI || terminalSize().rows <= output.split('\n').length) {
354
+ console.log(output);
355
+ }
356
+ else {
357
+ logUpdate(output);
358
+ }
359
+ };
360
+
361
+ if (canUpdateLog) {
362
+ log();
300
363
  }
301
364
 
302
365
  // run all cells
@@ -314,16 +377,18 @@ async function runBenchFile(file : string, options : BenchOptions, replica : Ben
314
377
  // @ts-ignore
315
378
  reclaimedCells[rowIndex][colIndex] = res.rts_reclaimed;
316
379
 
317
- if (!process.env.CI && !options.silent) {
318
- printResults();
380
+ if (canUpdateLog) {
381
+ log();
319
382
  }
320
383
  }
321
384
  }
322
385
 
323
- if (process.env.CI) {
324
- printResults();
386
+ if (canUpdateLog) {
387
+ logUpdate.done();
388
+ }
389
+ else {
390
+ log();
325
391
  }
326
- logUpdate.done();
327
392
 
328
393
  // save results
329
394
  if (options.save) {
package/commands/init.ts CHANGED
@@ -11,6 +11,7 @@ import {installAll} from './install/install-all.js';
11
11
  import {VesselConfig, readVesselConfig} from '../vessel.js';
12
12
  import {Config, Dependencies} from '../types.js';
13
13
  import {template} from './template.js';
14
+ import {kebabCase} from 'change-case';
14
15
 
15
16
  export async function init({yes = false} = {}) {
16
17
  let configFile = path.join(process.cwd(), 'mops.toml');
@@ -88,7 +89,7 @@ export async function init({yes = false} = {}) {
88
89
  type: 'text',
89
90
  name: 'name',
90
91
  message: 'Enter package name:',
91
- initial: '',
92
+ initial: kebabCase(path.basename(process.cwd())),
92
93
  },
93
94
  {
94
95
  type: 'text',
@@ -133,7 +134,7 @@ export async function init({yes = false} = {}) {
133
134
  ], promptsConfig);
134
135
 
135
136
  config.package = {
136
- name: (res.name || '').trim(),
137
+ name: kebabCase((res.name || '').trim()),
137
138
  version: '1.0.0',
138
139
  description: (res.description || '').trim(),
139
140
  repository: (res.repository || '').trim(),
@@ -87,8 +87,8 @@ export class Replica {
87
87
 
88
88
  // eslint-disable-next-line
89
89
  let config = readConfig();
90
- if (config.toolchain?.['pocket-ic'] !== '6.0.0') {
91
- console.error('Current Mops CLI only supports pocket-ic 6.0.0');
90
+ if (config.toolchain?.['pocket-ic'] !== '4.0.0') {
91
+ console.error('Current Mops CLI only supports pocket-ic 4.0.0');
92
92
  process.exit(1);
93
93
  }
94
94
 
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import chalk from 'chalk';
4
4
  import prompts from 'prompts';
5
- import camelCase from 'camelcase';
5
+ import {kebabCase, pascalCase} from 'change-case';
6
6
  import {getRootDir, readConfig} from '../mops.js';
7
7
  import {copyTemplateFileSync} from '../templates.js';
8
8
 
@@ -99,8 +99,8 @@ export async function template(templateName ?: string, options : any = {}) {
99
99
  let data = fs.readFileSync(dest).toString();
100
100
  data = data.replace(/<year>/g, new Date().getFullYear().toString());
101
101
  if (config.package?.name) {
102
- data = data.replace(/<name>/g, config.package.name);
103
- data = data.replace(/<import-name>/g, camelCase(config.package.name, {pascalCase: true}));
102
+ data = data.replace(/<name>/g, kebabCase(config.package.name));
103
+ data = data.replace(/<import-name>/g, pascalCase(config.package.name));
104
104
  }
105
105
  fs.writeFileSync(dest, data);
106
106
 
package/dist/cli.js CHANGED
@@ -2,6 +2,7 @@ import process from 'node:process';
2
2
  import fs from 'node:fs';
3
3
  import events from 'node:events';
4
4
  import { Command, Argument, Option } from 'commander';
5
+ import chalk from 'chalk';
5
6
  import { init } from './commands/init.js';
6
7
  import { publish } from './commands/publish.js';
7
8
  import { sources } from './commands/sources.js';
@@ -80,6 +81,10 @@ program
80
81
  .option('--verbose')
81
82
  .addOption(new Option('--lock <action>', 'Lockfile action').choices(['check', 'update', 'ignore']))
82
83
  .action(async (options) => {
84
+ if (process.argv.at(-1) !== 'install') {
85
+ console.log(`${chalk.red('Error:')} ${chalk.yellow('mops install')} command installs all dependencies.\nUse ${chalk.green(`mops add ${process.argv.at(-1)}`)} instead.`);
86
+ process.exit(1);
87
+ }
83
88
  if (!checkConfigFile()) {
84
89
  process.exit(1);
85
90
  }
@@ -1,6 +1,6 @@
1
1
  import { PocketIc, PocketIcServer } from 'pic-ic';
2
2
  export declare class BenchReplica {
3
- type: 'dfx' | 'pocket-ic';
3
+ type: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
4
4
  verbose: boolean;
5
5
  canisters: Record<string, {
6
6
  cwd: string;
@@ -9,7 +9,7 @@ export declare class BenchReplica {
9
9
  }>;
10
10
  pocketIcServer?: PocketIcServer;
11
11
  pocketIc?: PocketIc;
12
- constructor(type: 'dfx' | 'pocket-ic', verbose?: boolean);
12
+ constructor(type: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic', verbose?: boolean);
13
13
  start({ silent }?: {
14
14
  silent?: boolean | undefined;
15
15
  }): Promise<void>;
@@ -20,6 +20,7 @@ export declare class BenchReplica {
20
20
  dfxJson(canisterName: string): {
21
21
  version: number;
22
22
  canisters: Record<string, any>;
23
+ dfx: string;
23
24
  defaults: {
24
25
  build: {
25
26
  packtool: string;
@@ -7,6 +7,7 @@ import { PocketIc, PocketIcServer } from 'pic-ic';
7
7
  import { getRootDir, readConfig } from '../mops.js';
8
8
  import { createActor, idlFactory } from '../declarations/bench/index.js';
9
9
  import { toolchain } from './toolchain/index.js';
10
+ import { getDfxVersion } from '../helpers/get-dfx-version.js';
10
11
  export class BenchReplica {
11
12
  constructor(type, verbose = false) {
12
13
  this.verbose = false;
@@ -15,18 +16,20 @@ export class BenchReplica {
15
16
  this.verbose = verbose;
16
17
  }
17
18
  async start({ silent = false } = {}) {
18
- silent || console.log(`Starting ${this.type} replica...`);
19
- if (this.type == 'dfx') {
19
+ if (!process.env.CI && !silent) {
20
+ console.log(`Starting ${this.type} replica...`);
21
+ }
22
+ if (this.type == 'dfx' || this.type === 'dfx-pocket-ic') {
20
23
  await this.stop();
21
24
  let dir = path.join(getRootDir(), '.mops/.bench');
22
25
  fs.writeFileSync(path.join(dir, 'dfx.json'), JSON.stringify(this.dfxJson(''), null, 2));
23
- execSync('dfx start --background --clean --artificial-delay 0' + (this.verbose ? '' : ' -qqqq'), { cwd: dir, stdio: ['inherit', this.verbose ? 'inherit' : 'ignore', 'inherit'] });
26
+ execSync('dfx start --background --clean --artificial-delay 0' + (this.type === 'dfx-pocket-ic' ? ' --pocketic' : '') + (this.verbose ? '' : ' -qqqq'), { cwd: dir, stdio: ['inherit', this.verbose ? 'inherit' : 'ignore', 'inherit'] });
24
27
  }
25
28
  else {
26
29
  let pocketIcBin = await toolchain.bin('pocket-ic');
27
30
  let config = readConfig();
28
- if (config.toolchain?.['pocket-ic'] !== '6.0.0') {
29
- console.error('Current Mops CLI only supports pocket-ic 6.0.0');
31
+ if (config.toolchain?.['pocket-ic'] !== '4.0.0') {
32
+ console.error('Current Mops CLI only supports pocket-ic 4.0.0');
30
33
  process.exit(1);
31
34
  }
32
35
  this.pocketIcServer = await PocketIcServer.start({
@@ -36,7 +39,7 @@ export class BenchReplica {
36
39
  }
37
40
  }
38
41
  async stop() {
39
- if (this.type == 'dfx') {
42
+ if (this.type == 'dfx' || this.type === 'dfx-pocket-ic') {
40
43
  let dir = path.join(getRootDir(), '.mops/.bench');
41
44
  execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), { cwd: dir, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe'] });
42
45
  }
@@ -46,7 +49,7 @@ export class BenchReplica {
46
49
  }
47
50
  }
48
51
  async deploy(name, wasm, cwd = process.cwd()) {
49
- if (this.type === 'dfx') {
52
+ if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
50
53
  await execaCommand(`dfx deploy ${name} --mode reinstall --yes --identity anonymous`, { cwd, stdio: this.verbose ? 'pipe' : ['pipe', 'ignore', 'pipe'] });
51
54
  let canisterId = execSync(`dfx canister id ${name}`, { cwd }).toString().trim();
52
55
  let actor = await createActor(canisterId, {
@@ -83,6 +86,7 @@ export class BenchReplica {
83
86
  return {
84
87
  version: 1,
85
88
  canisters,
89
+ dfx: getDfxVersion(),
86
90
  defaults: {
87
91
  build: {
88
92
  packtool: 'mops sources',
@@ -1,6 +1,7 @@
1
1
  import { Benchmarks } from '../declarations/main/main.did.js';
2
+ type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
2
3
  type BenchOptions = {
3
- replica: 'dfx' | 'pocket-ic';
4
+ replica: ReplicaName;
4
5
  replicaVersion: string;
5
6
  compiler: 'moc';
6
7
  compilerVersion: string;
@@ -5,9 +5,12 @@ import os from 'node:os';
5
5
  import chalk from 'chalk';
6
6
  import { globSync } from 'glob';
7
7
  import { markdownTable } from 'markdown-table';
8
- import logUpdate from 'log-update';
8
+ import { createLogUpdate } from 'log-update';
9
9
  import { execaCommand } from 'execa';
10
10
  import stringWidth from 'string-width';
11
+ import { filesize } from 'filesize';
12
+ import terminalSize from 'terminal-size';
13
+ import { SemVer } from 'semver';
11
14
  import { getRootDir, readConfig } from '../mops.js';
12
15
  import { parallel } from '../parallel.js';
13
16
  import { absToRel } from './test/utils.js';
@@ -16,7 +19,6 @@ import { getDfxVersion } from '../helpers/get-dfx-version.js';
16
19
  import { getMocPath } from '../helpers/get-moc-path.js';
17
20
  import { sources } from './sources.js';
18
21
  import { BenchReplica } from './bench-replica.js';
19
- import { filesize } from 'filesize';
20
22
  let ignore = [
21
23
  '**/node_modules/**',
22
24
  '**/.mops/**',
@@ -42,14 +44,29 @@ export async function bench(filter = '', optionsArg = {}) {
42
44
  silent: false,
43
45
  };
44
46
  let options = { ...defaultOptions, ...optionsArg };
45
- if (options.replica == 'dfx') {
47
+ let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx');
48
+ if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
49
+ let dfxVersion = getDfxVersion();
50
+ if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
51
+ console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
52
+ process.exit(1);
53
+ }
54
+ else {
55
+ replicaType = 'dfx-pocket-ic';
56
+ }
57
+ }
58
+ options.replica = replicaType;
59
+ if (process.env.CI) {
60
+ console.log('# Benchmark Results\n\n');
61
+ }
62
+ if (replicaType == 'dfx') {
46
63
  options.replicaVersion = getDfxVersion();
47
64
  }
48
- else if (options.replica == 'pocket-ic') {
65
+ else if (replicaType == 'pocket-ic') {
49
66
  options.replicaVersion = config.toolchain?.['pocket-ic'] || '';
50
67
  }
51
68
  options.verbose && console.log(options);
52
- let replica = new BenchReplica(options.replica, options.verbose);
69
+ let replica = new BenchReplica(replicaType, options.verbose);
53
70
  let rootDir = getRootDir();
54
71
  let globStr = '**/bench?(mark)/**/*.bench.mo';
55
72
  if (filter) {
@@ -76,12 +93,16 @@ export async function bench(filter = '', optionsArg = {}) {
76
93
  for (let file of files) {
77
94
  console.log(chalk.gray(`• ${absToRel(file)}`));
78
95
  }
79
- console.log('');
80
- console.log('='.repeat(50));
81
- console.log('');
96
+ if (!process.env.CI) {
97
+ console.log('');
98
+ console.log('='.repeat(50));
99
+ console.log('');
100
+ }
82
101
  }
83
102
  await replica.start({ silent: options.silent });
84
- options.silent || console.log('Deploying canisters...');
103
+ if (!process.env.CI && !options.silent) {
104
+ console.log('Deploying canisters...');
105
+ }
85
106
  await parallel(os.cpus().length, files, async (file) => {
86
107
  try {
87
108
  await deployBenchFile(file, options, replica);
@@ -94,8 +115,8 @@ export async function bench(filter = '', optionsArg = {}) {
94
115
  });
95
116
  let benchResults = [];
96
117
  await parallel(1, files, async (file) => {
97
- if (!options.silent) {
98
- console.log('\n' + ''.repeat(50));
118
+ if (!options.silent && !process.env.CI) {
119
+ console.log('\n' + '-'.repeat(50));
99
120
  console.log(`\nRunning ${chalk.gray(absToRel(file))}...`);
100
121
  console.log('');
101
122
  }
@@ -109,7 +130,9 @@ export async function bench(filter = '', optionsArg = {}) {
109
130
  throw err;
110
131
  }
111
132
  });
112
- options.silent || console.log('Stopping replica...');
133
+ if (!process.env.CI && !options.silent) {
134
+ console.log('Stopping replica...');
135
+ }
113
136
  await replica.stop();
114
137
  fs.rmSync(benchDir, { recursive: true, force: true });
115
138
  return benchResults;
@@ -182,21 +205,33 @@ async function runBenchFile(file, options, replica) {
182
205
  };
183
206
  let getTable = (prop) => {
184
207
  let resArr = [['', ...schema.cols]];
208
+ let allZero = true;
185
209
  for (let [_rowIndex, row] of schema.rows.entries()) {
186
210
  let curRow = [row];
187
211
  for (let [_colIndex, col] of schema.cols.entries()) {
188
212
  let res = results.get(`${row}:${col}`);
189
213
  if (res) {
214
+ if (res[prop] != 0n) {
215
+ allZero = false;
216
+ }
190
217
  // compare with previous results
191
218
  let diff = '';
192
219
  if (options.compare && prevResults) {
193
220
  let prevRes = prevResults.get(`${row}:${col}`);
194
221
  if (prevRes) {
195
222
  let percent = (Number(res[prop]) - Number(prevRes[prop])) / Number(prevRes[prop]) * 100;
223
+ if (Object.is(percent, NaN)) {
224
+ percent = 0;
225
+ }
196
226
  let sign = percent > 0 ? '+' : '';
197
227
  let percentText = percent == 0 ? '0%' : sign + percent.toFixed(2) + '%';
198
228
  let color = percent == 0 ? 'gray' : (percent > 0 ? 'red' : 'green');
199
- diff = ` (${chalk[color](percentText)})`;
229
+ if (process.env.CI) {
230
+ diff = ` $({\\color{${color}}${percentText.replace('%', '\\\\%')}})$`;
231
+ }
232
+ else {
233
+ diff = ` (${chalk[color](percentText)})`;
234
+ }
200
235
  }
201
236
  else {
202
237
  diff = chalk.yellow(' (no previous results)');
@@ -221,23 +256,41 @@ async function runBenchFile(file, options, replica) {
221
256
  }
222
257
  resArr.push(curRow);
223
258
  }
259
+ // don't show Stable Memory table if all values are 0
260
+ if (allZero && prop == 'rts_logical_stable_memory_size') {
261
+ return '';
262
+ }
224
263
  return markdownTable(resArr, {
225
264
  align: ['l', ...'r'.repeat(schema.cols.length)],
226
265
  stringLength: stringWidth,
227
266
  });
228
267
  };
229
- let printResults = () => {
230
- logUpdate(`
231
- \n${chalk.bold(schema.name)}
232
- ${schema.description ? '\n' + chalk.gray(schema.description) : ''}
268
+ let logUpdate = createLogUpdate(process.stdout, { showCursor: true });
269
+ let getOutput = () => {
270
+ return `
271
+ \n${process.env.CI ? `## ${schema.name}` : chalk.bold(schema.name)}
272
+ ${schema.description ? '\n' + (process.env.CI ? `_${schema.description}_` : chalk.gray(schema.description)) : ''}
233
273
  \n\n${chalk.blue('Instructions')}\n\n${getTable('instructions')}
234
274
  \n\n${chalk.blue('Heap')}\n\n${getTable('rts_heap_size')}
235
- \n\n${chalk.blue('Stable Memory')}\n\n${getTable('rts_logical_stable_memory_size')}
236
275
  \n\n${chalk.blue('Garbage Collection')}\n\n${getTable('rts_reclaimed')}
237
- `);
276
+ ${getTable('rts_logical_stable_memory_size') ? `\n\n${chalk.blue('Stable Memory')}\n\n${getTable('rts_logical_stable_memory_size')}` : ''}
277
+ `;
238
278
  };
239
- if (!process.env.CI && !options.silent) {
240
- printResults();
279
+ let canUpdateLog = !process.env.CI && !options.silent && terminalSize().rows > getOutput().split('\n').length;
280
+ let log = () => {
281
+ if (options.silent) {
282
+ return;
283
+ }
284
+ let output = getOutput();
285
+ if (process.env.CI || terminalSize().rows <= output.split('\n').length) {
286
+ console.log(output);
287
+ }
288
+ else {
289
+ logUpdate(output);
290
+ }
291
+ };
292
+ if (canUpdateLog) {
293
+ log();
241
294
  }
242
295
  // run all cells
243
296
  for (let [rowIndex, row] of schema.rows.entries()) {
@@ -252,15 +305,17 @@ async function runBenchFile(file, options, replica) {
252
305
  logicalStableMemoryCells[rowIndex][colIndex] = res.rts_logical_stable_memory_size;
253
306
  // @ts-ignore
254
307
  reclaimedCells[rowIndex][colIndex] = res.rts_reclaimed;
255
- if (!process.env.CI && !options.silent) {
256
- printResults();
308
+ if (canUpdateLog) {
309
+ log();
257
310
  }
258
311
  }
259
312
  }
260
- if (process.env.CI) {
261
- printResults();
313
+ if (canUpdateLog) {
314
+ logUpdate.done();
315
+ }
316
+ else {
317
+ log();
262
318
  }
263
- logUpdate.done();
264
319
  // save results
265
320
  if (options.save) {
266
321
  console.log(`Saving results to ${chalk.gray(absToRel(resultsJsonFile))}`);
@@ -9,6 +9,7 @@ import { mainActor } from '../api/actors.js';
9
9
  import { installAll } from './install/install-all.js';
10
10
  import { readVesselConfig } from '../vessel.js';
11
11
  import { template } from './template.js';
12
+ import { kebabCase } from 'change-case';
12
13
  export async function init({ yes = false } = {}) {
13
14
  let configFile = path.join(process.cwd(), 'mops.toml');
14
15
  let exists = existsSync(configFile);
@@ -73,7 +74,7 @@ export async function init({ yes = false } = {}) {
73
74
  type: 'text',
74
75
  name: 'name',
75
76
  message: 'Enter package name:',
76
- initial: '',
77
+ initial: kebabCase(path.basename(process.cwd())),
77
78
  },
78
79
  {
79
80
  type: 'text',
@@ -117,7 +118,7 @@ export async function init({ yes = false } = {}) {
117
118
  },
118
119
  ], promptsConfig);
119
120
  config.package = {
120
- name: (res.name || '').trim(),
121
+ name: kebabCase((res.name || '').trim()),
121
122
  version: '1.0.0',
122
123
  description: (res.description || '').trim(),
123
124
  repository: (res.repository || '').trim(),
@@ -65,8 +65,8 @@ export class Replica {
65
65
  let pocketIcBin = await toolchain.bin('pocket-ic');
66
66
  // eslint-disable-next-line
67
67
  let config = readConfig();
68
- if (config.toolchain?.['pocket-ic'] !== '6.0.0') {
69
- console.error('Current Mops CLI only supports pocket-ic 6.0.0');
68
+ if (config.toolchain?.['pocket-ic'] !== '4.0.0') {
69
+ console.error('Current Mops CLI only supports pocket-ic 4.0.0');
70
70
  process.exit(1);
71
71
  }
72
72
  this.pocketIcServer = await PocketIcServer.start({
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import chalk from 'chalk';
4
4
  import prompts from 'prompts';
5
- import camelCase from 'camelcase';
5
+ import { kebabCase, pascalCase } from 'change-case';
6
6
  import { getRootDir, readConfig } from '../mops.js';
7
7
  import { copyTemplateFileSync } from '../templates.js';
8
8
  export async function template(templateName, options = {}) {
@@ -93,8 +93,8 @@ export async function template(templateName, options = {}) {
93
93
  let data = fs.readFileSync(dest).toString();
94
94
  data = data.replace(/<year>/g, new Date().getFullYear().toString());
95
95
  if (config.package?.name) {
96
- data = data.replace(/<name>/g, config.package.name);
97
- data = data.replace(/<import-name>/g, camelCase(config.package.name, { pascalCase: true }));
96
+ data = data.replace(/<name>/g, kebabCase(config.package.name));
97
+ data = data.replace(/<import-name>/g, pascalCase(config.package.name));
98
98
  }
99
99
  fs.writeFileSync(dest, data);
100
100
  console.log(chalk.green('Created'), path.relative(getRootDir(), 'README.md'));
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "1.4.0-pre.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "bin/mops.js",
@@ -28,20 +28,20 @@
28
28
  "node": ">=18.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@dfinity/agent": "2.2.0",
32
- "@dfinity/candid": "2.2.0",
33
- "@dfinity/identity": "2.2.0",
34
- "@dfinity/identity-secp256k1": "2.2.0",
35
- "@dfinity/principal": "2.2.0",
31
+ "@dfinity/agent": "2.3.0",
32
+ "@dfinity/candid": "2.3.0",
33
+ "@dfinity/identity": "2.3.0",
34
+ "@dfinity/identity-secp256k1": "2.3.0",
35
+ "@dfinity/principal": "2.3.0",
36
36
  "@iarna/toml": "2.2.5",
37
- "@noble/hashes": "1.5.0",
37
+ "@noble/hashes": "1.7.1",
38
38
  "as-table": "1.0.55",
39
39
  "buffer": "6.0.3",
40
40
  "cacheable-request": "12.0.1",
41
- "camelcase": "8.0.0",
42
- "chalk": "5.3.0",
41
+ "chalk": "5.4.1",
42
+ "change-case": "5.4.4",
43
43
  "chokidar": "3.6.0",
44
- "commander": "12.1.0",
44
+ "commander": "13.1.0",
45
45
  "debounce": "2.1.1",
46
46
  "decomp-tarxz": "0.1.1",
47
47
  "decompress": "4.2.1",
@@ -51,25 +51,26 @@
51
51
  "filesize": "10.1.6",
52
52
  "fs-extra": "11.2.0",
53
53
  "get-folder-size": "5.0.0",
54
- "glob": "11.0.0",
54
+ "glob": "11.0.1",
55
55
  "globby": "14.0.2",
56
- "got": "14.4.2",
56
+ "got": "14.4.6",
57
57
  "log-update": "6.1.0",
58
- "markdown-table": "3.0.3",
59
- "mdast-util-from-markdown": "2.0.1",
60
- "mdast-util-to-markdown": "2.1.0",
58
+ "markdown-table": "3.0.4",
59
+ "mdast-util-from-markdown": "2.0.2",
60
+ "mdast-util-to-markdown": "2.1.2",
61
61
  "minimatch": "10.0.1",
62
62
  "ncp": "2.0.0",
63
63
  "node-fetch": "3.3.2",
64
64
  "octokit": "3.1.2",
65
65
  "pem-file": "1.0.1",
66
- "pic-ic": "0.7.0",
66
+ "pic-ic": "0.5.3",
67
67
  "promisify-child-process": "4.1.2",
68
68
  "prompts": "2.4.2",
69
- "semver": "7.6.3",
69
+ "semver": "7.7.1",
70
70
  "stream-to-promise": "3.0.0",
71
71
  "string-width": "7.2.0",
72
- "tar": "7.4.3"
72
+ "tar": "7.4.3",
73
+ "terminal-size": "4.0.0"
73
74
  },
74
75
  "devDependencies": {
75
76
  "@tsconfig/strictest": "2.0.5",
@@ -78,7 +79,7 @@
78
79
  "@types/fs-extra": "11.0.4",
79
80
  "@types/glob": "8.1.0",
80
81
  "@types/ncp": "2.0.8",
81
- "@types/node": "22.7.4",
82
+ "@types/node": "22.13.4",
82
83
  "@types/prompts": "2.4.9",
83
84
  "@types/semver": "7.5.8",
84
85
  "@types/stream-to-promise": "2.2.4",
@@ -86,7 +87,7 @@
86
87
  "bun": "1.1.27",
87
88
  "esbuild": "0.23.1",
88
89
  "eslint": "8.57.0",
89
- "tsx": "4.19.1",
90
- "typescript": "5.6.2"
90
+ "tsx": "4.19.2",
91
+ "typescript": "5.7.3"
91
92
  }
92
93
  }
package/dist/pem.d.ts CHANGED
@@ -2,4 +2,4 @@ import { Buffer } from 'node:buffer';
2
2
  import { Ed25519KeyIdentity } from '@dfinity/identity';
3
3
  import { Secp256k1KeyIdentity } from '@dfinity/identity-secp256k1';
4
4
  export declare function decodeFile(file: string, password?: string): Secp256k1KeyIdentity | Ed25519KeyIdentity;
5
- export declare function encrypt(buffer: Buffer, password: string): Buffer;
5
+ export declare function encrypt(buffer: Buffer, password: string): Buffer<ArrayBuffer>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "1.4.0-pre.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "dist/bin/mops.js",
@@ -44,20 +44,20 @@
44
44
  "esbuild": "esbuild"
45
45
  },
46
46
  "dependencies": {
47
- "@dfinity/agent": "2.2.0",
48
- "@dfinity/candid": "2.2.0",
49
- "@dfinity/identity": "2.2.0",
50
- "@dfinity/identity-secp256k1": "2.2.0",
51
- "@dfinity/principal": "2.2.0",
47
+ "@dfinity/agent": "2.3.0",
48
+ "@dfinity/candid": "2.3.0",
49
+ "@dfinity/identity": "2.3.0",
50
+ "@dfinity/identity-secp256k1": "2.3.0",
51
+ "@dfinity/principal": "2.3.0",
52
52
  "@iarna/toml": "2.2.5",
53
- "@noble/hashes": "1.5.0",
53
+ "@noble/hashes": "1.7.1",
54
54
  "as-table": "1.0.55",
55
55
  "buffer": "6.0.3",
56
56
  "cacheable-request": "12.0.1",
57
- "camelcase": "8.0.0",
58
- "chalk": "5.3.0",
57
+ "chalk": "5.4.1",
58
+ "change-case": "5.4.4",
59
59
  "chokidar": "3.6.0",
60
- "commander": "12.1.0",
60
+ "commander": "13.1.0",
61
61
  "debounce": "2.1.1",
62
62
  "decomp-tarxz": "0.1.1",
63
63
  "decompress": "4.2.1",
@@ -67,25 +67,26 @@
67
67
  "filesize": "10.1.6",
68
68
  "fs-extra": "11.2.0",
69
69
  "get-folder-size": "5.0.0",
70
- "glob": "11.0.0",
70
+ "glob": "11.0.1",
71
71
  "globby": "14.0.2",
72
- "got": "14.4.2",
72
+ "got": "14.4.6",
73
73
  "log-update": "6.1.0",
74
- "markdown-table": "3.0.3",
75
- "mdast-util-from-markdown": "2.0.1",
76
- "mdast-util-to-markdown": "2.1.0",
74
+ "markdown-table": "3.0.4",
75
+ "mdast-util-from-markdown": "2.0.2",
76
+ "mdast-util-to-markdown": "2.1.2",
77
77
  "minimatch": "10.0.1",
78
78
  "ncp": "2.0.0",
79
79
  "node-fetch": "3.3.2",
80
80
  "octokit": "3.1.2",
81
81
  "pem-file": "1.0.1",
82
- "pic-ic": "0.7.0",
82
+ "pic-ic": "0.5.3",
83
83
  "promisify-child-process": "4.1.2",
84
84
  "prompts": "2.4.2",
85
- "semver": "7.6.3",
85
+ "semver": "7.7.1",
86
86
  "stream-to-promise": "3.0.0",
87
87
  "string-width": "7.2.0",
88
- "tar": "7.4.3"
88
+ "tar": "7.4.3",
89
+ "terminal-size": "4.0.0"
89
90
  },
90
91
  "devDependencies": {
91
92
  "@tsconfig/strictest": "2.0.5",
@@ -94,7 +95,7 @@
94
95
  "@types/fs-extra": "11.0.4",
95
96
  "@types/glob": "8.1.0",
96
97
  "@types/ncp": "2.0.8",
97
- "@types/node": "22.7.4",
98
+ "@types/node": "22.13.4",
98
99
  "@types/prompts": "2.4.9",
99
100
  "@types/semver": "7.5.8",
100
101
  "@types/stream-to-promise": "2.2.4",
@@ -102,7 +103,7 @@
102
103
  "bun": "1.1.27",
103
104
  "esbuild": "0.23.1",
104
105
  "eslint": "8.57.0",
105
- "tsx": "4.19.1",
106
- "typescript": "5.6.2"
106
+ "tsx": "4.19.2",
107
+ "typescript": "5.7.3"
107
108
  }
108
109
  }