feat: retarget the canton stack and split stack config into modules - #16
Conversation
The initial commit was made as "dAppBooster <no-reply@dappbooster.dev>", so the first entry in every new project's history belonged to the installer instead of the person who ran it. Drop the hardcoded name and email and let git fall back to the user's own configuration. Signing stays off, and --no-verify stays, so the project's own hooks do not lint a tree nobody has touched yet.
Canton now points at canton-dappbooster and installs with pnpm. It is cloned at its newest tag, copies one root .env file, and offers no optional features, so the wizard asks only for a project name and the CLI rejects --mode and --features for it. Stack metadata leaves source/constants/config.ts for one module per stack under source/stacks/, with source/stacks/index.ts holding the record and the accessors. Every type moves to source/types/types.ts. New fields in StackConfig: - prepare: the paths, scripts and devDependencies every scaffold drops. It runs before the install, so the package manager resolves the pruned manifest once. Replaces removeAfterClone and hygiene. - minNodeVersion: checked at the top of cloneRepo, so a Node that is too old fails with a plain message instead of a confusing install error. - postInstallComponent: a richer closing screen for the wizard, imported on demand so --info and the non-interactive path never load Ink. A stack is cloned at its newest tag unless ref names one, which today only DAPPBOOSTER_<STACK>_REF does. That leaves refType with nothing to decide, so it is gone, along with npm as a package manager. No stack used either.
Update the architecture guide, the readme and the agent instructions for the new layout. source/stacks/ is the single source of truth for stack and feature metadata, and every type lives in source/types/types.ts. Also covers: - the prepare step, and what it replaced - the Canton stack, and why it takes neither --mode nor --features - the rule that no file outside source/stacks/ and source/cli.tsx may test a stack by name
The review step printed everything on one long line, separating the settings with a middle dot. Each setting now gets its own line, and the value after the colon is bold green, the same style the stack and installation type answers already use. The installation mode is named from one shared table, so the review spells it the same way the selector did. - describeInstallPlan returns a label and a value per setting instead of a finished string, so the step decides how a line looks - MODE_LABELS moves to utils.ts, where both the selector and the review read it - the confirmation answers now read "Yes." and "No, start over." - planSummary is memoised, because the step list is built from it
The divider read "Full installation" or "Custom installation", built from the mode name. Stacks with no modes have nothing to put there, so the title is now fixed and works for any stack.
The divider read "Post-install instructions — EVM". The stack is already settled by the time this step runs, so the title is now fixed.
Canton fell back to a plain list of lines while EVM had a proper screen. It now has one too, laid out the same way: the steps to start, then a warning, then where to read more. Canton: - highlights dev-stack, the cd command, the script path and Stack Up - warns in bold that the first run pulls about 10 GB - links the README, the components documentation and the issue tracker EVM: - drops the line about the installer's own issue tracker - reports issues against the dAppBooster repo instead - adds a link to the components documentation - rewords the documentation line to match Canton's The postInstall lines in the stack config stay as they are. They are what --ni prints as JSON.
The running step showed a static circle and the word "Working...". It now shows a spinner, so a long clone or install looks alive instead of stuck. Adds ink-spinner, which resolves to the same ink 5.2.1 the other ink packages use, so there is still one renderer. Clone, cleanup and install all render through StepProgress, so all three get it.
Project names took letters, numbers and underscores only, so the common my-dapp spelling was rejected. Dashes are now allowed, but not as the first character: the name is the last argument of git clone, and git reads a leading dash as an option. --upload-pack= runs a command, so the name has to start with a letter, a number or an underscore. The wizard tip, the --ni error and the --help text all say so. Ask takes its tip as a node now, so the tip can put "non-initial" in bold.
Once a stack is picked, the title shows which one, so the stack stays visible for the rest of the run instead of scrolling away with the selection step. MainTitle takes the stack and reads its label from the config, so a third stack needs no change here. Nothing shows before a stack is chosen. The badge sits on the last line of the logo. ink-big-text pads its block with two blank lines top and bottom, which is what the bottom margin cancels out.
Patch and minor bumps only. No API changes, so nothing in the source had to move. - @biomejs/biome 2.5.12 -> 2.5.13 - knip 6.33.0 -> 6.35.1 - @types/node 24.13.3 -> 24.13.4 - lint-staged 17.5.0 -> 17.5.1 biome.json points at the matching schema, which biome migrate wrote. The major bumps are left alone: ink 7 wants react 19, and ink-divider depends on ink 5 outright rather than as a peer, so taking it would load two renderers. TypeScript 7 is its own decision.
The readme dropped its development section. Everything in it was already here except two things, which move over: - the full command table. Only the five validation commands were listed, so build, dev, test:coverage and lint:fix were missing, as was the fact that typecheck runs two passes - the warning to run the built CLI from a scratch directory, since it scaffolds into the folder it starts from
architecture.md was an index pointing at three files under docs/architecture/. The split existed so a reader could open one part instead of all of it, but the whole guide is only 280 lines, so it bought nothing and cost an index table to keep in sync and links between files that break when a section moves. It is one file now, with the sub-docs as sections: Key Abstractions, Data Flow, Extending the Installer. The docs folder is gone. The prose is unchanged. Only the heading levels moved, and the two links between sub-docs became in-page anchors.
Most of the readme repeated what CLAUDE.md and architecture.md already say, at more length and with less accuracy. The flag table was also incomplete. It now lists --info, --help, --version and the --non-interactive long form, checked against cli.tsx and the --help output, and the --name row shows the real pattern now that dashes are allowed.
demo.svg still showed an older wizard. It now shows the current one: the stack prompt, the badge, the stacked review screen and the spinner. It is cut at 15 seconds, ending as the clone starts. Past that point it is the package install, a long stretch of near-static output that reads as a frozen image rather than a loop. The file is 28 KB, down from 90 KB. scripts/record-demo.py regenerates it in one command. It scaffolds a real EVM project in a temporary directory, drives the wizard, and runs svg-term-cli. CLAUDE.md records what was expensive to work out: the exact svg-term flags that match the committed geometry, why asciinema cannot be scripted here, and why the script uses a pty from the Python standard library.
Claims that this branch made wrong: - stacks were said to declare a "ref strategy (tag-latest vs branch)". refType is gone; a stack declares an optional ref and is cloned at its newest tag without one - the interactive step order read "install then cleanup". It is clone, cleanup, install, post-install - installPackages was said to use pnpm or npm. It is pnpm only - Confirmation was said to show a one-line summary. It shows one line per setting Also adds ink-spinner to the styling row, CantonPostInstall.tsx to the structure tree, and the stack badge to the MainTitle description.
The installer accepted Node 22 while the Canton stack needs 24.15.0, so a Canton user on Node 22 got as far as the clone before being turned away. Everything now asks for the same version. - engines.node is >=24.15.0 - the CI floor job runs 24.15.0 instead of 22 - the readme, CLAUDE.md and architecture.md say the same .nvmrc stays at 24. It already resolves to the newest 24.x, and pinning development to the floor is worse than following the latest patch. CI still covers both. dAppBooster declares no Node version at all, which is BootNodeDev/dAppBooster#484. The EVM stack gets no minNodeVersion until that lands, since the number should come from the template.
There was a problem hiding this comment.
🔵 Needs a closer look
It is a large, multi-file refactor that retargets a stack, changes CLI/UX behavior, and touches CI and dependency floors, so final human verification is warranted.
Pull request overview
This PR retargets the Canton stack at the new canton-dappbooster repository (whose three libraries now ship on npm) and refactors stack/feature metadata out of a single source/constants/config.ts into a per-stack module layout under source/stacks/. Scaffolding Canton is now essentially deletion: a prepare phase removes the in-tree library folders (canton-connect, canton-dappbooster, canton-theme, kit/) and repo-only tooling before a single pnpm install, so the same package.json resolves the libraries from the registry. Canton declares no features, so the wizard asks only for a project name and the non-interactive path rejects --mode/--features for it. The EVM path keeps its features and behavior, with cosmetic UI updates (per-line review screen, running spinner, stack badge, dedicated post-install screens).
Changes:
- Split
constants/config.tsintosource/stacks/{index,evm,canton}.ts+ sharedsource/types/types.ts; all consumers read viagetStackConfig, andgetInstallationModesreturns[]for featureless stacks to drive step-skipping and CLI rejection. - Retarget Canton (new
repoUrl,pnpm,minNodeVersion 24.15.0,initialCommit, latest-tag clone,preparepaths/scripts/devDependencies, single.env.example → .env), drop the Canton feature system, and generalizeremoveAfterCloneinto a config-driven prepare phase applied before install. - Allow dashes (not leading) in project names, add spinner/badge/per-line review UI, dedicated
EvmPostInstall/CantonPostInstall, dropnpm/refType, bump four dev deps, raiseengines.nodefloor, and update docs/demo/CI.
File summaries
| File | Description |
|---|---|
source/stacks/index.ts |
New accessors (getStackConfig with env overrides, getInstallationModes) that centralize stack metadata. |
source/stacks/evm.ts |
EVM StackConfig with prepare/staging and the five features unchanged. |
source/stacks/canton.ts |
Retargeted Canton config: new repo, pnpm, prepare deletions, no features, dedicated post-install. |
source/types/types.ts |
Home for shared types (Stack, FeatureName, StackConfig, PrepareStep, PlanSummaryItem, …). |
source/operations/cleanupFiles.ts |
Config-driven prepare phase: delete paths, strip scripts referencing removed dirs, prune devDependencies pre-install. |
source/operations/installPackages.ts |
Simplified to pnpm-only (remove) install/post-install flow. |
source/operations/cloneRepo.ts |
Uses ref (env override) or latest tag; enforces minNodeVersion before disk work. |
source/nonInteractive.ts |
Rejects --mode/--features for featureless stacks with a named reason. |
source/app.tsx |
Skips mode/feature/confirmation steps when a stack has no features. |
source/utils/utils.ts |
Adds meetsNodeVersion, MODE_LABELS, per-item describeInstallPlan, dash-aware isValidName. |
source/components/steps/* |
New spinner (StepProgress), stack badge (MainTitle), and Evm/Canton post-install screens. |
source/info.ts |
--info reports empty modes/features for Canton. |
tests, docs, demo, CI, package.json |
Comprehensive test updates, doc merge, re-recorded demo, dep bumps, and Node-floor CI rename. |
Review details
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
- Files reviewed: 48/50 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
fernandomg
left a comment
There was a problem hiding this comment.
all worked, tested manually and tested sandboxed in a clean-unaware claude session.
The latter reported the following:
Issues hit
None that broke the run. Everything worked on the first attempt. Two friction points:
- The post-install instruction is wrong for non-interactive use. It says
./scripts/dev-stack.sh, which opens a TUI menu and hard-fails without a terminal. The headless path is./scripts/dev-stack.sh up, and you only learn that by reading the script. - No sense of how long this takes. "Pulls about 10 GB" is the only hint. There's no progress signal between "started" and "done", which is rough for both humans and automation.
Room for improvement
In the CLI:
- Have
--niemit the non-interactive next command (./scripts/dev-stack.sh up), not the menu entry point. The scaffolder already knows it's in agent mode — the advice should match. - Make
postInstallstructured rather than prose. Something like{"command": "...", "requires": ["docker"], "estimatedMinutes": 20}is actionable; a sentence is not. - Add a preflight check (a
--doctor, or just run it during scaffold) for Docker,dpm, Node and pnpm versions. All four are hard requirements and all four fail late and confusingly today.
In the generated project:
README.mdis stale in two places: it hardcodesamulet-vesting-0.0.1.dar(the actual build is0.0.2—dev-stack.shderives this fromdaml.yaml, so the README should too, or just not name the file), and it asks for pnpm 11.22.0 whilepackage.jsonpins 11.24.0.- Add a
--jsonor--quietmode todev-stack.sh upso progress is machine-readable instead of ANSI-coloured prose. - The post-install checklist should mention the separate browser wallet. Right now you finish the documented steps and the app still isn't usable, with no explanation until you read
dev-stack.sh's final output.
The non-interactive post-install told agents to run ./scripts/dev-stack.sh, which opens an arrow-key menu and fails when there is no terminal. The headless command is ./scripts/dev-stack.sh up, and the only way to find that out was to read the script. The canton postInstall lines now cover what an agent needs: - run every command from the folder reported in "path" - Docker, and the docker-up subcommand that starts it on macOS - the DAML SDK, which the script checks before any container starts - "up" to start the stack, and why the bare call fails - that "up" prints each step and fails on its own, so a slow first run is not a hang - "status" and "down" - the Carpincho wallet repo, which runs outside the project The human screen keeps its menu wording, which is the right advice in a terminal. nonInteractive.test.ts now asserts the "up" subcommand, not just the script name.
The installer runs pnpm to install the project's dependencies, but never checked it was there. A machine without pnpm got a full clone first and a spawn ENOENT afterwards, with the new folder already on disk. cloneRepo now runs "<packageManager> --version" right after the Node floor check and before the clone, and fails with: pnpm was not found. Install it, then run the installer again. The command name comes from the stack config, so a stack on another package manager checks for that one instead.
Fixed.
No way to know how long it will take or get a sense of progress, but this is a
Done.
This looks like too much work for little gain: the consumer is an LLM agent, prose is what it reads best. A schema only pays off if something (a CI script or some other tool) parses it.
It does not, check https://github.com/BootNodeDev/canton-dappbooster#dar-build-and-deploy
That's in the readme and it's optional. For the rest I created this separate issue BootNodeDev/canton-dappbooster#215 |
Summary
Closes #15
canton-dappbooster moved to a new repository and publishes its three libraries to npm. The installer still pointed at the old repo and described a tree that no longer exists.
Changes
Deviations
refTyperemoved entirely rather than set totag-latest. With both stacks on tags it had nothing left to decide, sorefalone drives the cloneAcceptance criteria
pnpm dlx dappbooster --canton --name testproj --niscaffolds a working project from the latest canton-dappbooster tagpackage.jsonhas neither the seven scripts nor typedoc and postcsspnpm installin the scaffolded project resolves the three@bootnodedev/*libraries from npm, with no path pointing into a workspace library folderpnpm lint,pnpm typecheck,pnpm testandpnpm knipall pass in the scaffolded project (knip printing configuration hints is fine, as long as it exits 0)--modeor--featureswith--cantonfails with a message naming the reasonsource/outsidestacks/andcli.tsxtests a stack by nameTest plan
Automated tests
pnpm installpnpm lint && pnpm typecheck && pnpm build && pnpm test && pnpm knipManual verification
pnpm buildnode <repo>/dist/cli.js./scripts/dev-stack.sh upin the new project and choose Stack UpOptional: EVM
pnpm subgraph-codegenandpnpm dev, and open the printed URLNon-interactive, driven by an agent verification
Give a coding agent only the goal, never the flags, and watch what it does.
--infofirst, and to readmodesbefore choosing anything--canton --ni --name <name>and no--modeor--features"success": trueand an emptyfeatureslist--evm --ni --mode custom --features demo,subgraph, and the same features echoed backTo check the failure paths by hand:
--canton --ni --name x --mode fulland expect a refusal naming Canton--evm --ni --name x --mode custom --features nopeand expect the valid feature names listed--canton --evmand expect a conflicting-flags errorBreaking changes
None.
Checklist