Skip to content

feat(kit): every platform from one clip.config.ts: desktop-kit, mobile-kit, create-clip-wallet for extension, desktop and phone - #12

Merged
shayansal merged 6 commits into
mainfrom
feat/kit-all-platforms
Oct 7, 2026
Merged

shayansal merged 6 commits into
mainfrom
feat/kit-all-platforms

Conversation

@shayansal

@shayansal shayansal commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

npx create-clip-wallet my-wallet now makes the wallet on every platform from one root clip.config.ts: a browser extension, a desktop app (macOS, Windows, Linux) and a phone app (iOS, Android), plus the Scaffold-HBAR dapp with --scaffold-hbar. The desktop and phone apps become libraries the same way the extension became @clip-wallet/extension-kit.

Ported from the pre-publication history onto main: Apache-2.0 everywhere (including the new packages' LICENSE and NOTICE), the Low audit fixes kept (MOB-02 and PLG-02 moved with the mobile code into mobile-kit), crypto dependencies pinned exactly, vitest 4.1.11, and shayan@coldai.org contacts. pnpm-lock.yaml was regenerated with pnpm install.

Generated layout

clip.config.ts            the wallet, for every platform
wallet.identity.json      name, description, rdns, homepage, icon, appId, extension.key
icon.svg | icon.png       the logo; every platform's icons are rendered from it
MAINNET.md  .env  .keys/  checklist, CLIP_* build values, extension key (the last two never committed)
packages/extension/       wxt.config.ts = clipWallet({ config, configDir: "../.." }); one-line entrypoints
packages/desktop/         clipDesktop() + electronBuilderConfig(); one-line main/preload/renderer; icons, entitlements
packages/mobile/          expoConfig() + withClipWallet(); registerClipWallet(); assets/; eas.json
packages/nextjs/          Scaffold-HBAR dapp (--scaffold-hbar)
docs/listings/  docs/signing.md  tools/harness/  .harness/  AGENTS.md  llms.txt

Parts you don't choose are removed: their folders, root scripts, and the platform:<part> blocks in the docs and CI. With --scaffold-hbar and every platform, the result is byte-for-byte the create-scaffold-hbar project.

CLI

npx create-clip-wallet acme-wallet --platforms extension,desktop,mobile \
  --name "Acme Wallet" --rdns com.acme.wallet --id com.acme.wallet \
  --logo ./acme-logo.png --accent "#0B7A3B" --networks "evm:*,hedera,solana,bitcoin" \
  --languages en,de,ja --homepage https://wallet.acme.example --scaffold-hbar --yes

New options: --platforms, --scaffold-hbar, --id, --logo (alias --icon) and --languages. Without --yes it asks for each one. The new brand command (pnpm wallet:brand) re-renders every icon from the logo. Icons are made with Node alone: PNG encode and decode, area-average resampling, and ICO and ICNS writers. SVG logos are rasterised once by resvg, rsvg-convert, sips or ImageMagick.

New packages

  • @clip-wallet/desktop-kit: the main process, preloads, pages and native-messaging host, moved from apps/desktop.
    • clipDesktop() builds the electron-vite config.
    • electronBuilderConfig() maps clip.config.ts to electron-builder: app id, product, executable and artifact names, scheme, locales, icons, and signing only when its env vars are set.
  • @clip-wallet/mobile-kit: the screens, background host, in-app browser and plugins, moved from apps/mobile.
    • expoConfig() builds the app config.
    • withClipWallet() wires Metro.
  • @clip-wallet/config gains languages, appId, scheme, desktop/mobile id overrides, fees/usage (reserved, never acted on), platformIds(), and @clip-wallet/config/node.
  • apps/desktop and apps/mobile are now only Clip Wallet's brand on the kits, like apps/extension.

Docs

docs/kit-platforms.md is folded into the docs site and removed:

  • kit/index, create-clip-wallet, config (new Platforms section) and build-and-ship (desktop and phone sections) are updated.
  • New kit/signing page, added to the sidebar.
  • The project's wxt.config.ts, electron.vite.config.ts and app.config.ts are typechecked snippets.
  • Repo layout, vault-importer rules and the engine diagram are updated.
  • The new config settings are in the generated schema reference.
  • TypeDoc pages are generated for both kits.

Test results (local, macOS arm64, Node 24)

Check Result
pnpm install --frozen-lockfile ok
pnpm -r typecheck ok
pnpm -r test ok (desktop-kit 66, mobile-kit 103 vitest + 58 jest-expo, create-clip-wallet 26, docs 29, …)
pnpm harness ok (1989 source files, 0 warnings); check-manifests ok; sync-template ok
pnpm pack-all 37 tarballs (desktop-kit 228 kB, mobile-kit 629 kB)
pnpm kit:e2e --dapp all checks passed (76)
pnpm kit:e2e:scaffold-hbar all checks passed (same project as create-clip-wallet)
desktop Playwright e2e (apps/desktop) 2/2
extension Playwright e2e (apps/extension) 23 passed, 1 skipped (store screenshots). link.spec timed out once in the first full run, then passed alone and in a second full run.
docs build + link check 203 pages, no broken links, nothing unsafe
gitleaks git on the 3 commits no leaks

Build sizes from kit:e2e (a kit-built wallet, every platform):

Output Size
extension (chrome-mv3, unpacked) 11.2 MB
extension store zip 3.8 MB
desktop out/ (main, preloads, renderer) 23.6 MB
desktop Acme-Wallet-0.1.0-mac-arm64.zip 115.0 MB
desktop Acme Wallet.app (mac-arm64) 265.6 MB
mobile iOS bundle (Hermes) 25.7 MB
mobile Android bundle (Hermes) 25.7 MB
mobile dist/ (expo export) 51.4 MB

CI fixes in this PR

On main, the services job and the reproducible-build check already failed, and the desktop workflow failed on every runner. The new packages also brought CodeQL alerts. The last three commits fix all of these:

  • CodeQL:
    • Linear scans replace the regexes flagged as ReDoS in config, create-clip-wallet, i18n and media-client.
    • The harness and kit e2e escape regex metacharacters fully.
    • A file-system race in selectParts() is removed.
  • services: the install uses --filter "{./services/**}...". Without the braces, pnpm installed only the services, not packages/link.
  • desktop:
    • The Playwright step runs with --conditions=development.
    • The desktop-kit path and permission tests are platform-neutral.
    • shellEmulator: true lets Windows run NODE_OPTIONS=… electron-vite build.
  • repro: the check uses full history, so the commit bundle can be fetched. The container makes its outputs readable when run with umask 077.
  • create-clip-wallet: the scaffold tests get a 60 s timeout on shared runners.

Not built here

  • Windows and Linux installers were not built locally.
    • The desktop workflow builds apps/desktop for Windows (NSIS + zip) and Linux (AppImage, deb, tar.gz), unsigned, in CI only.
    • The CI kit e2e (ubuntu) builds the kit project's Linux tar.gz.
    • A kit project's Windows installer and Linux AppImage/deb were not built anywhere.
  • No native phone builds. The phone app was checked with expo export (iOS and Android) and expo prebuild only. There was no Xcode or Gradle build and no EAS.

Needs accounts or certificates (owner)

None of these is needed to build. The variable names are in kit/signing and the project's docs/signing.md.

  • Apple Developer Program:
    • Developer ID Application certificate and notarization key, for signed and notarized macOS builds. Everything built here is unsigned.
    • App Store Connect, for iOS.
  • Windows code-signing certificate (OV/EV) or Azure Trusted Signing.
  • Store accounts: Chrome Web Store, addons.mozilla.org, Edge Partner Center, Google Play Console. An Expo/EAS account if EAS builds are used.
  • A domain with AASA/assetlinks for universal links and phone passkeys.
  • npm publishing of the two new packages, through the existing CI-only changesets release with provenance.

🤖 Generated with Claude Code

Schayan Salehi and others added 3 commits October 6, 2026 20:29
…it; clip.config languages, app ids, scheme

The desktop and phone apps become libraries driven by clip.config.ts, the way the extension became
@clip-wallet/extension-kit: apps/desktop and apps/mobile now only hold Clip Wallet's brand (clip.config.ts, icons) and
one-line entrypoints.

- packages/desktop-kit: the main process, preloads, renderer pages, native-messaging host and their unit tests (moved
  from apps/desktop). clipDesktop() builds the electron-vite config (resolved config as virtual:clip-wallet/config,
  icon inlined as the dapp-facing identity, pages' title and CSP, native host bundled after the main build, mainnet
  checklist); electronBuilderConfig() maps the config to electron-builder (app id, product/executable/artifact names,
  deep-link scheme, Chromium locales for the offered languages, icons, env-driven signing and update publishing).
  The app id, scheme, TON Connect key, window title, user-agent scrub and WalletConnect metadata come from the config.
- packages/mobile-kit: the screens, background host, in-app browser, plugins and their vitest + jest-expo suites (moved
  from apps/mobile). expoConfig() maps the config to app.config (name, slug, scheme, bundle id, package, icons,
  adaptive icon and splash on the accent colour, permission texts); withClipWallet() wires Metro (the resolved config
  as a generated virtual module, Node shims, one React). Keychain services are <rdns>.vault / <rdns>.devicekey
  (unchanged for Clip Wallet); the onboarding icon is passed in by the app; Ledger BLE loads through import().
- @clip-wallet/config: languages, appId, scheme, desktop/mobile id overrides, fees/usage reserved for Clip Cloud
  (off, never acted on); platformIds(); @clip-wallet/config/node (loadClipConfigSync, buildEnv, resolveBuildConfig,
  iconDataUri, openChecklistItems).
- @clip-wallet/i18n + ui + both kits: only the languages clip.config offers are matched and listed.
- Harness allow-list, brand renderer and tests, CI workflows follow the move.

Verified: pnpm -r typecheck, pnpm -r test, pnpm harness; apps/desktop build + both Playwright e2e specs (2/2);
apps/mobile expo export --platform ios (28 MB Hermes bundle).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tension, desktop, mobile

`npx create-clip-wallet my-wallet` now makes the wallet on every platform: packages/extension (WXT on
@clip-wallet/extension-kit), packages/desktop (Electron on @clip-wallet/desktop-kit) and packages/mobile (Expo on
@clip-wallet/mobile-kit), plus packages/nextjs with --scaffold-hbar. Each depends only on published @clip-wallet/*
packages; one clip.config.ts + wallet.identity.json at the project root drives all of them.

- Template (templates/scaffold-hbar-clip-wallet): clip.config.ts, wallet.identity.json, the logo, MAINNET.md, .env and
  .keys/ move to the root; new packages/desktop (clipDesktop(), electronBuilderConfig(), one-line entrypoints,
  entitlements) and packages/mobile (expoConfig(), withClipWallet(), registerClipWallet(), eas.json); the dapp reads the
  identity from the root; root scripts dev:/desktop:/mobile:*; docs/signing.md (store accounts and code-signing
  variable names, no secrets); README, AGENTS.md, llms.txt, MAINNET.md, .harness, CI and the provenance check cover
  every platform, with platform:<part> / only:<part> markers.
- CLI: --platforms, --scaffold-hbar, --id, --logo (alias --icon), --languages, prompts for each, per-platform next
  steps; `brand` command (pnpm wallet:brand). selectParts() removes unchosen folders, scripts and doc blocks, so
  --scaffold-hbar with every platform is still byte-for-byte the create-scaffold-hbar project.
- Icons (src/icons.mjs, Node built-ins only): PNG decode/encode, premultiplied area-average resampling, ICO and ICNS
  writers; extension 16–128, macOS .icns, Windows .ico, Linux 16–1024, tray + macOS template, iOS icon (opaque, on the
  accent), Android adaptive + monochrome, splash. SVG logos rasterised once with @resvg/resvg-js, rsvg-convert, sips or
  ImageMagick, whichever is installed. A later accent change keeps a custom logo.
- extension-kit: clipWallet({ configDir }) for a shared clip.config.ts; store zips named after the wallet.
- Harness: kit projects are recognised by the root config; every present platform must build through its kit
  (clipWallet, clipDesktop + electronBuilderConfig, expoConfig + withClipWallet); appId may not be org.coldai.*.
- Kit e2e (tools/kit/e2e.mjs): every platform from the tarballs — identity and icons; install, harness, types;
  extension build, manifest, extension id and EIP-6963 in Chromium; desktop build, electron-builder for the host (macOS
  arm64 .app + zip) with bundle id, name, scheme and icon checked, packaged app launched headless to onboarding; Expo
  config, expo export (iOS + Android) and expo prebuild with ids, name, scheme and icons checked; mainnet refused by
  the harness and all three builds; security floor; --dapp builds the Scaffold-HBAR dapp.

Verified: pnpm -r typecheck, pnpm -r test, pnpm harness, pnpm pack-all, pnpm kit:e2e --dapp,
pnpm kit:e2e:scaffold-hbar (create-scaffold-hbar@latest, projects identical), apps/desktop Playwright e2e (2/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cs for the platform kits

- Docs site (apps/docs/src/kit): the "launch your own wallet" pages cover every platform. index (the platforms, the
  project layout with the config, identity, logo, MAINNET.md, .env and .keys/ at the root), create-clip-wallet
  (options, prompts, next steps, what it writes, icons from one logo, commands, the Scaffold-HBAR route, how kit:e2e
  tests it), config (platform settings: appId, desktop/mobile ids, scheme, languages, fees/usage reserved),
  build-and-ship (extension with configDir, desktop app, phone app, what the harness checks) and a new signing page
  (store accounts and code-signing variable names, never values) in the sidebar. Snippets for the project's
  wxt.config.ts, electron.vite.config.ts and app.config.ts are typechecked against the kits; the snippet test knows
  the kit project's scripts; reference.ts documents the new clip.config settings.
- Repo layout, vault-importer rules and the engine diagram follow the kits; @module headers on the new entry files
  for the API reference; pako's declarations are referenced from gunzip.ts so other programs typecheck it.
- create-clip-wallet, @clip-wallet/config, desktop-kit and mobile-kit READMEs (Install, Example, Documentation);
  apps/desktop and apps/mobile READMEs point at the kits; AGENTS.md (layout, commands, a desktop/phone recipe, the
  template recipe) and llms.txt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread packages/config/src/index.ts Fixed
Comment thread packages/create-clip-wallet/src/identity.mjs Fixed
Comment thread packages/create-clip-wallet/src/template.mjs Fixed
Comment thread packages/create-clip-wallet/src/template.mjs Fixed
Comment thread packages/create-clip-wallet/src/template.mjs Fixed
Comment thread tools/harness/check.mjs Fixed
Comment thread tools/kit/e2e.mjs Fixed
Schayan Salehi and others added 3 commits October 6, 2026 21:39
…caping, a file-system race)

- Linear scans instead of polynomial regexes on input: trimming hyphens in slugOfName() and platformIds()
  (@clip-wallet/config), the networks and languages arrays create-clip-wallet writes into clip.config.ts, the
  platform markers stripParts() reads (matched on the trimmed line), the "-u-…nu-" check in numberLocale()
  (@clip-wallet/i18n), and the trailing slashes of the media proxy base (@clip-wallet/media-client).
- tools/harness/check.mjs (and the template's byte-for-byte copy) and tools/kit/e2e.mjs escape every regex
  metacharacter, backslash included, when they build a RegExp from a binding, module or app id.
- selectParts() reads each marked file and skips one that isn't there, instead of checking first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd unit tests on every runner; repro bundle

- ci.yml: pnpm --filter "{./services/**}..." (with braces) also installs packages/link and backup-client, which the
  services typecheck against; the old selector installed only the services.
- desktop.yml: the Playwright step runs with --conditions=development, as `pnpm e2e` does locally (its helpers import
  workspace packages from source; nothing is built to dist/ in that job).
- desktop-kit tests on Windows: the clip-app path test uses the platform's own paths, and the launcher's POSIX mode
  is checked off Windows only.
- repro.yml: full history, so repro-check.sh's bundle of the commit can be fetched in each container.
- create-clip-wallet scaffold tests get 60 s each: copying the template and rendering every icon takes several
  seconds on a shared runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…un can be read back

- pnpm-workspace.yaml: shellEmulator, so scripts that set variables POSIX-style (NODE_OPTIONS=--conditions=development
  electron-vite build, the desktop app's dist:*, the extension's build) run the same way under cmd.exe; the desktop
  workflow's Windows build stopped at "'NODE_OPTIONS' is not recognized".
- scripts/repro-check.sh: the container writes the checksums as root under umask 077; it now makes them readable, so
  the host can compare the two runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shayansal
shayansal merged commit d0bbb18 into main Oct 7, 2026
11 checks passed
shayansal added a commit that referenced this pull request Oct 7, 2026
feat(networks): 85 of the 87 CLPR networks, 93 mainnets: 9 chain packages, Chainflip, STRATO, Arc (stacked on #12)
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.

2 participants