Skip to content

chore(toolchain): standardize Node.js 24 and pnpm 12 across active repositories #38

Closed

Description

@ClaudiaFang

Goal

Standardize active firstsun-dev JavaScript/TypeScript projects on Node.js 24 for CI/build and pnpm 12.14.0 (exact pin), preserving runtime compatibility, release safety and current tests. Keep independent from Cloudflare Worker CI/CD v2.

Initial inventory (re-audit at execution)

  • Existing pnpm: blog, heaven-monorepo, innovation-apps, anas-mcp, content-core, heaven-www, code-insights.
  • npm candidates: git-files-sync, watermark-bucket-uploader, obsidian-plugin-template, news-getter (astro-src), kilo-plugin-smart-web, agent-mcp (openhands-mcp). Audit consumer/release compatibility before converting.
  • Inspect newly active projects and pending PRs (such as firstsun-bot PR ci: Remove SonarQube, update Node versions, and enhance build summary #2), nested packages, and each repo's default branch. Exclude archives, empty repos, and unrelated Python/Terraform/Windmill projects.

Related existing work

  • Migrate GitHub Actions off Node 20 runtimes #29 covers GitHub Actions Node 20 action-runtime migration; coordinate but do not conflate it with the build/runtime baseline.
  • firstsun-dev/heaven-monorepo#49 covers Docker pnpm@latest / lockfile mismatch; resolve its exact scope during the pnpm pinning migration.

Requirements

  1. Audit existing Issues and PRs per repository before changing anything; reuse/update applicable Issues and create only missing per-repo tracking Issues.
  2. Create one dedicated branch and one PR per applicable repository, based on its actual default branch. Suggested branch: chore/node24-pnpm12. Do not auto-merge or deploy.
  3. Pin pnpm@12.14.0 consistently in packageManager and any CI/Docker bootstrap. Use Node 24 for CI/build; retain lower published runtime Node engine ranges where necessary and test them.
  4. Migrate pnpm 10/11 config: package.json pnpm settings / overrides, pnpm-workspace.yaml, .npmrc non-auth configuration, allowBuilds, catalogs, and lockfile. Preserve security overrides and dependency script safety.
  5. Update all npm candidates' CI/cache/install/release/packaging instructions and Dockerfiles only after compatibility testing; preserve existing consumer install behavior and release provenance.
  6. Verify cold/frozen installs, lint, typecheck, build, unit, integration, E2E, native dependency builds, Docker and publish/pack dry-run where applicable; do not hide, skip, or downgrade failing checks.
  7. Verify self-hosted runner Node 24 with pnpm 12 via Corepack or supported official installer; extend runner-image smoke test. Runner fleet rollout remains explicitly gated.
  8. Keep Cloudflare Previews/Hybrid v2 and unrelated dependency upgrades outside toolchain PRs.
  9. Push each completed branch, open its PR with issue link, exact validation evidence and CI links. Treat push as ready for review, not CI pass. Do not merge until CI is checked.
  10. Maintain a linked per-repo checklist here; close per-repo Issues only after merged PRs, and this Issue only when all agreed in-scope migrations are complete.

Acceptance

  • All applicable active JS/TS repositories have Node 24 CI/build baseline and identical exact pnpm 12 pin, or documented justified exceptions.
  • Every applicable frozen-lockfile install, test, build, Docker/publish workflow passes on the relevant runner/platform.
  • Existing shared workflows, monorepo dependencies, package publishers, and consumers continue to work.
  • Changes remain independently reviewable and reversible per repository.

Activity

  1. ClaudiaFang commented on Oct 19, 2026

    @ClaudiaFang
    MemberAuthor

    Migration status (Node.js 24 + pnpm 12.14.0)

    Status as of 2026-10-19. Every repo has its own Issue + PR; nothing was auto-merged by tooling. Install = clean rm -rf node_modules && pnpm install --frozen-lockfile with pnpm 12.14.0 (passes in every worktree).

    Stage 1 — shared infrastructure

    • .github — #39 · PR #40 merged; tags v1.6.0 + floating v1 moved to the merge commit. Obsidian shared workflows now pnpm-aware (npm fallback kept); actions/setup unchanged (already Node 24, reads packageManager).
    • infra-config — #94 · PR #95 — runner-image smoke test now asserts pnpm 12.14.0 (+11/10 pins via Corepack); no fleet rebuild, rollout gate untouched. No CI on the repo; not exercised on a real image build.

    Stage 2 — existing pnpm repos

    • anas-mcp — #26 · PR #27 — pnpm 10.33.0 → 12.14.0. CI pass. Lockfile refresh included.
    • content-core — #1 · PR #2 — pnpm 10.0.0 → 12.14.0, CI Node 24. CI pass. Lockfile refresh included.
    • heaven-www — #46 · PR #47 — pnpm 11.17.0 → 12.14.0. Lint/typecheck/build + CodeQL pass; deploy-pipeline jobs skipped on PR. Lockfile refresh included.
    • innovation-apps — #74 · PR #75 — pnpm 10.33.0 → 12.14.0. Only CodeQL ran (app workflows are path-filtered; will first run on next app change or workflow_dispatch). Lockfile refresh included.
    • code-insights — #29 · PR #30 — unpinned (CI pnpm 9 / Docker pnpm 10.33.0) → 12.14.0, Docker Node 22 → 24, docker build verified. CI pass. Lockfile refresh included.
    • blog — #446 · PR #447 merged 2026-10-19 08:40; PR checks all passed. Post-merge main CI/CD was still running when this was written — verify before treating as complete. Lockfile refresh NOT applied (wrangler/vite-plugin/miniflare need a coordinated bump → separate PR). Container images still need a rebuild/push to pick up Node 24 + pnpm 12.
    • heaven-monorepo — #52 · PR #53 (Refs docs(openspec): correct CI/CD v2 spec (owner decisions + pilot findings) #49, not closed) — pnpm 10.33.0 → 12.14.0; 6 Dockerfiles pinned to 12.14.0 (no pnpm@latest), all build on amd64. pull_request run green after clearing a stale /cache/pnpm-store entry (see risks). Lockfile refresh NOT applied (@hono/zod-openapi 1.2.2→1.6.3 breaks api-009-user 400→415).

    Stage 3 — npm → pnpm

    • git-files-sync — #163 · PR #164 — npm → 12.14.0. Latest run green (lint, build, unit 22/24, e2e gitea/github/gitlab, Release/Package). Pre-refresh main.js byte-identical to npm baseline; after the lockfile-refresh commit main.js differs (ignore 7.0.6→7.0.12) — revert that commit if byte-identical artifacts are required. Conflicts expected with #157/#160.
    • watermark-bucket-uploader — #29 · PR #30 — npm → 12.14.0. New run against merged chore(ci): pnpm-aware shared Obsidian workflows, Node 24 default #40 passes (lint, Node 22/24 tests, package artifact). main.js is NOT byte-identical to the npm baseline (re-resolved transitives: @smithy/types, undici, semver). Lockfile refresh NOT applied (TS 5.9 / obsidian 1.14 break typecheck + lint → needs source fixes). Dependabot fix(ci): reach Postgres service via job container network #28 needs rebase.
    • obsidian-plugin-template — #1 · PR #2 — npm (no lockfile) → 12.14.0. main.js byte-identical to npm baseline. Package Artifact now passes; Lint and Test jobs still fail — template defects that fail identically on the npm baseline (no eslint config, missing tslib, no tests). Also fixes id-token: write / stray \${{ in ci.yml.
    • news-getter (astro-src) — #4 · PR #5 — npm → 12.14.0, build output identical (251 pages). No CI runs on PRs (only on push to main). TypeScript 7 held back by lockfile (>= range would float to it).
    • kilo-plugin-smart-web — #1 · PR #2 (base develop) — npm → 12.14.0, engines.node >=20 kept. No CI, no tests (smoke only); refresh bumps @kilocode/plugin 7.4.11→7.8.12 — try in Kilo before merging.
    • agent-mcp (openhands-mcp) — #5 · PR #6 — npm → 12.14.0, Dockerfile node:24-alpine, 60/60 tests, docker build + /healthz OK, dist/ byte-identical. No CI in repo. engines.node raised to >=24 (private service).
    • firstsun-bot — #4 — no migration PR: main has no JS yet; asked scaffold PR #2 to adopt Node 24 + pnpm 12.14.0.

    Excluded

    status-page, windmill-flows, obsidian-sync-test (no JS/TS package); skills (two tiny nutritional-specialist package.json only); firstsun-core, git-files-sync-e2e, kestra-flows (empty); obsidian-releases, general-workflows (archived); Python/Terraform-only repos.

    Open risks

    1. Shared runner pnpm store: /cache/pnpm-store (host bind mount on gitlabci-01, shared by 10 runners) produced ERR_PNPM_BROKEN_PNPM_INSTALL (missing @pnpm/exe.linux-x64/bin/pnpm.mjs) when jobs switch pnpm 11 → 12. git-files-sync traced it to parallel jobs racing on the shared store (fixed there with a per-leg store under $RUNNER_TEMP); heaven-monorepo recovered after the stale entry was removed. Not fixed at the source — actions/setup@v1 + setup-pnpm: true on any pnpm-12 repo can hit it again. Store ownership (permission denied removing as tianyao) suggests a uid mismatch worth a follow-up in infra-config.
    2. Rerun gotcha: re-running a workflow reuses the called shared-workflow commit of the original run; consumers of chore(ci): pnpm-aware shared Obsidian workflows, Node 24 default #40 needed a fresh run (close/reopen) to pick it up.
    3. Lockfile refreshes are separate, individually revertable commits; refresh was skipped (reverted) for blog, heaven-monorepo and watermark-bucket-uploader because of genuine regressions listed above.
    4. Container images (blog, heaven-monorepo e2e/GitLab node image 22-slim-build) need rebuilding before they carry Node 24 + pnpm 12.

    Close each per-repo issue only after its PR is merged and post-merge CI is verified; close this issue when all in-scope PRs are done.

  2. ClaudiaFang commented on Oct 20, 2026

    @ClaudiaFang
    MemberAuthor

    Update — shared pnpm store fix

    • infra-config — PR #98 (fix/runner-pnpm-store-per-runner, open, no CI on repo): each runner container gets its own host store /cache/pnpm-stores/runner-N, mounted at the unchanged /cache/pnpm-store. Template test fails on the old layout (3/4) and passes on the new one; rendered compose validates with docker compose config. Nothing applied to the host.

    Supersedes open risk #1 above (shared runner store): the fix is written but not live — it takes effect only at the gated runner rollout (github_actions_runner_rollout). Until then the shared /cache/pnpm-store can still race. Before rollout: check free disk on gitlabci-01 (df -h /cache; up to 10× one store), and afterwards delete the old shared dir with the documented throwaway-container command.

    Other updates since the checklist: .github#39 is closed (PR #40 merged, v1.6.0 + v1 tagged). obsidian-plugin-template and watermark-bucket-uploader re-ran against the merged shared workflows via close/reopen — watermark CI is green, the template's Package Artifact passes and its Lint/Test still fail on baseline template defects.

  3. ClaudiaFang commented on Oct 20, 2026

    @ClaudiaFang
    MemberAuthor

    Update — infra-config #95 deployed to the runner fleet (2026-10-20)

    • infra-config — PR #95 merged (de2d2ef) and rolled out on gitlabci-01 with github_actions_runner_rollout=true. All 10 runners were idle beforehand (no Runner.Worker), so no jobs were interrupted.
      • Playbook: ok=9 changed=2 failed=0 (image build + fleet reconcile).
      • After: 10/10 containers up; heavenweb-runner-1..10 online and idle in the org runner list.
      • Image check (runner 1 only): pnpm resolves 12.14.0 / 11.0.0 / 10.33.0 from packageManager; Node v24.20.0.
    • infra-config — PR #98 (per-runner pnpm store) is still open and not live.

    Open risk #1 (shared runner store) is unchanged: the fleet still shares /cache/pnpm-store (6.1 GB), so the pnpm 11 → 12 ERR_PNPM_BROKEN_PNPM_INSTALL race can recur until #98 is merged and rolled out. That second rollout needs up to 10× the store disk; / has 62 GB free (84% used), and the old shared dir should be deleted afterwards with the documented throwaway-container command.

  4. ClaudiaFang commented on Oct 20, 2026

    @ClaudiaFang
    MemberAuthor

    Update — shared store fixed, failed post-merge jobs recovered (2026-10-20)

    • infra-config#98 merged and rolled out on gitlabci-01 (ok=9 changed=3 failed=0): each runner now has its own pnpm store (/cache/pnpm-stores/runner-N); 10/10 runners online. The old shared /cache/pnpm-store was removed. Some jobs on 3 busy runners were interrupted (accepted beforehand). Details in the PR's Deployment section.
    • heaven-monorepo: Semantic Release re-run succeeded (release v1.1.5); the shared-store failure did not recur.
    • anas-mcp: Deploy re-run succeeded (previous failure was Cloudflare API 10500 on version activation).
    • All 14 migration PRs are merged; each PR/issue now has a post-merge record. Remaining known failures: obsidian-plugin-template Lint/Test (baseline template defects, not migration-related).
    • Still open / unverified: no soak period for per-runner stores (watch df -h / on gitlabci-01 as each runner warms its store); container images for blog / heaven-monorepo still need a rebuild to carry Node 24 + pnpm 12; blog, heaven-monorepo and watermark lockfile refreshes were skipped (regressions listed earlier); masked pnpm version error in anas-mcp; kilo-plugin-smart-web @kilocode/plugin bump untried; git-files-sync main CI was still running when last checked earlier.
  5. linked a pull request that will close this issuechore(toolchain): Node.js 24 + pnpm 12.14.0 #2on Oct 21, 2026
  6. linked a pull request that will close this issuechore(toolchain): Node.js 24 + pnpm 12.14.0 #5on Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions