Skip to content

fix(cli): stop an explicit --wallet-provider being discarded in silence - #461

Merged
GigaHierz merged 2 commits into
celo-org:mainfrom
ghozzza:fix/wallet-provider-signal
Aug 14, 2026
Merged

fix(cli): stop an explicit --wallet-provider being discarded in silence#461
GigaHierz merged 2 commits into
celo-org:mainfrom
ghozzza:fix/wallet-provider-signal

Conversation

@ghozzza

@ghozzza ghozzza commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Closes #453. All three items from that issue, plus a crash found while verifying item 3 that belongs with them.

1. The flag is discarded without a word

create app -t x402 --wallet-provider thirdweb exited 0 and produced a project with no thirdweb in it. The forcing is right — the plop guards skip the wallet actions regardless, so honouring the flag would only write a navbar importing a component nothing generates (#396) — but nothing told the user their flag did nothing.

Now it warns, on stderr, naming the flag and the reason:

⚠️  Ignoring --wallet-provider thirdweb: the x402 template ships no wallet layer of its own.

--wallet-provider none stays quiet. That is what the forcing produces anyway, so it agrees rather than conflicts.

2. The skip message was false for half the templates it covered

Skipping RainbowKit - This template uses its own wallet components was shown for x402 too, which ships none — which is exactly why the flag cannot be honoured there. The one explanation a user got pointed at a wallet layer that does not exist.

The reason now depends on the template, and the list lives in src/utils/templates.ts rather than being restated at each guard. That drift is the whole bug: the same fact was written in four places (the forcing, two comments beside it, and the strings) and the copies disagreed.

3. The thirdweb lib guard did not match its components guard

Aligned, as the issue asks. Both now read the shared list.

The part that was not in the issue: minipay

Checking item 3 turned up a live crash rather than a latent one. minipay was absent from the forcing, and it writes connect-button.tsx and wallet-provider.tsx — the same two filenames the thirdweb template writes. Nothing stopped both actions from running.

On main (666f51a):

$ create mp -t minipay --wallet-provider thirdweb --skip-install -y
Error: Template generation failed: File already exists
 -> apps/web/src/components/connect-button.tsx
$ echo $?
1

The project is left half on disk. Adding minipay to the shared list fixes it, and it is the same edit the other three items need, so separating it would mean touching these lines twice.

Flagging the scope explicitly in case you would rather I split it: the issue names farcaster-miniapp, ai-chat and x402, and this PR also changes behaviour for minipay.

Verification

Generated from this branch, with a control run each time so a guard that suppresses everything would not pass:

command before after
-t minipay --wallet-provider thirdweb exit 1, half-written exit 0, minipay's own three components, no lib/client.ts, warns
-t x402 --wallet-provider thirdweb exit 0, silent warns "ships no wallet layer of its own"
-t basic --wallet-provider thirdweb thirdweb wired unchanged — lib/client.ts present, silent
-t x402 --wallet-provider none silent silent

Four regression tests added to template-wiring.test.ts, including the control. The helper moved from execFileSync to spawnSync because the diagnostic is on stderr and execFileSync only returns stdout. 26/26 pass, tsc clean, eslint clean apart from one pre-existing warning in scaffold-smoke.test.ts that this branch does not touch.

Four templates cannot honour --wallet-provider, for two different
reasons, and the difference was restated in four places that had
drifted apart. Move the list and both reasons into utils/templates.ts
and read it everywhere.

The skip messages claimed every affected template "uses its own wallet
components", which is false for x402 and ai-chat: they ship none, and
that is precisely why the flag cannot be applied.

minipay was missing from the forcing altogether. It writes
connect-button.tsx and wallet-provider.tsx, the same filenames the
thirdweb template writes, so `-t minipay --wallet-provider thirdweb`
aborted with "File already exists", exited 1 and left a half-written
project. Also align the thirdweb lib guard with its components guard.

Closes celo-org#453

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ghozzza
ghozzza force-pushed the fix/wallet-provider-signal branch from fd514c8 to 5a6cb5b Compare August 13, 2026 12:14

@GigaHierz GigaHierz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Items 1–3 are right and well-executed — the warning at the final resolution point, the per-template skip reasons, the shared list ending the four-way drift, and the spawnSync test harness are all exactly what #453 asked for. The minipay collision discovery is real too (verified the mechanics: on main, minipay is absent from the forcing, so an explicit thirdweb flag runs both component actions onto the same filenames and plop aborts).

But the chosen fix for it introduces a worse regression, verified by scaffolding from this branch:

tsx src/index.ts create mp-check -t minipay --skip-install -y
grep -E "rainbowkit|wagmi|viem|react-query" mp-check/apps/web/package.json
# → no matches

Every default minipay scaffold now ships without its wallet stack. Putting minipay in the shared list makes ignoresWalletProvider force walletProvider = "none" — but minipay's own components are built on the rainbowkit/wagmi stack (wallet-provider.tsx imports RainbowKitProvider/WagmiProvider/QueryClientProvider, user-balance.tsx uses wagmi hooks), and the manifest template gates all four deps on walletProvider === "rainbowkit" (@rainbow-me/rainbowkit directly; viem/wagmi via the rainbowkit-or-farcaster guard from #450; react-query via #428's guard). With "none", none of them land, and the navbar also loses its connect-button import (its guard is rainbowkit-or-thirdweb), so minipay's own ConnectButton is never rendered. On main, minipay defaults to rainbowkit and all of this works — this branch breaks it.

Suggested shape: minipay isn't "ignores the flag → none"; it requires rainbowkit. Something like a third category in utils/templates.ts:

export const REQUIRES_WALLET: Record<string, string> = { "minipay": "rainbowkit" };
// forcing: REQUIRES_WALLET[t] ?? (SHIPS_NO_WALLET/farcaster → "none") ?? flag ?? default
  • Forcing minipay to "rainbowkit" fixes the collision just as well: the rainbowkit components action already skips on templateType === "minipay", and the thirdweb actions skip on walletProvider !== "thirdweb" — no same-filename writes, no crash.
  • The warning logic generalizes to "flag differs from the forced value" (warn for --wallet-provider thirdweb, stay quiet for --wallet-provider rainbowkit on minipay, mirroring the none agreement case you already handle).
  • walletOverrideReason for minipay can then say what's actually true: it ships its own rainbowkit-based components.

Test gap that let this through: the minipay fixture asserts its components exist and thirdweb's lib doesn't, but never asserts the manifest keeps the wallet deps. Please add e.g. expect(pkg.dependencies).toHaveProperty("@rainbow-me/rainbowkit") (and wagmi) to the minipay fixture — that assertion fails on this branch today and would have caught the regression.

Happy to re-verify as soon as it's revised — everything else in the PR is mergeable as-is.

Review on celo-org#461 found that the first fix for the minipay/thirdweb
collision broke every default minipay scaffold. Putting minipay in the
shared list forced walletProvider = "none", but minipay's own
components are built on that stack — wallet-provider.tsx imports
RainbowKitProvider, WagmiProvider and QueryClientProvider, and
user-balance.tsx uses wagmi hooks — while the base manifest gates
@rainbow-me/rainbowkit, wagmi, viem and @tanstack/react-query on
walletProvider === "rainbowkit". The result was a project whose own
components imported four packages it no longer declared.

The list conflated two questions. They are now separate: what
walletProvider must be (forcedWalletProvider) and which wallet-template
files must not be written (skipsWalletTemplateFiles). minipay is in the
second and takes "rainbowkit" from the first.

Forcing rainbowkit closes the original collision just as well: the
rainbowkit components action already skips on templateType === minipay,
and both thirdweb actions skip on walletProvider !== thirdweb.

The warning now fires when the flag differs from the forced value
whatever that value is, so --wallet-provider rainbowkit on minipay is
agreement and stays quiet, and the message names what is used instead.

Adds the manifest assertion review asked for. It fails on the previous
revision: reverting minipay to "none" turns 3 tests red. 28/28.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ghozzza

ghozzza commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

You are right, and thank you for scaffolding it rather than reading it — I would not have found this from the diff. Revised in ab6ced1.

Reproduced your repro first, both sides:

this branch (before): minipay default → 0 of rainbowkit/wagmi/viem/react-query
main:                 minipay default → all four present

And confirmed the cause you named: wallet-provider.tsx imports RainbowKitProvider, WagmiProvider and QueryClientProvider, user-balance.tsx uses wagmi hooks.

The list was answering two questions at once. That is the actual defect, and your suggested shape separates them:

  • forcedWalletProvider(t) — what the value must be. REQUIRES_WALLET first, then "none".
  • skipsWalletTemplateFiles(t) — which wallet-template files must not be written.

minipay is in the second and takes "rainbowkit" from the first. Renamed ignoresWalletProvider out of existence, since for minipay it was simply the wrong verb.

The original collision closes just as well, exactly as you predicted: the rainbowkit components action already skips on templateType === "minipay" and both thirdweb actions skip on walletProvider !== "thirdweb", so nothing writes the same filename twice.

Warning generalised to "the flag differs from the forced value", and it now names the substitute:

-t minipay --wallet-provider thirdweb
  ⚠️  Ignoring --wallet-provider thirdweb: the minipay template ships its own
      rainbowkit-based wallet components. Using rainbowkit instead.

-t minipay --wallet-provider rainbowkit   → silent (agreement)
-t x402   --wallet-provider thirdweb      → "…ships no wallet layer of its own. Using none instead."
-t basic  --wallet-provider thirdweb      → silent, client.ts present

The test gap, closed the way you asked. Added toHaveProperty("@rainbow-me/rainbowkit") and wagmi to the minipay fixture, plus a separate test for the default scaffold with no flag at all — which is the case that was actually broken and which no fixture covered. It asserts all four packages and that the components needing them exist.

Mutation-tested rather than assumed: reverting minipay to "none" turns 3 tests red. Previously that revert was invisible.

28/28, tsc clean.

The lesson I am taking is narrower than the bug. Every assertion in my minipay fixture was absence-shaped — thirdweb's lib is not here — with nothing asserting that what should be present still was. That is the same shape as two other misses this week, and it is now a rule I am applying rather than a note.

@ghozzza

ghozzza commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Revision pushed in ab6ced1 — you were right, and the regression reproduced exactly as you described.

Flagging one piece of plumbing first: submitting CHANGES_REQUESTED drops the reviewer from the request list, so this PR is no longer in your "awaiting your review" queue. I have read-only access here, so --add-reviewer returns 404 and I cannot put it back. The board card for #453 is on In review, but this comment is the only notification I can actually generate. Not asking for write access — just noting why this might otherwise sit quietly.

On the fix. Your diagnosis was the right one and my original shape was wrong. I had collapsed two different questions into one list:

  • does this template need a specific wallet provider? — minipay does: rainbowkit
  • does this template write its own wallet files? — minipay does, which is what collided with thirdweb

Putting minipay in one shared list answered both with "ignore the flag", and that is what stripped the stack. Restructured to your suggested shape:

export const REQUIRES_WALLET: Record<string, string> = { minipay: "rainbowkit" };
export const SHIPS_OWN_WALLET = ["farcaster-miniapp", "minipay"];
export const SHIPS_NO_WALLET  = ["ai-chat", "x402"];

So minipay is now forced to rainbowkit rather than to none; the thirdweb collision is still prevented, because the file-writing question is answered separately.

Both sides verified by scaffolding, not by reading the diff:

create mp-check -t minipay --skip-install -y
grep -E "rainbowkit|wagmi|viem|react-query" mp-check/apps/web/package.json   # all four present

create mp-tw -t minipay --wallet-provider thirdweb --skip-install -y
# completes, warns that minipay requires rainbowkit, no "File already exists"

Added the assertion you asked for, plus one you did not: a default-scaffold test asserting all four deps are in package.json. That is the one that would have caught this — the original suite only ever exercised explicit-flag paths, so the default case nobody passes a flag for was untested. Reverting the fix turns three tests red.

Ready for another look when you get to it.

@ghozzza

ghozzza commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

@GigaHierz — pinging because this one will not reach you otherwise.

Submitting the CHANGES_REQUESTED review removed you from the reviewer list, so this PR is no longer in your "awaiting your review" queue. I have read-only access on this repo, so --add-reviewer returns 404 and I cannot put it back. The board card for #453 is on In review, but that is the only signal left.

The revision landed in ab6ced1 at 09:42, about 25 minutes after your review, and it is green. The regression you found reproduced exactly as described, and the fix follows the shape you suggested — the two questions your review separated (which wallet provider a template requires vs whether it writes its own wallet files) are now two separate lists, so minipay is forced to rainbowkit rather than to none. Details in the comment above.

Nothing needed from you beyond knowing it is there.

@GigaHierz GigaHierz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-verified the revision empirically: a default minipay scaffold now declares all four wallet packages its components import (@rainbow-me/rainbowkit, wagmi, viem, @tanstack/react-query — the regression from the first version is gone); -t minipay --wallet-provider thirdweb exits 0 with the correct warning ('ships its own rainbowkit-based wallet components. Using rainbowkit instead.'), no thirdweb lib lands, and the rainbowkit deps survive; agreement cases stay quiet. The forcedWalletProvider/skipsWalletTemplateFiles split is the right factoring — the two questions genuinely have different answers for minipay, and the file documents why. Full suite 28/28 on the branch. Nice turnaround.

@GigaHierz
GigaHierz merged commit 893c842 into celo-org:main Aug 14, 2026
2 checks passed
Sign up for free to 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.

--wallet-provider is discarded without a word, and the skip message that explains why is wrong for two templates

2 participants