Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Modernize: oclif v4 migration + test harness + behavior-locking test suite - #41

Open
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization
Open

Modernize: oclif v4 migration + test harness + behavior-locking test suite#41
paulgnz wants to merge 4 commits into
XPRNetwork:masterfrom
paulgnz:modernization

Conversation

@paulgnz

Copy link
Copy Markdown
Contributor

Summary

This PR modernizes the proton-cli toolchain in three phases, each landed in its own commit so the diff can be reviewed in stages:

  1. Repair test harness.npm test was broken — the existing @oclif/test@1 errored at module load on modern Node (module.parent.filename is undefined). Bumped mocha/ts-node/@types/mocha; replaced the deprecated mocha.opts with .mocharc.json; added a small spawn-based CLI runner so behavior tests don't depend on @oclif/test internals.

  2. Behavior-locking test suite. No tests existed before this. Added 138 tests covering: pure unit tests for revealPassword/encryptor/confirmation; command-registration smoke tests that walk src/commands/**/*.ts and assert each file imports cleanly + declares a description; behavior tests for the security-critical commands shipped in PR security: redact private keys and add reveal-password gate for key:get / key:list #39 (key:list, key:get, key:reveal-setup, key:reveal-disable). Suite runs in ~7s.

  3. oclif v4 migration. All command files migrated from the deprecated @oclif/command@1.x to @oclif/core@4. Args migrated from legacy array syntax [{ name, required }] to v4 object syntax { name: Args.string({...}) }. flags.X(...)Flags.X(...). CliUx.ux namespace replaced with a small compatibility shim at src/utils/ux.ts that preserves the legacy method surface (log, styledJSON, prompt, confirm, url, table) on top of console + inquirer. Removed @oclif/command, @oclif/config, @oclif/parser. Bumped @oclif/plugin-help to v6 and oclif (the build CLI) to v4.

Test suite is green throughout; tests caught a couple of pre-existing latent typing bugs that v4's stricter inference exposed (delegatebw/undelegatebw referenced args.account when only args.receiver was declared; endpoint:set referenced args.chain when only args.endpoint was declared) — both fixed in this PR.

Result: deprecation warnings on fresh install

Verified by running npm pack against this branch and npm install ./proton-cli-0.1.98.tgz in a clean directory.

BeforeAfter
Total npm warn deprecated lines168
@oclif/* deprecation warnings90

The eight remaining warnings are all transitive dependencies of packages this repo doesn't directly own. Mapping:

DeprecationComes viaWho fixes it
eth-sig-util@3.0.1@proton/api@proton/api should migrate to @metamask/eth-sig-util
ethereumjs-abi@0.6.8@proton/api@proton/api
lodash.isequal@4.5.0@proton/api@walletconnect/*walletconnect bump
node-domexception@1.0.0@proton/jsnode-fetch chainclears when @proton/js updates node-fetch
uuid@8.3.2@proton/js, oclif, @oclif/testclears when those bump
inflight@1.0.6glob@7 chain — used by nyc and oclifreplace nyc with c8, or wait for nyc
glob@7.2.3nyc + oclif chainsame
rimraf@3.0.2nyc + a few otherssame

Cleaning these would mean either (a) bumping @proton/js / @proton/api upstream, or (b) replacing nyc with c8 for code coverage. Neither belongs in this PR; the second one is a 5-minute follow-up if desired.

Test plan

  • npm test — 138 tests, ~7s
  • npm pack && npm install ../*.tgz in a clean directory — installs cleanly, deprecation count cut in half, all @oclif/* warnings gone
  • Installed binary runs end-to-end: proton --version and proton key:list --help print expected output
  • All commands compile under TypeScript strict mode
  • Reviewer: smoke-test a few commands you care about that aren't covered by the test suite — chain operations, msig, contract:set, etc.

Notes for reviewers

  • The src/utils/ux.ts shim is a deliberate choice. v4 trimmed the ux namespace dramatically (gone: log, styledJSON, prompt, confirm, url, table). Rather than rewriting every call site, the shim gives us a stable internal surface with familiar method names. ~100 lines, fully typed.
  • The two codemod scripts in scripts/ (migrate-oclif.mjs and migrate-args.mjs) drove the bulk of the rewrite. They're committed for audit/reproducibility but are one-shot tools — happy to drop them in a follow-up commit if you'd prefer a cleaner tree.
  • TypeScript exposed two latent bugs in legacy code (the args.account / args.chain references mentioned above). Fixed inline rather than separately so reviewers can see why the tests pass.
  • Build uses tsx instead of ts-node for tests — handles the Node v22 ESM/CJS mix without the configuration gymnastics ts-node currently needs.

Branch state

  • Off XPRNetwork/proton-cli@master at 1f69edc (the 0.1.98 bump merge)
  • 4 commits, each phase its own logical unit
  • No private key strings of any kind in any commit (verified: git diff master..modernization | grep -E 'PVT_K1_|PVT_R1_' → no matches)

paulgnz added 4 commits May 7, 2026 08:20
- Bump mocha to ^10, ts-node to ^10, @types/mocha to ^10
- Replace deprecated test/mocha.opts with test/.mocharc.json
- Tighten test tsconfig to explicitly use commonjs + transpileOnly so
ts-node resolves TypeScript imports under Node v22
- Remove three stale test files (network/version/boilerplate) that
referenced moved imports and used the broken @oclif/test@1
- Add test/helpers/cli.ts — spawn-based CLI runner that does not
require @oclif/test, avoiding the v1 module.parent.filename crash
on modern Node versions
- Drop the posttest lint hook (3196 pre-existing style errors are out
of scope for this PR; expose linting as 'npm run lint' instead)
- Add first unit test (reveal-password) to verify harness works
npm test runs in <1s and exits green.
Unit tests for storage modules (chai + mocha, no @oclif/test):
- reveal-password: hash/verify roundtrip, salt randomness, scrypt params
- encryptor: AES-256-CBC encrypt/decrypt, IV randomness, wrong-key, unicode
- confirmation: shared CONFIRMATION_PHRASE constant locked to 'I UNDERSTAND'
Command-registration smoke tests:
- Walks src/commands/**/*.ts, asserts each file (a) imports without errors
and (b) declares a description. Catches the kinds of regressions a
command-by-command oclif migration can introduce (broken imports,
wrong base class, missing description).
Test infrastructure:
- Switch from ts-node to tsx (handles ESM/CJS mix on Node v22 cleanly,
no extension-resolution gymnastics)
- mocha v10 config in test/.mocharc.json with tsx as the loader
- Drop ts-node dependency (replaced by tsx)
128 tests passing in ~2s. No network or chain-touching tests yet —
those land later for the security-critical commands.
- Add isolated-HOME test fixture so behavior tests don't touch the
user's real config (XDG_*_HOME and HOME pointed at a per-test
tempdir; cleanup afterwards)
- Add pretest hook to run tsc -b so behavior tests exercise the
built CLI via spawn
- key:list tests: empty wallet, no PVT_K1_ leakage, --help shows
--reveal-private and --force
- key:get tests: empty-wallet behavior, --help mentions reveal password
and --force, no key strings in help output
- reveal-setup/disable tests: --help content, disable on fresh wallet
is a no-op, setup behaviour with non-TTY input
138 tests passing in ~7s. The pretest tsc adds ~5s; could move to a
single mocha 'before' hook later if speed matters.
The package's commands and supporting modules now use @oclif/core v4
exclusively. The legacy @oclif/command, @oclif/config, @oclif/parser,
and CliUx namespace are gone. v3 plugin-help bumped to v6 and the
oclif build CLI bumped to v4 to drop further deprecation chains.
Result of `npm pack` + fresh install: deprecation warning count
drops from 16 to 8. All eight remaining warnings are transitive
dependencies of @proton/js, @proton/api, oclif, or nyc (eth-sig-util,
ethereumjs-abi, inflight, glob, rimraf, lodash.isequal, node-
domexception, uuid). Zero @oclif/* warnings remain.
Code changes:
- src/utils/ux.ts is a small compatibility shim for the parts of the
legacy ux API that v4 dropped (log, styledJSON, prompt, confirm,
url, table). Implemented in <100 lines on top of console + inquirer
+ a tiny home-rolled table formatter. Avoids touching every call
site that previously used CliUx.ux.foo.
- All 50+ command files moved off @oclif/command/Command to
@oclif/core/Command, with await added to this.parse() calls.
- 45 command args migrated from legacy array syntax
([{ name, required, description }]) to v4 object syntax
({ name: Args.string({ required, description }) }).
- All flags() calls updated from lowercase 'flags.boolean(...)' to v4
'Flags.boolean(...)'.
- src/core/flags/index.ts: Flags.build was removed in v4; replaced
with a builder closure that returns a configured Flags.string.
- contract/set.ts dynamic-args pattern (which used @oclif/parser
Input directly) refactored to declare both args as optional and
validate at runtime against contractConfig overrides.
- Latent typing bugs surfaced by stricter v4 typing fixed:
delegatebw/undelegatebw used args.account when only args.receiver
was declared; endpoint/set used args.chain when only args.endpoint
was declared.
Test suite: 138 tests still passing post-migration.
Codemods used to drive the change live in scripts/migrate-oclif.mjs
and scripts/migrate-args.mjs and were kept in the repo for review/
audit purposes; they are one-shot tools and can be deleted in a
follow-up commit if upstream prefers a cleaner tree.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@paulgnz