A version written into a manifest is written into every manifest that wants it,
which is how eslint came to exist in a hundred and four forms across this estate
and how a package came to resolve twice at run time. The catalog moves the number
out of the manifest: a manifest names the package, the workspace names the
version.
Four are held below their latest because the newer release cannot be used, and
the reason is recorded rather than the version alone: @noble/hashes 2 renamed
every subpath the web3 stack imports, @splinetool/runtime 2 depends on a package
that was never published, @dynamic-labs 5.4.1 the same, and react-resizable-panels
3 points its types condition at the bundle.
Co-authored-by: Hanzo Dev <[email protected]>
Every dependency on a @hanzo/@luxfi/@zooai package now names the same version
across the repo: a catalog entry where pnpm supports one, an exact pin where it
does not, and a range only where a peer genuinely means one.
pnpm itself is pinned too — the estate ran eighteen different versions, five of
them too old to read a catalog.
Co-authored-by: Hanzo Dev <[email protected]>
One app carried the Hanzo shell and twenty did not, so a reader crossing from
base.hanzo.ai to zen.hanzo.ai left the ecosystem and landed somewhere that only
resembled it. Five of those twenty had hand-rolled a footer of their own —
sixteen lines of copyright and a repo link, written five separate times.
Each app now loads the brand tokens before its own sheet, reports through
docs-analytics under its own product name, and renders HanzoFooter from
@hanzogui/shell — the same 6-column ecosystem footer, defined once, that
apps/docs already used.
A footer written inside a layout was chrome pretending to be content, and it is
gone. A footer written inside a page is content pretending to be chrome: those
keep their words and become sections, so each page has one contentinfo landmark
instead of two.
Three manifests listed @hanzo/font twice in the same object.
Builds verified across the four shapes this repo has: a static export, a
next.config.mjs app, a single-page app with no route groups, and one that
already reported analytics. Every one renders exactly one footer.
Co-authored-by: Hanzo Dev <[email protected]>
Thirteen shipped apps and every scaffold in packages/create-app pulled their
face from Google at request time — Inter through next/font/google in the
examples and the four Next templates, Geist and Geist_Mono in the apps, and in
the seven react-router roots a bare <link> to fonts.googleapis.com. That last
one never even applied what it fetched: nothing in those trees set a family, so
the browser downloaded Inter, spent two preconnects on it, and rendered
system-ui. So `create-app` handed a customer a new docs site whose first act was
a third-party font request for a face that is not ours.
The apps read the family back through --font-sans and --font-mono, which are
next/font's handles rather than names of anything, so those follow the binding
over to --font-zen-sans and --font-zen-mono. Eight of them had only ever bound
the mono and were leaning on Tailwind's default for the text face; they now name
both, or swapping the binding would have dropped the body copy to system-ui
without a word.
Zen and ZenMono are built faces, not constructors — subsetting, display: swap
and fallback metrics are already in them — so the call and its options go away.
Twelve example layouts imported `ZenSans` from `@hanzo/font/sans`, a name
the package stopped exporting at 1.9.0 — the family is called Zen, so the
binding is `Zen`. Every one of those layouts would fail to resolve the
import against a current install, and the `^1.8.x` ranges they pinned kept
resolving to the old export instead of surfacing it.
Three things the workspace disagreed with itself about.
Versions. apps/docs ran ahead on next 16.2.6 / react 19.2.6 / TS 6, the other
21 apps trailed on next 16.1.6 / react 19.2.3 / TS 5.9.3, and the packages sat
somewhere between with five different @types/react pins. Everything is now on
the newest patch of the line it was already on — react 19.2.8, next 16.2.12,
@types/react 19.2.18, @types/react-dom 19.2.4 — and the TS-5 stragglers join
the TS 6.0.3 the root and every package already used. No majors were invented:
6.0.3 IS the top of the 6.x line, and TS 7 is blocked because [email protected]
declares `typescript: ^5.5.0 || ^6.0.0`.
The duplicate key. next.config.mts declared `transpilePackages` twice in one
object literal, so the later list won and @hanzogui/shell and @hanzo/brand had
never been transpiled — the comment explaining why they must be outlived the
setting it described. tsc had been reporting this the whole time as
next.config.mts(193,3) TS1117; the app's `types:check` never reaches tsc (its
script starts with a bare `@hanzo/docs-mdx`, which is not the bin's name and
fails immediately), so nobody saw it. One list now, both groups in it.
Dead weight. Twelve packages apps/docs declared and no file, config, script or
browserslist field referenced: @radix-ui/react-dialog, @floating-ui/react-dom,
@mixedbread/sdk, @orama/orama, openapi-sampler, react-remove-scroll,
algoliasearch, gray-matter, tinyexec, tinyglobby, @types/three (types for a
package that isn't installed) and shadcn (no components.json exists anywhere in
the repo, so the CLI was never initialized). The ones that are real
dependencies of packages/openapi, packages/core and packages/cli keep their own
copies — pnpm's node_modules is isolated, so nothing lost a resolution.
@orama/core stays: apps/docs/app/static.json/route.ts pulls OramaDocument
through @hanzo/docs-core/search/orama-cloud, which types against it.
Verified against a clean worktree at HEAD, since the working tree carries
gigabytes of untracked synced project docs that CI never checks out:
turbo build, apps + packages 43/52 before, 43/52 after, same 9 failures
docs export 1764 html pages, byte-identical page count
deploy.yml gate index/docs/services present, /docs has nav
tsc --noEmit in apps/docs 325 errors before, 324 after (the TS1117)
vitest 169 passed / 13 failed, both sides
The 9 build failures and 13 test failures are unchanged from HEAD and none are
version-related: 7 sibling apps cannot resolve @hanzo/mdx:collections/server
under `next build --webpack`, zen-docs has a committed docs/server.ts importing
a deleted zen5-coder-flash.mdx, and packages/preview cannot resolve its own
@/lib/source alias under waku/vite.
Co-authored-by: Hanzo Dev <[email protected]>
The fumadocs-fork rebrand left ~13 apps + examples referencing packages under
names that don't exist in the workspace (in BOTH directions: some kept
fumadocs-*, some became @hanzo/docs-*). pnpm install failed outright. Mapped
every reference (deps + imports, 607 source + 61 package.json) to the package
that actually exists, by suffix:
@hanzo/docs-{core,mdx,ui,base-ui} → fumadocs-{core,mdx,ui} / @fumadocs/base-ui
@fumadocs/{story,cli,mdx-remote,tailwind} → @hanzo/docs-{story,cli,...}
fumadocs-{docgen,epub,twoslash,typescript} → @hanzo/docs-{...}
drop phantom eslint-config-custom
Guarded @hanzo/docs-mdx vs -mdx-remote. Also fixes a pre-existing cli bug
(createConfigSchema referenced undefined isSrc) that blocked the package build.
Verified: pnpm install resolves clean (46.8s, was broken); package dist
regenerates phantom-free from the corrected source (hanzo-docs 430→0). Full
app build-green is blocked only by a node v26 toolchain bug in fumadocs-mdx's
config loader (repo targets node >=24.14; CI node builds it).