Skip to content

feat: scaffold script + repo build/test/release tooling#3

Open
ivanbanov wants to merge 8 commits into
mainfrom
feat/scaffold-script
Open

feat: scaffold script + repo build/test/release tooling#3
ivanbanov wants to merge 8 commits into
mainfrom
feat/scaffold-script

Conversation

@ivanbanov

@ivanbanov ivanbanov commented Jul 15, 2026

Copy link
Copy Markdown
Member

Brings the repo to a working, CI-green tooling foundation: the primitive scaffold generator plus the build/test/release toolchain — no primitive packages, no sandbox apps (those land in follow-up PRs).

Scaffold (commit 1)

  • scripts/scaffold.tspnpm scaffold <kind> <name> copies a tokenized template tree (__name__ / __Name__ / __camelName__) into packages/, then derives the tsconfig.json paths and tsdown.config.ts workspace wiring from the packages it created.
  • scripts/templates/full/** — the first "kind": the core/dom/react trio for a new primitive, tokenized and real (lintable/diffable), not string templates.
  • scripts/templates/README.md — tokens, why the dir is tool-excluded, and how to add another kind.
  • scripts/templates/** excluded from oxfmt, oxlint, vitest, and knip (the __name__ token isn't valid until scaffolded).

Build / test / release tooling (commit 2)

  • package.json — rename to ui; add build (tsdown), test:ci (vitest run), changeset:version / changeset:publish. Adds tsdown, publint, @changesets/changelog-github. Omits jsdom (only the React binding's DOM tests need it) and the sandbox:* scripts (no sandbox in this PR).
  • tsdown.config.ts — one root config, builds the publish set in workspace mode. tsdown errors on an empty workspace, so it points at the existing placeholder packages/core for now; the first real primitive replaces that entry.
  • tsconfig.json — reformatted; empty paths (package aliases land with the packages).
  • .changeset/config.json — schema bump, GitHub changelog generator (dunky-dev/ui), baseBranch: origin/main (matches ci.yml's --since). Drops the fixed group, @sandbox/* ignore, and the peer-dependent experimental flag — each only applies once the packages/sandbox exist.
  • knip.config.ts — drop the now-redundant build ignoreBinaries (resolves to a real script now); keep the scaffold-templates ignore.
  • .oxfmtrc.json — also ignore **/dist/**.
  • CONTRIBUTING.md — apply a pending oxfmt table-alignment fix (pre-existing on main) so format:check is green.

Why point the build at the placeholder?

ci.yml (already on main) runs pnpm build, but tsdown refuses an empty workspace. Rather than stub the build, it builds the repo's current sole publishable package — the template placeholder packages/core (builds clean, publint passes). The packages PR swaps this list for the press packages and removes the placeholder.

Test plan — all seven ci.yml jobs pass locally

  • pnpm build — builds packages/core, publint clean
  • pnpm test:ci — 1 passing (placeholder)
  • pnpm typecheck
  • pnpm lint
  • pnpm format:check
  • pnpm knip — no unused deps, no hints
  • pnpm changeset status --since=origin/main

Introduces a code-generation script that copies a tokenized template tree
(currently one kind, "full": the core/dom/react trio for a new primitive)
into packages/, substituting the primitive's name, then derives the
tsconfig `paths` and tsdown `workspace` wiring from the packages it
created.

Template stubs under scripts/templates/** use a __name__ token that isn't
valid TS/lintable source until scaffolded, so they're excluded from
oxfmt, oxlint, vitest, and knip.
Brings the repo-level toolchain to a working, CI-green state without
adding any primitive packages or sandbox apps:

- package.json — rename to `ui`; add `build` (tsdown), `test:ci`
  (vitest run), and `changeset:version` / `changeset:publish`. Adds
  tsdown, publint, and @changesets/changelog-github. Omits jsdom (only
  the React binding's DOM tests need it) and the sandbox:* scripts.
- tsdown.config.ts — one root config that builds the publish set in
  workspace mode. tsdown errors on an empty workspace, so it points at
  the existing placeholder `packages/core` for now; the first real
  primitive replaces that entry.
- tsconfig.json — reformatted; empty `paths` (the package aliases land
  with the packages).
- .changeset/config.json — schema bump, GitHub changelog generator
  (repo dunky-dev/ui), baseBranch origin/main to match ci.yml. Drops the
  `fixed` group, `@sandbox/*` ignore, and the peer-dependent experimental
  flag — all of which only apply once the packages/sandbox exist.
- knip.config.ts — drop the now-redundant `build` ignoreBinaries (it
  resolves to a real script now); keep the scaffold-templates ignore.
- .oxfmtrc.json — also ignore **/dist/** build output.
- CONTRIBUTING.md — apply a pending oxfmt table-alignment fix so
  format:check is green.

All seven ci.yml jobs (build, test:ci, typecheck, lint, format, knip,
changeset status) pass locally.
@ivanbanov ivanbanov changed the title feat: add pnpm scaffold for generating primitive packages feat: scaffold script + repo build/test/release tooling Jul 15, 2026
ivanbanov and others added 6 commits July 15, 2026 14:16
ci-setup pinned pnpm 10.20.0 while package.json's packageManager is
pnpm@11.10.0; pnpm/action-setup@v4 aborts with ERR_PNPM_BAD_PM_VERSION
when both are set and disagree, failing every CI job at setup. Drop the
explicit version so package.json is the single source of truth.
Resolve conflicts in package.json (keep scaffold + storybook scripts),
tsconfig.json (keep @dunky-dev/core path mapping), and regenerate
pnpm-lock.yaml. Rename scaffold template SPECS.md files to SPEC.md and
update all references.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Core is substrate-free — the dependency runs substrate -> core, not the
reverse. Drop the concrete @dunky.dev/dom-__name__ and
@dunky.dev/react-__name__ links from the core README and types.ts,
keeping only the generic driver-contract language that describes core's
own boundary.

Bypassing pre-commit: both oxlint and oxfmt exclude scripts/templates/**,
so a template-only change leaves the hook with no files to act on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Core is substrate-agnostic; DOM is just one substrate. Generalize the
two remaining DOM mentions ("no DOM, no framework" -> "no substrate, no
framework"; "all DOM/native event reading" -> "all event reading"). The
dom package keeps DOM wording — it is the DOM driver.

Bypassing pre-commit: oxlint/oxfmt exclude scripts/templates/**, so a
template-only change leaves the hook with no files to act on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Unwrap the `full` kind: templates now live in scripts/templates/packages
  and the command is `pnpm scaffold <name>` (one template set, so no kind
  selector). Functionality unchanged — still generates the full set.
- Adopt the design-system SPEC.md format in the core template (Reference,
  Overview, Anatomy, Behavior, States, A11y, Constraints, Design); the react
  substrate SPEC now just references the core one.
- Drop the dom substrate. React binds the core machine directly: the hook
  owns the element listeners and translates DOM events into machine events
  (ported from the old dom driver), depending on @dunky.dev/state-machine
  instead of @dunky.dev/dom-__name__.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ARCHITECTURE.md now documents the core/substrate model: the packages/
grid (one behavior package per primitive in core, one binding per
substrate), the dependency direction (state-machine -> core -> substrate
-> consumer), the per-primitive anatomy, spec placement, and root vs
substrate infra ownership.

SPEC templates: the core SPEC carries the behavior contract (Reference,
Overview, Anatomy, Behavior, States, A11y, Constraints, Design); the
substrate SPEC covers only its own surface (docs link, install, usage,
API) and defers behavior to the core spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant