ic-mops 2.3.2 → 2.5.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
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Next
4
4
 
5
+ ## 2.5.0
6
+ - Add support for `MOPS_REGISTRY_HOST` and `MOPS_REGISTRY_CANISTER_ID` environment variables for custom registry endpoints
7
+ - Fix `mops build` crashing with `__wbindgen_malloc` error in bundled CLI distribution
8
+ - Fix `parallel()` swallowing errors from concurrent tasks (e.g. `mops publish` uploads), which could hang or leave failures unreported
9
+
10
+ ## 2.4.0
11
+ - Support `[build].outputDir` config in `mops.toml` for custom build output directory
12
+ - Fix `mops build --output` CLI option being silently ignored
13
+ - Warn when canister `args` contain flags managed by `mops build` (e.g. `-o`, `-c`, `--idl`)
14
+ - Support pocket-ic versions beyond 9.x.x (fixes #410)
15
+
5
16
  ## 2.3.2
6
17
  - Fix `mops check`, `mops build`, and `mops check-stable` failing to find canister entrypoints when run from a subdirectory
7
18
 
package/RELEASE.md CHANGED
@@ -1,20 +1,8 @@
1
1
  # Mops CLI Release
2
2
 
3
- ## Prerequisites
3
+ ## 1. Update changelog
4
4
 
5
- ### Docker
6
-
7
- Docker (or OrbStack) must be installed and running. The on-chain release step builds the CLI inside a Docker container (`zenvoich/mops-builder:1.1.0`) for reproducibility.
8
-
9
- ### dfx
10
-
11
- `dfx` must be installed with the `mops` identity configured (see [Adding the `mops` identity to dfx](#adding-the-mops-identity-to-dfx)).
12
-
13
- ## Release Steps
14
-
15
- ### 1. Update changelog
16
-
17
- Move items from the `## Next` section in `CHANGELOG.md` into a new version heading:
5
+ Move items from `## Next` in `CHANGELOG.md` into a new version heading:
18
6
 
19
7
  ```markdown
20
8
  ## Next
@@ -24,16 +12,16 @@ Move items from the `## Next` section in `CHANGELOG.md` into a new version headi
24
12
  - Change 2
25
13
  ```
26
14
 
27
- The heading must contain the exact version string — the release workflow parses it to extract release notes for the GitHub Release.
15
+ The heading must match the exact version string — the release workflow parses it to extract release notes.
28
16
 
29
- ### 2. Bump version
17
+ ## 2. Bump version
30
18
 
31
19
  ```bash
32
20
  cd cli
33
- npm version minor --no-git-tag-version # or: patch / major
21
+ npm version patch --no-git-tag-version # or: minor / major
34
22
  ```
35
23
 
36
- ### 3. Create a release branch and PR
24
+ ## 3. Create a release PR
37
25
 
38
26
  ```bash
39
27
  git checkout -b <username>/release-X.Y.Z
@@ -43,11 +31,9 @@ git push -u origin <username>/release-X.Y.Z
43
31
  gh pr create --title "release: CLI vX.Y.Z" --body "..."
44
32
  ```
45
33
 
46
- Wait for CI to pass, then merge the PR.
47
-
48
- ### 4. Tag and push
34
+ Wait for CI to pass, then merge.
49
35
 
50
- After the PR is merged to `main`:
36
+ ## 4. Tag and push
51
37
 
52
38
  ```bash
53
39
  git checkout main && git pull
@@ -55,111 +41,20 @@ git tag cli-vX.Y.Z
55
41
  git push origin cli-vX.Y.Z
56
42
  ```
57
43
 
58
- This triggers the [`release.yml`](../.github/workflows/release.yml) workflow which automatically:
59
- 1. Validates the tag is on `main` and version matches `package.json`
60
- 2. Builds the CLI tarball in Docker (reproducible build)
61
- 3. Computes and reports the SHA256 hash (visible in the workflow Step Summary)
62
- 4. Publishes to npm via OIDC trusted publishing
63
- 5. Creates a GitHub Release with the tarball attached and changelog as release notes
64
-
65
- Monitor the workflow run at [Actions → Release CLI](https://github.com/caffeinelabs/mops/actions/workflows/release.yml).
66
-
67
- ### 5. Prepare on-chain release
68
-
69
- Run from the **repo root** (not `cli/`), with Docker running:
70
-
71
- ```bash
72
- npm run release-cli
73
- ```
74
-
75
- This runs `cli/release-cli.ts`, which:
76
- 1. Calls `./build.sh` — full Docker build with the real version from `cli/package.json`
77
- 2. Extracts release notes from `CHANGELOG.md` for that version
78
- 3. Computes SHA256 of `bundle/cli.tgz`
79
- 4. Copies the tarball to `cli-releases/versions/<version>.tgz`
80
- 5. Creates tag copies: `latest.tgz` and `<major>.tgz`
81
- 6. Updates `cli-releases/tags/latest` to the new version
82
- 7. Updates `cli-releases/releases.json` with metadata (timestamp, size, hash, commit hash, download URL, release notes)
83
-
84
- ### 6. Deploy the canister
44
+ This triggers the [`release.yml`](../.github/workflows/release.yml) workflow which builds, publishes to npm, creates a GitHub Release, deploys canisters (`cli.mops.one` and `docs.mops.one`), and opens a PR with on-chain release artifacts.
85
45
 
86
- ```bash
87
- dfx deploy --network ic --no-wallet cli --identity mops
88
- ```
46
+ Monitor at [Actions → Release CLI](https://github.com/caffeinelabs/mops/actions/workflows/release.yml).
89
47
 
90
- This deploys the `cli-releases` canister (serving `cli.mops.one`) to the Internet Computer mainnet.
48
+ ## 5. Merge artifacts PR
91
49
 
92
- ### 7. Deploy the docs canister
93
-
94
- ```bash
95
- dfx deploy --network ic --no-wallet docs --identity mops
96
- ```
97
-
98
- This builds the Docusaurus site (`docs/`) and deploys the `docs` assets canister (serving `docs.mops.one`). Docs are not auto-deployed, so this step ensures any documentation changes from the release are published.
99
-
100
- ### 8. Commit and push release artifacts
101
-
102
- Step 5 generates files in `cli-releases/` that must be committed and pushed:
103
-
104
- ```bash
105
- git add cli-releases/
106
- git commit -m "cli-releases: v<version> artifacts"
107
- ```
108
-
109
- Since direct pushes to `main` are not allowed, create a branch and PR:
110
-
111
- ```bash
112
- git checkout -b <username>/release-X.Y.Z-artifacts
113
- git push -u origin <username>/release-X.Y.Z-artifacts
114
- gh pr create --title "cli-releases: vX.Y.Z artifacts" --body "Release artifacts generated by \`npm run release-cli\` for CLI vX.Y.Z."
115
- ```
116
-
117
- Merge this PR after approval.
50
+ After the workflow completes, merge the `cli-releases: vX.Y.Z artifacts` PR.
118
51
 
119
52
  ## Verify build
120
53
 
121
- Anyone can verify a released version by rebuilding from source. The SHA256 hash and verification instructions are included in each [GitHub Release](https://github.com/caffeinelabs/mops/releases).
54
+ Anyone can verify a released version by rebuilding from source. Instructions are included in each [GitHub Release](https://github.com/caffeinelabs/mops/releases).
122
55
 
123
56
  ```bash
124
57
  cd cli
125
58
  docker build . --build-arg COMMIT_HASH=<commit_hash> --build-arg MOPS_VERSION=<mops_version> -t mops
126
59
  docker run --rm --env SHASUM=<build_hash> mops
127
60
  ```
128
-
129
- ## Adding the `mops` identity to dfx
130
-
131
- Check if the identity already exists:
132
- ```bash
133
- dfx identity list
134
- ```
135
-
136
- If `mops` appears, verify it's the correct one:
137
- ```bash
138
- dfx identity get-principal --identity mops
139
- ```
140
-
141
- If it doesn't exist, import it from the PEM file stored in Bitwarden (`Mops identity (canisters and packages)`):
142
-
143
- 1. Save the PEM key to a temporary file:
144
- ```bash
145
- cat > /tmp/mops-identity.pem << 'EOF'
146
- -----BEGIN EC PRIVATE KEY-----
147
- <paste key from Bitwarden>
148
- -----END EC PRIVATE KEY-----
149
- EOF
150
- ```
151
-
152
- 2. Import into dfx:
153
- ```bash
154
- dfx identity import mops /tmp/mops-identity.pem
155
- ```
156
-
157
- 3. Delete the temporary file:
158
- ```bash
159
- rm /tmp/mops-identity.pem
160
- ```
161
-
162
- 4. Verify:
163
- ```bash
164
- dfx identity get-principal --identity mops
165
- ```
package/api/network.ts CHANGED
@@ -3,20 +3,28 @@ export function getNetwork() {
3
3
  }
4
4
 
5
5
  export function getEndpoint(network: string) {
6
+ let endpoint: { host: string; canisterId: string };
6
7
  if (network === "staging") {
7
- return {
8
+ endpoint = {
8
9
  host: "https://icp-api.io",
9
10
  canisterId: "2d2zu-vaaaa-aaaak-qb6pq-cai",
10
11
  };
11
12
  } else if (network === "ic") {
12
- return {
13
+ endpoint = {
13
14
  host: "https://icp-api.io",
14
15
  canisterId: "oknww-riaaa-aaaam-qaf6a-cai",
15
16
  };
16
17
  } else {
17
- return {
18
+ endpoint = {
18
19
  host: "http://127.0.0.1:4943",
19
20
  canisterId: "2d2zu-vaaaa-aaaak-qb6pq-cai",
20
21
  };
21
22
  }
23
+
24
+ const hostOverride = process.env["MOPS_REGISTRY_HOST"]?.trim();
25
+ const canisterOverride = process.env["MOPS_REGISTRY_CANISTER_ID"]?.trim();
26
+ return {
27
+ host: hostOverride || endpoint.host,
28
+ canisterId: canisterOverride || endpoint.canisterId,
29
+ };
22
30
  }
package/bundle/cli.tgz CHANGED
Binary file
package/cli.ts CHANGED
@@ -301,11 +301,7 @@ program
301
301
  .command("build [canisters...]")
302
302
  .description("Build a canister")
303
303
  .addOption(new Option("--verbose", "Verbose console output"))
304
- .addOption(
305
- new Option("--output, -o <output>", "Output directory").default(
306
- DEFAULT_BUILD_OUTPUT_DIR,
307
- ),
308
- )
304
+ .addOption(new Option("--output, -o <output>", "Output directory"))
309
305
  .allowUnknownOption(true) // TODO: restrict unknown before "--"
310
306
  .action(async (canisters, options) => {
311
307
  checkConfigFile(true);
@@ -317,6 +313,7 @@ program
317
313
  });
318
314
  await build(args.length ? args : undefined, {
319
315
  ...options,
316
+ outputDir: options.output,
320
317
  extraArgs,
321
318
  });
322
319
  });
@@ -3,12 +3,13 @@ import { execSync } from "node:child_process";
3
3
  import path from "node:path";
4
4
  import fs from "node:fs";
5
5
  import { execaCommand } from "execa";
6
- import { PocketIc, PocketIcServer } from "pic-ic";
6
+ import { getRootDir } from "../mops.js";
7
7
  import {
8
- PocketIc as PocketIcMops,
9
- PocketIcServer as PocketIcServerMops,
10
- } from "pic-js-mops";
11
- import { getRootDir, readConfig } from "../mops.js";
8
+ type AnyPocketIcServer,
9
+ type AnyPocketIc,
10
+ type AnySetupCanister,
11
+ startPocketIc,
12
+ } from "../helpers/pocket-ic-client.js";
12
13
  import { createActor, idlFactory } from "../declarations/bench/index.js";
13
14
  import { toolchain } from "./toolchain/index.js";
14
15
  import { getDfxVersion } from "../helpers/get-dfx-version.js";
@@ -18,8 +19,8 @@ export class BenchReplica {
18
19
  verbose = false;
19
20
  canisters: Record<string, { cwd: string; canisterId: string; actor: any }> =
20
21
  {};
21
- pocketIcServer?: PocketIcServer | PocketIcServerMops;
22
- pocketIc?: PocketIc | PocketIcMops;
22
+ pocketIcServer?: AnyPocketIcServer;
23
+ pocketIc?: AnyPocketIc;
23
24
 
24
25
  constructor(type: "dfx" | "pocket-ic" | "dfx-pocket-ic", verbose = false) {
25
26
  this.type = type;
@@ -49,30 +50,10 @@ export class BenchReplica {
49
50
  );
50
51
  } else {
51
52
  let pocketIcBin = await toolchain.bin("pocket-ic");
52
- let config = readConfig();
53
- if (
54
- config.toolchain?.["pocket-ic"] !== "4.0.0" &&
55
- !config.toolchain?.["pocket-ic"]?.startsWith("9.")
56
- ) {
57
- console.error(
58
- "Current Mops CLI only supports pocket-ic 9.x.x and 4.0.0",
59
- );
60
- process.exit(1);
61
- }
62
- // pocket-ic 9.x.x
63
- if (config.toolchain?.["pocket-ic"]?.startsWith("9.")) {
64
- this.pocketIcServer = await PocketIcServerMops.start({
65
- binPath: pocketIcBin,
66
- });
67
- this.pocketIc = await PocketIcMops.create(this.pocketIcServer.getUrl());
68
- }
69
- // pocket-ic 4.0.0
70
- else {
71
- this.pocketIcServer = await PocketIcServer.start({
72
- binPath: pocketIcBin,
73
- });
74
- this.pocketIc = await PocketIc.create(this.pocketIcServer.getUrl());
75
- }
53
+
54
+ let pic = await startPocketIc({ binPath: pocketIcBin });
55
+ this.pocketIcServer = pic.server;
56
+ this.pocketIc = pic.client;
76
57
  }
77
58
  }
78
59
 
@@ -105,10 +86,8 @@ export class BenchReplica {
105
86
  });
106
87
  this.canisters[name] = { cwd, canisterId, actor };
107
88
  } else if (this.pocketIc) {
108
- type PocketIcSetupCanister = PocketIcMops["setupCanister"] &
109
- PocketIc["setupCanister"];
110
89
  let { canisterId, actor } = await (
111
- this.pocketIc.setupCanister as PocketIcSetupCanister
90
+ this.pocketIc.setupCanister as AnySetupCanister
112
91
  )({ idlFactory, wasm });
113
92
  this.canisters[name] = {
114
93
  cwd,
package/commands/build.ts CHANGED
@@ -6,6 +6,7 @@ import { join } from "node:path";
6
6
  import { cliError } from "../error.js";
7
7
  import { isCandidCompatible } from "../helpers/is-candid-compatible.js";
8
8
  import { resolveCanisterConfigs } from "../helpers/resolve-canisters.js";
9
+ import { CanisterConfig, Config } from "../types.js";
9
10
  import { CustomSection, getWasmBindings } from "../wasm.js";
10
11
  import { getGlobalMocArgs, readConfig, resolveConfigPath } from "../mops.js";
11
12
  import { sourcesArgs } from "./sources.js";
@@ -27,9 +28,13 @@ export async function build(
27
28
  cliError("No canisters specified to build");
28
29
  }
29
30
 
30
- let outputDir = options.outputDir ?? DEFAULT_BUILD_OUTPUT_DIR;
31
- let mocPath = await toolchain.bin("moc", { fallback: true });
32
31
  let config = readConfig();
32
+ let configOutputDir = config.build?.outputDir
33
+ ? resolveConfigPath(config.build.outputDir)
34
+ : undefined;
35
+ let outputDir =
36
+ options.outputDir ?? configOutputDir ?? DEFAULT_BUILD_OUTPUT_DIR;
37
+ let mocPath = await toolchain.bin("moc", { fallback: true });
33
38
  let canisters = resolveCanisterConfigs(config);
34
39
  if (!Object.keys(canisters).length) {
35
40
  cliError(`No Motoko canisters found in mops.toml configuration`);
@@ -78,23 +83,10 @@ export async function build(
78
83
  ...(await sourcesArgs()).flat(),
79
84
  ...getGlobalMocArgs(config),
80
85
  ];
81
- if (config.build?.args) {
82
- if (typeof config.build.args === "string") {
83
- cliError(
84
- `[build] config 'args' should be an array of strings in mops.toml config file`,
85
- );
86
- }
87
- args.push(...config.build.args);
88
- }
89
- if (canister.args) {
90
- if (typeof canister.args === "string") {
91
- cliError(
92
- `Canister config 'args' should be an array of strings for canister ${canisterName}`,
93
- );
94
- }
95
- args.push(...canister.args);
96
- }
97
- args.push(...(options.extraArgs ?? []));
86
+ args.push(
87
+ ...collectExtraArgs(config, canister, canisterName, options.extraArgs),
88
+ );
89
+
98
90
  const isPublicCandid = true; // always true for now to reduce corner cases
99
91
  const candidVisibility = isPublicCandid ? "icp:public" : "icp:private";
100
92
  if (isPublicCandid) {
@@ -196,3 +188,54 @@ export async function build(
196
188
  ),
197
189
  );
198
190
  }
191
+
192
+ const managedFlags: Record<string, string> = {
193
+ "-o": "use [build].outputDir in mops.toml or --output flag instead",
194
+ "-c": "this flag is always set by mops build",
195
+ "--idl": "this flag is always set by mops build",
196
+ "--public-metadata": "this flag is managed by mops build",
197
+ };
198
+
199
+ function collectExtraArgs(
200
+ config: Config,
201
+ canister: CanisterConfig,
202
+ canisterName: string,
203
+ extraArgs?: string[],
204
+ ): string[] {
205
+ const args: string[] = [];
206
+
207
+ if (config.build?.args) {
208
+ if (typeof config.build.args === "string") {
209
+ cliError(
210
+ `[build] config 'args' should be an array of strings in mops.toml config file`,
211
+ );
212
+ }
213
+ args.push(...config.build.args);
214
+ }
215
+ if (canister.args) {
216
+ if (typeof canister.args === "string") {
217
+ cliError(
218
+ `Canister config 'args' should be an array of strings for canister ${canisterName}`,
219
+ );
220
+ }
221
+ args.push(...canister.args);
222
+ }
223
+ if (extraArgs) {
224
+ args.push(...extraArgs);
225
+ }
226
+
227
+ const warned = new Set<string>();
228
+ for (const arg of args) {
229
+ const hint = managedFlags[arg];
230
+ if (hint && !warned.has(arg)) {
231
+ warned.add(arg);
232
+ console.warn(
233
+ chalk.yellow(
234
+ `Warning: '${arg}' in args for canister ${canisterName} may conflict with mops build — ${hint}`,
235
+ ),
236
+ );
237
+ }
238
+ }
239
+
240
+ return args;
241
+ }
@@ -11,14 +11,14 @@ import { spawn as spawnAsync } from "promisify-child-process";
11
11
 
12
12
  import { IDL } from "@icp-sdk/core/candid";
13
13
  import { Actor, HttpAgent } from "@icp-sdk/core/agent";
14
- import { PocketIc, PocketIcServer } from "pic-ic";
15
- import {
16
- PocketIc as PocketIcMops,
17
- PocketIcServer as PocketIcServerMops,
18
- } from "pic-js-mops";
19
14
  import chalk from "chalk";
20
15
 
21
- import { readConfig } from "../mops.js";
16
+ import {
17
+ type AnyPocketIcServer,
18
+ type AnyPocketIc,
19
+ type AnySetupCanister,
20
+ startPocketIc,
21
+ } from "../helpers/pocket-ic-client.js";
22
22
  import { toolchain } from "./toolchain/index.js";
23
23
  import { getDfxVersion } from "../helpers/get-dfx-version.js";
24
24
 
@@ -36,8 +36,8 @@ export class Replica {
36
36
  string,
37
37
  { cwd: string; canisterId: string; actor: any; stream: PassThrough }
38
38
  > = {};
39
- pocketIcServer?: PocketIcServer | PocketIcServerMops;
40
- pocketIc?: PocketIc | PocketIcMops;
39
+ pocketIcServer?: AnyPocketIcServer;
40
+ pocketIc?: AnyPocketIc;
41
41
  dfxProcess?: ChildProcessWithoutNullStreams;
42
42
  dir: string = ""; // absolute path (/.../.mops/.test/)
43
43
  ttl = 60;
@@ -114,37 +114,14 @@ export class Replica {
114
114
  } else {
115
115
  let pocketIcBin = await toolchain.bin("pocket-ic");
116
116
 
117
- let config = readConfig();
118
- if (
119
- config.toolchain?.["pocket-ic"] !== "4.0.0" &&
120
- !config.toolchain?.["pocket-ic"]?.startsWith("9.")
121
- ) {
122
- console.error(
123
- "Current Mops CLI only supports pocket-ic 9.x.x and 4.0.0",
124
- );
125
- process.exit(1);
126
- }
127
-
128
- // pocket-ic 9.x.x
129
- if (config.toolchain?.["pocket-ic"]?.startsWith("9.")) {
130
- this.pocketIcServer = await PocketIcServerMops.start({
131
- showRuntimeLogs: false,
132
- showCanisterLogs: false,
133
- binPath: pocketIcBin,
134
- ttl: this.ttl,
135
- });
136
- this.pocketIc = await PocketIcMops.create(this.pocketIcServer.getUrl());
137
- }
138
- // pocket-ic 4.0.0
139
- else {
140
- this.pocketIcServer = await PocketIcServer.start({
141
- showRuntimeLogs: false,
142
- showCanisterLogs: false,
143
- binPath: pocketIcBin,
144
- ttl: this.ttl,
145
- });
146
- this.pocketIc = await PocketIc.create(this.pocketIcServer.getUrl());
147
- }
117
+ let pic = await startPocketIc({
118
+ binPath: pocketIcBin,
119
+ showRuntimeLogs: false,
120
+ showCanisterLogs: false,
121
+ ttl: this.ttl,
122
+ });
123
+ this.pocketIcServer = pic.server;
124
+ this.pocketIc = pic.client;
148
125
 
149
126
  // process canister logs
150
127
  this._attachCanisterLogHandler(
@@ -305,10 +282,8 @@ export class Replica {
305
282
  stream: new PassThrough(),
306
283
  };
307
284
  } else if (this.pocketIc) {
308
- type PocketIcSetupCanister = PocketIcMops["setupCanister"] &
309
- PocketIc["setupCanister"];
310
285
  let { canisterId, actor } = await (
311
- this.pocketIc.setupCanister as PocketIcSetupCanister
286
+ this.pocketIc.setupCanister as AnySetupCanister
312
287
  )({
313
288
  wasm,
314
289
  idlFactory,
@@ -2,22 +2,29 @@ export function getNetwork() {
2
2
  return globalThis.MOPS_NETWORK || "ic";
3
3
  }
4
4
  export function getEndpoint(network) {
5
+ let endpoint;
5
6
  if (network === "staging") {
6
- return {
7
+ endpoint = {
7
8
  host: "https://icp-api.io",
8
9
  canisterId: "2d2zu-vaaaa-aaaak-qb6pq-cai",
9
10
  };
10
11
  }
11
12
  else if (network === "ic") {
12
- return {
13
+ endpoint = {
13
14
  host: "https://icp-api.io",
14
15
  canisterId: "oknww-riaaa-aaaam-qaf6a-cai",
15
16
  };
16
17
  }
17
18
  else {
18
- return {
19
+ endpoint = {
19
20
  host: "http://127.0.0.1:4943",
20
21
  canisterId: "2d2zu-vaaaa-aaaak-qb6pq-cai",
21
22
  };
22
23
  }
24
+ const hostOverride = process.env["MOPS_REGISTRY_HOST"]?.trim();
25
+ const canisterOverride = process.env["MOPS_REGISTRY_CANISTER_ID"]?.trim();
26
+ return {
27
+ host: hostOverride || endpoint.host,
28
+ canisterId: canisterOverride || endpoint.canisterId,
29
+ };
23
30
  }
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { getNetwork } from "./api/network.js";
7
7
  import { cacheSize, cleanCache, show } from "./cache.js";
8
8
  import { add } from "./commands/add.js";
9
9
  import { bench } from "./commands/bench.js";
10
- import { build, DEFAULT_BUILD_OUTPUT_DIR } from "./commands/build.js";
10
+ import { build } from "./commands/build.js";
11
11
  import { bump } from "./commands/bump.js";
12
12
  import { check } from "./commands/check.js";
13
13
  import { checkCandid } from "./commands/check-candid.js";
@@ -236,7 +236,7 @@ program
236
236
  .command("build [canisters...]")
237
237
  .description("Build a canister")
238
238
  .addOption(new Option("--verbose", "Verbose console output"))
239
- .addOption(new Option("--output, -o <output>", "Output directory").default(DEFAULT_BUILD_OUTPUT_DIR))
239
+ .addOption(new Option("--output, -o <output>", "Output directory"))
240
240
  .allowUnknownOption(true) // TODO: restrict unknown before "--"
241
241
  .action(async (canisters, options) => {
242
242
  checkConfigFile(true);
@@ -248,6 +248,7 @@ program
248
248
  });
249
249
  await build(args.length ? args : undefined, {
250
250
  ...options,
251
+ outputDir: options.output,
251
252
  extraArgs,
252
253
  });
253
254
  });
@@ -1,5 +1,4 @@
1
- import { PocketIc, PocketIcServer } from "pic-ic";
2
- import { PocketIc as PocketIcMops, PocketIcServer as PocketIcServerMops } from "pic-js-mops";
1
+ import { type AnyPocketIcServer, type AnyPocketIc } from "../helpers/pocket-ic-client.js";
3
2
  export declare class BenchReplica {
4
3
  type: "dfx" | "pocket-ic" | "dfx-pocket-ic";
5
4
  verbose: boolean;
@@ -8,8 +7,8 @@ export declare class BenchReplica {
8
7
  canisterId: string;
9
8
  actor: any;
10
9
  }>;
11
- pocketIcServer?: PocketIcServer | PocketIcServerMops;
12
- pocketIc?: PocketIc | PocketIcMops;
10
+ pocketIcServer?: AnyPocketIcServer;
11
+ pocketIc?: AnyPocketIc;
13
12
  constructor(type: "dfx" | "pocket-ic" | "dfx-pocket-ic", verbose?: boolean);
14
13
  start({ silent }?: {
15
14
  silent?: boolean | undefined;
@@ -3,9 +3,8 @@ import { execSync } from "node:child_process";
3
3
  import path from "node:path";
4
4
  import fs from "node:fs";
5
5
  import { execaCommand } from "execa";
6
- import { PocketIc, PocketIcServer } from "pic-ic";
7
- import { PocketIc as PocketIcMops, PocketIcServer as PocketIcServerMops, } from "pic-js-mops";
8
- import { getRootDir, readConfig } from "../mops.js";
6
+ import { getRootDir } from "../mops.js";
7
+ import { startPocketIc, } from "../helpers/pocket-ic-client.js";
9
8
  import { createActor, idlFactory } from "../declarations/bench/index.js";
10
9
  import { toolchain } from "./toolchain/index.js";
11
10
  import { getDfxVersion } from "../helpers/get-dfx-version.js";
@@ -36,26 +35,9 @@ export class BenchReplica {
36
35
  }
37
36
  else {
38
37
  let pocketIcBin = await toolchain.bin("pocket-ic");
39
- let config = readConfig();
40
- if (config.toolchain?.["pocket-ic"] !== "4.0.0" &&
41
- !config.toolchain?.["pocket-ic"]?.startsWith("9.")) {
42
- console.error("Current Mops CLI only supports pocket-ic 9.x.x and 4.0.0");
43
- process.exit(1);
44
- }
45
- // pocket-ic 9.x.x
46
- if (config.toolchain?.["pocket-ic"]?.startsWith("9.")) {
47
- this.pocketIcServer = await PocketIcServerMops.start({
48
- binPath: pocketIcBin,
49
- });
50
- this.pocketIc = await PocketIcMops.create(this.pocketIcServer.getUrl());
51
- }
52
- // pocket-ic 4.0.0
53
- else {
54
- this.pocketIcServer = await PocketIcServer.start({
55
- binPath: pocketIcBin,
56
- });
57
- this.pocketIc = await PocketIc.create(this.pocketIcServer.getUrl());
58
- }
38
+ let pic = await startPocketIc({ binPath: pocketIcBin });
39
+ this.pocketIcServer = pic.server;
40
+ this.pocketIc = pic.client;
59
41
  }
60
42
  }
61
43
  async stop() {