Conversation
Bug fixes:
- Fix path splitting on spaces in test, watch error-checker, and warning-checker
(use sourcesArgs().flat() instead of sources().join(" ").split(" "))
- Fix compareVersions silently treating short versions as equal (parseInt || 0)
- Fix sync incorrectly reporting version-pinned deps as missing/unused
- Forward --lock option from update command to add() calls
- Add error handling to getGithubCommit (check res.ok and json.sha)
- Fix installFromGithub using process.exit(1) instead of returning false
- Remove dead unreachable code in build.ts canister name validation
- Add try/catch around JSON.parse in readLockFile with actionable error message
- Fix sources.ts path resolution when cwd differs from process.cwd()
- Warn and return false for deps with no version, repo, or path
- Harden integrity check prefix matching (startsWith(packageId + "/"))
- Pass dep.repo to getTransitiveDependenciesOf in remove.ts
Code quality:
- Rename puiblishingId typo to publishingId in publish.ts
- Fix loose equality (== to ===) in build.ts
- Use path.join instead of string concatenation in resolve-packages.ts and integrity.ts
- Escape version string in find-changelog-entry.ts regex
- Avoid in-place array mutation with [...vers].reverse()
Documentation:
- Fix typos: "Initalize" -> "Initialize", "conflics" -> "conflicts"
- Remove invalid JSON comment in format docs
- Split duplicate moc keys into separate examples in toolchain docs
- Document missing mops.toml [package] fields: baseDir, readme, dfx
Made-with: Cursor
- add.ts: check installFromGithub return value before writing to config - update.ts: wrap getGithubCommit in try/catch to handle API failures gracefully - vessel.ts: remove duplicate error log (downloadFromGithub already logs) - CHANGELOG.md: add entries for all user-facing fixes Made-with: Cursor
Benchmark Resultsbench/1-buffer-vector-add.bench.mo
|
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Buffer | 9_557 |
5_687_594 |
525_783_888 |
| Vector | 13_525 |
4_378_612 |
417_864_498 |
Heap
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Buffer | 272 B |
272 B |
272 B |
| Vector | 272 B |
272 B |
272 B |
Garbage Collection
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Buffer | 1.09 KiB |
143.28 KiB |
12.02 MiB |
| Vector | 1.09 KiB |
45.65 KiB |
3.86 MiB |
bench/2-vector-buffer-add.bench.mo $({\color{green}-10.02\%})$
Add
Add items one-by-one
Instructions:
Heap:
Stable Memory:
Garbage Collection:
Instructions
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Vector | 13_525 |
4_378_966 |
417_886_092 |
| Buffer | 9_557 |
5_686_886 |
525_781_056 |
Heap
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Vector | 272 B |
272 B |
272 B |
| Buffer | 272 B |
272 B |
272 B |
Garbage Collection
| 10 | 10000 | 1000000 | |
|---|---|---|---|
| Vector | 1.09 KiB |
45.65 KiB |
3.86 MiB |
| Buffer | 1.09 KiB |
143.28 KiB |
12.02 MiB |
bench/array.bench.mo $({\color{green}-17.47\%})$
Array
arr arr
Instructions:
Heap:
Stable Memory:
Garbage Collection:
Instructions
| 100k x1 | reset1 | 100k x3 | reset2 | 100k x4 | reset3 | |
|---|---|---|---|---|---|---|
| Array | 13_502_096 |
3_335 |
27_003_270 |
3_809 |
54_004_127 |
4_283 |
Heap
| 100k x1 | reset1 | 100k x3 | reset2 | 100k x4 | reset3 | |
|---|---|---|---|---|---|---|
| Array | 390.9 KiB |
-390.37 KiB |
390.9 KiB |
-390.37 KiB |
390.9 KiB |
-390.37 KiB |
Garbage Collection
| 100k x1 | reset1 | 100k x3 | reset2 | 100k x4 | reset3 | |
|---|---|---|---|---|---|---|
| Array | 360 B |
390.97 KiB |
391 KiB |
390.97 KiB |
1.14 MiB |
390.97 KiB |
bench/prng.bench.mo $({\color{gray}0\%})$
Prng
Benchmark N next calls for different PRNGs
Instructions:
Heap:
Stable Memory:
Garbage Collection:
Instructions
| 10 | 100 | 1000 | 10000 | |
|---|---|---|---|---|
| Seiran128 | 1_694 | 15_194 | 150_194 | 1_500_194 |
| SFC64 | 2_802 | 28_962 | 288_557 | 2_882_655 |
| SFC32 | 2_383 | 23_825 | 237_026 | 2_379_333 |
Heap
| 10 | 100 | 1000 | 10000 | |
|---|---|---|---|---|
| Seiran128 | 272 B | 272 B | 272 B | 272 B |
| SFC64 | 308 B | 272 B | 272 B | 272 B |
| SFC32 | 280 B | 280 B | 272 B | 272 B |
Garbage Collection
| 10 | 100 | 1000 | 10000 | |
|---|---|---|---|---|
| Seiran128 | 296 B | 296 B | 296 B | 296 B |
| SFC64 | 536 B | 4.98 KiB | 47.16 KiB | 469.04 KiB |
| SFC32 | 376 B | 1.78 KiB | 15.39 KiB | 156.11 KiB |
bench/removeLast.bench.mo $({\color{green}-10.90\%})$
Remove items using removeLast
Vector and buffer are initialized with 100k items and then 70k items are removed one-by-one.
Instructions:
Heap:
Stable Memory:
Garbage Collection:
Instructions
| remove 70k | |
|---|---|
| Vector | 27_707_716 |
| Buffer | 29_236_977 |
Heap
| remove 70k | |
|---|---|
| Vector | -136.8 KiB |
| Buffer | -269.76 KiB |
Garbage Collection
| remove 70k | |
|---|---|
| Vector | 139.45 KiB |
| Buffer | 540.43 KiB |
bench/stable-memory.bench.mo $({\color{green}-134.03\%})$
Stable Memory and Region
Grow Region and store blobs in it
Instructions:
Heap:
Stable Memory:
Garbage Collection:
Instructions
| Region (fill 1/100) | Region (fill 1/50) | StableMemory | |
|---|---|---|---|
| 10 pages | 2_627_029 |
10_496_318 |
2_693 |
| 100 pages | 52_466_721 |
104_914_650 |
2_698 |
| 256 pages | 134_274_022 |
268_575_191 |
3_246 |
Heap
| Region (fill 1/100) | Region (fill 1/50) | StableMemory | |
|---|---|---|---|
| 10 pages | 272 B |
272 B |
276 B |
| 100 pages | 272 B |
272 B |
272 B |
| 256 pages | 272 B |
272 B |
276 B |
Garbage Collection
| Region (fill 1/100) | Region (fill 1/50) | StableMemory | |
|---|---|---|---|
| 10 pages | 208.34 KiB |
832.38 KiB |
336 B |
| 100 pages | 4.06 MiB |
8.13 MiB |
340 B |
| 256 pages | 10.4 MiB |
20.8 MiB |
340 B |
Stable Memory
| Region (fill 1/100) | Region (fill 1/50) | StableMemory | |
|---|---|---|---|
| 10 pages | 8 MiB |
8 MiB |
8 MiB |
| 100 pages | 8 MiB |
8 MiB |
0 B |
| 256 pages | 16 MiB |
16 MiB |
16 MiB |
Also add CHANGELOG note about stricter build canister name validation. Made-with: Cursor
Summary
Comprehensive audit of the mops CLI uncovered and independently verified 14+ bugs across core commands (install, check, build, test, sync, update, sources, publish, remove, add). All findings were verified against the actual source code before fixing.
High-priority fixes
Medium-priority fixes
Code quality
Documentation
Behavior changes
Test plan
Manual testing results
Test suite: 11 suites, 51 tests, 46 snapshots — all passing.
Smoke tests (run against dev entry point via
npm run mops):mops install— installs deps from cache/registry, verifies integrity ✓mops check— type-checks canister entrypoints, reports success ✓mops build— builds 2 canisters, validates candid compatibility, respects per-canister args (--incremental-gc,--release) ✓mops build foo— builds a single named canister ✓mops build nonexistent— exits with code 1, reports "not found in mops.toml configuration" (new stricter validation working) ✓mops test— runs Motoko test files with thetestlibrary, reports pass/fail ✓Targeted verifications:
mops syncwith version-pinned dep ("base@0.11.1" = "0.11.1"):mo:baseis imported (no false "unused" report) ✓mops update --lock ignore:diff) ✓mops.tomlwas updated frombase = "0.11.0"tobase = "0.16.0"✓--lock ignoreoption is properly forwarded to inneradd()calls ✓