build: bump @gjsify/* to 0.48.0 - #181
Merged
Merged
Conversation
The tree declared three ranges of one toolchain — ^0.10.0, ^0.14.0 and ^0.16.3 across ten manifests — which gjsify's installer resolves into a single hoisted slot, so every workspace built against whichever one happened to win. All 20 declarations are now ^0.48.0 and the lockfile holds one version: 142 top-level @gjsify packages, all 0.48.0. The lockfile also moves from format 2 to 4, which 0.48.0 writes; an older CLI cannot read it, which is why the vendored Flatpak bundle and gjsify-sources.json are re-cut in the same commit. Adwaita moved its widget classes into Adw/Gtk namespaces, matching the GNOME names the web and Android twins already mirror in their own comments. That is 18 classes in app-web and 17 in app-android, plus three renames the compiler cannot see: AdwComboRow's `items` attribute became `model` (an unknown attribute is ignored, so the hex monitor's region list rendered EMPTY), GtkMenuButton's `menuItems` became `menuModel`, and AdwViewSwitcherBar's `revealed` lost its setter in favour of `reveal` — measured in a browser, `revealed` is now {get: true, set: false} and assigning it from a module throws "TypeError: Cannot set property revealed". app-web drives that line on every mobile layout switch. app-gnome's @Girs pins moved to 4.6.0, the flat generator versioning that @gjsify/storybook 0.48.0 depends on. The old 1.10.0-4.0.4 scheme left a second copy of every ambient .d.ts under storybook's node_modules and 119 duplicate global declarations with it. It also gains `gjsify.app: "gjs"`: `--app` lost its hard default in gjsify 0.19.0 and now follows the host runtime, so `build:gjs` (which passes no --app) produced a Node bundle carrying a GJS shebang whenever a Node-hosted CLI ran it — silently, since nothing errors. Measured with the project's own node_modules/.bin/gjsify 0.48.0. Type errors: app-web 31 -> 0, app-gnome 119 -> 0, app-android 25 -> 0. All 14 gates green. Exercised, not just compiled: the headless CLI assembles stack-example to the expected 24 bytes and simulates snake to completion in 15473 steps; the web bundle loads in headless Chrome with every custom element upgraded, the combo row carrying its 7 real options, and zero console errors or uncaught exceptions; the GNOME app builds and starts on Wayland through all four views. Five app-android call sites go through a documented `asView` helper. Two @gjsify/adwaita-nativescript widgets redeclare a member NativeScript's View already owns — AdwClamp's private `_measuredWidth` and AdwNavigationView's narrowing of the public `Observable._emit` — so they are not assignable to View. Both are type-only and belong upstream; the helper names them and is meant to be deleted on the next bump. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
Every workflow bootstrapped @gjsify/cli@^0.8.0 globally and then called bare `gjsify` for all of format, lint, the builds and the type checks. Nothing after the install step used the CLI the tree resolves, so CI measured 0.8.x while a developer measured 0.16.3 and the Flatpak build measured the vendored 0.10.0 — three toolchains, one green badge. The badge was not wrong about 0.8.x; it was silent about everything else, and `gjsify format --check` and `gjsify lint` in fact CRASHED on the pinned CLI (a yargs "unknown arguments" error, with lint then hanging forever) from 0.16.3 until the fix in 0.16.4. ci.yml and deploy-pages.yml now prepend the workspace bin to GITHUB_PATH after install, the step issue-to-pr.yml already had, and every bootstrap pin is exact 0.48.0 rather than a floating caret. A PATH step is silent when it fails to take effect and a CLI that merely runs proves nothing about which one it is, so both jobs also assert that `gjsify --version` equals the version in node_modules/@gjsify/cli — the drift becomes an error message instead of a number nobody reads. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
The "package scripts must be a chain" rule cited a measurement on the CLI this repo pinned at the time (0.16.3), and that pin has just moved. The defect it describes — a single-command script body dispatched in-process, then exiting with a `process.exitCode` its commands never set — was fixed upstream in gjsify 0.23.0. Re-measured here on 0.48.0: a script whose whole body is `gjsify run <throwing bundle>` exits 1, and app-web's single-command `build:app` propagated a failing bundle as exit 1. The rule stays, and so does the incident behind it (issue #180, the catalog check that reported "All translations passed" over catalogs it had emptied) — a rule stripped of its reason gets simplified back into the bug, and the residual hole is narrower rather than closed: a dispatched command that neither throws nor sets process.exitCode still yields 0. Also: bare `gjsify format` writes since 0.29.0 (`--write` defaults to true), so the pre-commit line said "check" for a step that edits files. And the package table listed two vite plugins as local packages long after they moved to @gjsify/*, omitted packages/cli entirely, and still credited app-web to Jekyll, which its own section says was removed. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
Both failures came out of the first CI run on this branch, and neither was visible from a local checkout. The Fedora jobs run a bare `fedora:43` that installs `git tar xz findutils gjs`. @gjsify/rolldown-native 0.48.0's typelib now pulls libjson-glib-1.0.so.0 and libsoup-3.0.so.0, and neither is in that image — measured by running the workflow's own prereq line in a container: of the seven libraries the native prebuilds need, exactly those two are missing. GJS reports it as a GIRepository warning and then "Unsupported type void", which reads like a translation-catalog failure because that is the first step that loads the bundler. Added json-glib + libsoup3 to all four Fedora workflows. A developer does not see this: a GNOME desktop already has both. The Flatpak build assembled app-gnome without its dependencies. meson asked for them with `gjsify workspace @learn6502/app-gnome build --with-dependencies`, but `collectTransitiveClosure` only follows deps whose spec starts with `workspace:`, and this monorepo declares its internal deps as plain `^x.y.z` ranges on purpose (pnpm-workspace.yaml explains why). So the flag matched nothing, built nothing, reported nothing and exited 0 — and `gjsify build --app gjs` then aborted on `@learn6502/core` and learn's two generated `.ui` files as unresolved bare specifiers. Reproduced locally from a clean tree, with both flag spellings and with --include-dev. meson now spells out core -> examples -> learn, the order the CI workflows already use; verified from clean, the chain exits 0 and produces the same 784530-byte executable. Worth recording: app-web's build has the same missing-dependency condition and exits 0 anyway, emitting a bundle 91 KB smaller than the correct one, because only `--app gjs` treats an unresolved bare specifier as fatal. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
The second CI run got past the catalogs and died building @learn6502/learn: "Requiring Pango, version 1.0: Typelib file for namespace 'Pango' not found". Not learn's own bundle — the plugin's. The CLI auto-bundles the by-name `@mdx-js/rollup` plugin, and `bundlePluginForGjs` passes no globals policy, so that bundle is always built with `--globals auto`. Since 0.48.0 auto sees HTMLCanvasElement, document and navigator in the plugin's graph and injects GTK-backed registers, leaving a bundle that demands Pango, PangoCairo, Gdk and GdkPixbuf at import. learn's own `--globals node` scopes learn's bundle and never reaches the plugin's, and nothing in package.json can reach it either. Measured in a fedora:43 container: after the workflow's prereq line all four typelibs are absent, and `pango gtk4 gdk-pixbuf2` supplies all four. This gives up a property the type-check container had on purpose — it was GTK-less, and #143's follow-up specifically scoped learn's globals to keep it that way. Getting it back needs the plugin bundler to stop injecting DOM globals, or to accept a policy from the consumer; both are gjsify's to fix. The comment in the workflow says so, so this comes out again rather than settling. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
app.css says "keep in sync with the package on a widget bump", and the bump to @gjsify/adwaita-nativescript 0.48.0 did not carry it: the tracked copy was byte-identical to the 0.16.3 theme (1490 lines vs the package's 2137, verified against the 0.16.3 tarball). Nothing failed, because nothing looks at it. CI runs `app-android check`, which is `gjsify tsc --noEmit` — a stylesheet is invisible to it. What the drift actually cost, measured by intersecting the class strings in lib/esm with each sheet: 19 classes the 0.48.0 widgets emit have a rule upstream and none in the tracked copy. One of them is rendered by this app — `.adw-preferences-group-header` (+ `.single-line`), which the five Adw.PreferencesGroup instances build. 0.48.0 moved the header metrics off `.adw-preferences-group-title` (now `margin: 0`) onto that wrapper, so with the old sheet the wrapper gets no margin and no 34 DIP single-line floor. The other 18 (drop-down, entry, data-grid, shortcut-label, sidebar edges, badges) are latent: no widget in this app draws them today. The reverse direction is safe. The two removed declarations are inert here: `padding-*: var(--safeAreaInsetTop/Bottom, 0)` never resolved (the NS CSS subset has no custom properties; AdwToolbarView applies the real inset itself since gjsify #1128), and `.adw-wrap-box`'s margin belongs to a widget this app does not use. Not verified: no Android device or emulator here, so this is the package's own shipped theme taken as authored, not a rendering test. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
The table still credited app-android to "Material Design 3". #156/#157 ported that app to native Adwaita widgets and dropped Material: its package.json depends on @gjsify/adwaita-nativescript and on no Material package, app.ts calls registerAdwaita(), and every `Material` left in the tree is a comment describing what was replaced. The same commit that fixed the app-web row (Jekyll -> `@gjsify/adwaita-web`) left this one, so the file kept sending readers to a toolkit the app has not used for two releases. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
The learn build needs Pango/Gdk/GdkPixbuf typelibs since 0.48.0, and this PR added `pango gtk4 gdk-pixbuf2` to ci.yml and deploy-pages.yml but not here — while issue-to-pr.yml runs `gjsify workspace @learn6502/learn build` in the same bare fedora:43 image, at its "Type check the generated example" step. Nothing on a PR can see it: this workflow is issue-triggered, so all three PR checks stay green and the break surfaces on the next example submission instead. Reproduced in fedora:43 with exactly the old prereq line plus Node 24: core and examples build, then learn exits 1 with gjsify config: failed to import the GJS bundle for plugin "@mdx-js/rollup" ... (Requiring Pango, version 1.0: Typelib file for namespace 'Pango', version '1.0' not found) package-managers.yml needs no change — it builds only `@learn6502/core` and type-checks common-ui, which its own comment already scopes as "gjs only, no GTK build deps". Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
JumpLink
added a commit
to gjsify/workspace
that referenced
this pull request
Sep 5, 2026
JumpLink/Learn6502#181 landed: `@gjsify/*` 0.16.3 → 0.48.0 across ten manifests, `@girs/*` pinned at 4.6.0, and all four CLI bootstraps pinned exactly to 0.48.0 (they were `^0.8.0` / `^0.10.0`, so CI had been measuring a different toolchain than local work did). The independent review round found three defects none of the three green checks could see: - `issue-to-pr.yml` never got the `pango gtk4 gdk-pixbuf2` prerequisites the bump added to the other two workflows, and runs in the same bare `fedora:43`. It is issue-triggered, so it would have broken on the next example submission, where no PR check looks. Reproduced in a container, then fixed. - `packages/app-android/app/adwaita.css` was still the 0.16.3 theme while the widgets shipped 0.48.0 — 19 emitted classes had a rule upstream and none in the vendored copy. `check` there is `tsc --noEmit`, which cannot see a stylesheet. - `AGENTS.md` still credited app-android to Material Design 3, dropped in #156. The element-versus-class rename trap was checked explicitly rather than assumed: the four removed `adw-*` tags have zero references in the tree, and the CSS classes did not move with the tags — the shipped widgets still emit `adw-button`, so the styling is intact. Verified in headless Chrome, not by type-check. Claude-Session: https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The toolchain was 38 minors behind, and it was behind in four different places at
once.
@gjsify/*was declared as^0.10.0,^0.14.0and^0.16.3across tenmanifests; CI bootstrapped
^0.8.0globally and then called baregjsifyforevery step; and the Flatpak build ran a vendored bundle last cut at 0.10.0. One
green badge, four toolchains, and none of them the one a developer runs.
All of it now says 0.48.0.
What the bump broke, and what fixes it
Adwaita namespaced its widget classes.
AdwButtonisGtk.Button,AdwClampisAdw.Clamp, and so on — the GNOME names the web and Android twinsalready used in their own comments. 18 classes in app-web, 17 in app-android.
AdwCard,AdwBottomSheetContent,AdwBottomSheetSheetandAdwSourceViewstay flat.
Three renames the compiler cannot see. These are the ones worth reviewing:
AdwComboRowattributeitemsmodelGtkMenuButton.menuItemsmenuModelAdwViewSwitcherBar.revealed =.reveal =revealedis now{get: true, set: false}; assigning it from a module throwsTypeError: Cannot set property revealed. app-web drives that line on every mobile layout switch.@girshad moved to flat versioning. app-gnome pinned the old1.10.0-4.0.4scheme while@gjsify/storybook@0.48.0depends on4.6.0, so asecond copy of every ambient
.d.tslanded under storybook'snode_modules—119 duplicate global declarations. All 12 pins are now
4.6.0.--applost its hard default in gjsify 0.19.0 and follows the host runtimeinstead. app-gnome's
build:gjspasses no--app, so a Node-hosted CLI wouldwrite a Node bundle carrying a GJS shebang, with no error. Fixed by declaring
gjsify.app: "gjs".The lockfile format moved 2 → 4. An older CLI cannot read v4, which is why
build-aux/gjsify.gjs.mjsis re-vendored andgjsify-sources.jsonregeneratedin the same commit — its 168
@gjsifytarballs across three versions are now 136at 0.48.0. Without that the Flatpak leg of this very PR could not build.
The CI pin
ci.ymlanddeploy-pages.ymlbootstrapped@gjsify/cli@^0.8.0and neverswitched to the workspace copy, so
format,lint, the builds and the typechecks all ran the bootstrap. They now prepend the workspace bin to
GITHUB_PATHafter install — the stepissue-to-pr.ymlalready had — and everybootstrap pin is exact.
A PATH step is silent when it fails to take effect, so both jobs also assert
gjsify --versionequals the version innode_modules/@gjsify/cli. Driftbecomes an error message rather than a number nobody reads.
This mattered more than a version skew: on the pinned 0.16.3,
gjsify format --checkandgjsify lintcrash with a yargs "unknown arguments"error, and
lintthen hangs forever (killed after 632 s). Upstream fixed it in0.16.4 — the next patch after the pin. Nobody noticed because CI ran 0.8.x.
Three failures only CI could show
The first CI run on this branch went red in both container jobs, and neither was
reproducible from a local checkout. Both are fixed here.
The Fedora image is missing two libraries the new native bundler needs.
@gjsify/rolldown-native0.48.0's typelib pullslibjson-glib-1.0.so.0andlibsoup-3.0.so.0; barefedora:43plus the workflow's owngit tar xz findutils gjshas neither. Measured by running that prereq line in acontainer: of the seven libraries the native prebuilds need, exactly those two
are absent. GJS surfaces it as a GIRepository warning followed by
Unsupported type void, attributed to whichever step first loads the bundler —here "Validate translation catalogs", which has nothing to do with it. A GNOME
desktop already has both, which is why every local run was green.
--with-dependenciessilently builds nothing in this repo. The Flatpak buildasked meson for
gjsify workspace @learn6502/app-gnome build --with-dependencies,but
collectTransitiveClosureonly follows deps whose spec starts withworkspace:, and this monorepo declares its internal deps as plain^x.y.zranges deliberately (
pnpm-workspace.yamlsays why). The flag matched nothing,built nothing, printed nothing and exited 0 — then
gjsify build --app gjsaborted on
@learn6502/coreand learn's two generated.uifiles. Reproducedlocally from a clean tree with both flag spellings and
--include-dev. meson nowspells out
core -> examples -> learn, the order the workflows already use;from clean that chain exits 0 and produces the same 784530-byte executable.
The
learnbuild now needs GTK typelibs in a container that had none. TheCLI auto-bundles the by-name
@mdx-js/rollupplugin, andbundlePluginForGjspasses no globals policy — that bundle is always
--globals auto, which since0.48.0 sees
HTMLCanvasElement/document/navigatorin the plugin's graph andinjects GTK-backed registers. The result demands Pango, PangoCairo, Gdk and
GdkPixbuf at import. learn's own
--globals nodescopes learn's bundle, not theplugin's, and nothing in
package.jsoncan reach it. Measured in a container:all four typelibs absent after the prereq line, all four supplied by
pango gtk4 gdk-pixbuf2. This gives up a property the type-check container hadon purpose (#143's follow-up scoped learn's globals precisely to keep it
GTK-less) — getting it back is a gjsify fix, and the workflow comment says so.
A related sharp edge, recorded but not fixed here: app-web's build hits the same
missing-dependency condition and exits 0 anyway, emitting a bundle 91 KB
smaller than the correct one, because only
--app gjstreats an unresolved barespecifier as fatal.
Measured
Every command run with
node_modules/.bin/gjsify0.48.0, never the one onPATH. Type-error counts are re-derived, not carried over.format --checklintworkspace core buildworkspace examples buildworkspace learn buildworkspace translations checkworkspace learn checkworkspace core checkworkspace common-ui checkworkspace app-web checkworkspace app-gnome check:typescriptworkspace app-android checkworkspace cli checkworkspace app-web build:appgjsify install --immutablesucceeds and leaves the lockfile untouched, which iswhat CI runs.
And CI agrees, on its own hardware: Code Quality 39s, Type check (GJS 1.86)
3m9s, Flatpak Build 3m18s — all green. Both container jobs print the line the
new assert exists for:
That is the workspace copy, not the global bootstrap — the first time this
repository's CI can show which toolchain it measured. The Flatpak leg installs
the executable, gresource, metainfo, schemas and icons, exports the repo and
emits a real
eu.jumplink.Learn6502-x86_64.flatpak.zip.Exercised, not just compiled
A green typecheck cannot see a bundle that builds and does nothing.
stack-exampleto the expected 24 bytes, emitsthe correct disassembly, and simulates
snaketo completion in 15473steps.
app.js(1.04 MB) loads with every customelement upgraded (toolbar view, view stack, source view ×32, combo row, split
view, 5 clamps), zero console errors and zero uncaught exceptions. The
combo row carries its 7 real options, which is the
items→modelfixproving itself. At a 420×780 viewport the mobile branch runs and the switcher
bar reports
reveal: true.schemas, and starts on Wayland through all four views with no exceptions. The
gettext plugin still emits 928 translated entries across 14 languages.
Deliberately left open
@gjsify/adwaita-nativescript@0.48.0.AdwClampdeclares
private _measuredWidth, whichViewCommonalready declaresprivate;
AdwNavigationViewnarrows the publicObservable._emitto private.Either makes the widget non-assignable to
View. Both are type-only — theruntime objects are real NativeScript views. Five call sites go through a
documented
asViewhelper (packages/app-android/app/utils/as-view.ts) thatnames both and is meant to be deleted once the fix ships. This belongs in a
gjsify PR and is not opened here.
@learn6502/translationsdoes regenerate them (the POT grows 457 → 461 msgids, no catalog shrinks), but
that is Translations: catalogs and Android i18n lag the sources #179's lag closing and it wants translator review, not a toolchain
bump. Reverted here.
either stop injecting DOM globals or take a policy from the consumer; until
then
pango gtk4 gdk-pixbuf2stay in the workflow.gjsify workspace --with-dependenciesis effectively dead for this repountil it stops requiring the
workspace:protocol, or the repo adopts thatprotocol. The meson call site no longer depends on it; nothing else used it.
gjsify lintneeds a realnodeonPATHunder GJS — oxlint has nonative bridge. CI's lint job is on ubuntu with Node, so this is fine today.
status was closed in gjsify 0.23.0. Re-measured on 0.48.0: a single-command
script body wrapping a throwing bundle exits 1, and app-web's
build:apppropagated a failing bundle as exit 1.
AGENTS.mdrecords the re-measurementand keeps the chains — the residual hole (a command that neither throws nor
sets
process.exitCode) is narrower, not closed.AGENTS.mdalso drops two vite plugins that stopped being local packages, addspackages/cli, and stops crediting app-web to Jekyll.🤖 Generated with Claude Code
https://claude.ai/code/session_01YQ87zT8bbwAhB1Hn264Krx