Repository navigation
chore: Node 24 LTS 승격 + 런타임·패키지매니저 버전 단일 출처화 - #14
Merged
Merged
Conversation
engines said >=20.9.0, but commander@15 already required >=22.12.0 — so Node 20 could not install this package and the docs said otherwise. Node 20 also reached end of life in April. 24 is the current LTS, and going there now costs nothing while nobody depends on the old floor. The version was written in nine places with nothing keeping them in step. .nvmrc is now canonical: both workflows read it through node-version-file, and a new guard ties engines, the tsup target, the install.sh gate, and the prose in four documents back to it. The gate needed its logic changed, not just its message — a whole-major floor makes the minor term dead code that would otherwise rot. CI now activates pnpm through corepack so packageManager is the only place its version lives. Scoping that to `corepack enable pnpm` matters: the bare form also shims npm, and that shim aborts inside a repository whose packageManager is pnpm, which breaks both install.sh and the npm publish step in the release workflow.
Every GitHub Action was still on the v4 it was written with at c4f814f, three majors behind. setup-node v7 is the one that matters: actions/setup-node#531 tracks the corepack chicken-and-egg problem where cache: pnpm needs pnpm on PATH before setup-node runs, and enabling corepack that early binds pnpm to the runner's default Node on Windows, where .cmd shims resolve against their own directory. v7 is reported to make the double-setup-node workaround unnecessary. Dependencies were the same story. Eleven move; five do not, each for a reason rather than caution: TypeScript 7 reports node: specifiers as unresolved identifiers, which the same tree compiles clean under 5.9.3, and vite, plugin-react, vitest and jsdom are one coupled unit whose newest jsdom changes accessible-name computation in a way that needs test expectations rewritten, not a version bumped. eslint.config.mjs now ignores artifacts/, a gitignored scratch tree carrying its own ESLint 9 install that made ESLint 10 crash mixing two majors in one run.
Two separate Windows failures, one loud and one quiet. The loud one: git checks out LF as CRLF on Windows by default, so the .nvmrc assertion compared '24\r\n' against '24\n' and failed the job. The repository had no .gitattributes at all, so line endings were whatever each platform decided. It now pins them, and the assertion checks what nvm actually parses — one terminated line, no padding — rather than which bytes terminate it. The quiet one: Windows CI was testing on Node 22 while claiming to test 24. setup-node installed 24 correctly, but Corepack had already written its pnpm shim next to the runner's default Node, and a Windows .cmd shim resolves against its own directory rather than PATH. v7 did not change this, so the double-setup-node workaround from actions/setup-node#531 goes in: install Node, enable Corepack on it, then run setup-node again for the cache. This one only warned, so the fix is verifiable from a `node --version` line rather than from a green check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KUF3P9ehRWYZqZ1nw3BuZY
base64url includes `-` and `_`, so roughly one session id in 64 began with a character the CLI's parser treats as an option. `--session <id>` then failed with `unknown option`, and CI went red at random — twice in one afternoon, on two different tests. The leading byte is now redrawn until it lands on an alphanumeric digit. Every other position keeps the full 64-symbol alphabet and the length is unchanged, so the cost is about 0.046 bits out of 144. Auth tokens are untouched: they never reach an argument vector. The test drives create() rather than the generator, because asserting on the generator alone still passed when the call site was reverted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KUF3P9ehRWYZqZ1nw3BuZY
2 tasks
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.
무엇이 바뀌나
Node 런타임을 20(EOL) → 24 LTS 로 올리고, 런타임·패키지매니저 버전을 단일 출처로 묶는다.
engines가>=24.0.0이 되어 Node 20/22 사용자는EBADENGINE을 받고install.sh가 설치를 거부한다.배경
Closes #13
engines선언이 이미 거짓이었다의존성이 선언보다 높은 버전을 요구하고 있었다.
commander@15.0.0>=22.12.0@modelcontextprotocol/server@2.0.0>=20open@11.0.1>=20즉 Node 20 에서는 애초에 설치가 성립하지 않는데 README·
install.sh·engines가 20.9 를 안내하고 있었다. 이 PR 은 새로 제약을 거는 게 아니라 이미 틀린 광고를 바로잡는 쪽에 가깝다. 다만 npm 이EBADENGINE을 내보내는 것은 사실이므로 릴리스 노트에 명시가 필요하다.Node 20 은 EOL
22 로 가면 1년여 뒤 같은 작업을 반복한다. 릴리스 직후이고 사용자가 아직 없는 지금이 가장 싼 시점이라 24 로 갔다.
버전이 9곳에 흩어져 있었다
engines2곳, CI/release 워크플로 2곳,tsuptarget, README 영·한,getting-started,install.sh(안내 문구 + 게이트 로직)..nvmrc도.node-version도 없어 개발자 로컬은 제각각이었다.pnpm 도 이중 관리였다 —
packageManager: pnpm@10.29.3이 있는데 CI 는 그걸 안 읽고pnpm/action-setup에 따로 적었고, 문서는corepack enable을 안내하는데 CI 는 corepack 을 쓰지 않았다.#11 에서 고친 버전 하드코딩과 같은 구조의 문제다.
작업 내용
Node 24 승격
.nvmrc(신규,24) — canonical. CI·릴리스가node-version-file로 읽어 하드코딩 제거engines>=24.0.0(루트 +packages/pixel-cli)tsup.config.tstarget: "node24"install.sh— 안내 문구 및 게이트 로직.>=24.0.0은 whole major 이므로 minor 항이 죽은 코드가 되어 제거했다docs/getting-started.md,CONTRIBUTING.md,bug_report.yml갱신corepack 으로 pnpm 단일화
CI 가
pnpm/action-setup대신 corepack 을 쓴다.packageManager필드가 단일 출처가 된다.여기서 실제 버그를 하나 잡았다. 처음엔 바레
corepack enable을 썼는데test:distribution이 이렇게 실패했다:바레 형태는 npm 까지 shim 하는데, 그 shim 은
packageManager: pnpm인 저장소 안에서 실행을 거부한다. 그게install.sh의npm install --global을 깨뜨린다.corepack enable pnpm으로 스코프를 좁혀 pnpm/pnpx shim 만 만들고 npm 은 진짜를 남겼다.코드 리뷰가 이게 테스트만의 문제가 아님을 짚었다 —
release.yml:60이npm publish를 실행하므로 스코프 없는 enable 이었다면 발행 경로에도 pnpm-abort shim 이 깔렸을 것이다.문서를 CI 와 일치시킴
문서 4곳이 여전히 바레
corepack enable을 안내하고 있었다. 그대로 두면 기여자가 CI 주석이 "install.sh 를 깨뜨린다"고 명시한 바로 그 shim 을 설치하게 되고,pnpm test:distribution이 혼란스러운 에러로 실패한다. 전부corepack enable pnpm으로 바꾸고 왜 스코프가 필요한지 한 줄씩 덧붙였다.CONTRIBUTING.md:11의 sharp 잔재도 고쳤다 — #7 에서@jsquashwasm 으로 교체했으므로 네이티브 툴체인이 필요 없다는 게 오히려 장점인데 정반대로 적혀 있었다.새 가드
tests/manifests/runtime-versions.test.ts(신규, 10 tests) —.nvmrc·engines2곳·워크플로 2곳·tsuptarget·install.sh게이트·문서 Node 버전·문서 pnpm 버전을 전부 canonical 과 대조한다. 모든 비교가 디스크-대-디스크이고 파일 안에 버전 리터럴이 없다.자가체크
루프 — 1회차 구현 + 2회차 코드 리뷰 반영(4건).
코드 리뷰 — 위반 0건. corepack 스코핑·게이트 로직·tautology 수정 셋 다 소스에서 검증됐다. 개선 4건(문서 corepack 불일치, sharp 잔재, 게이트가 나중에 느슨해질 여지, 문서 pnpm 하드코딩) 전부 반영했다.
QA 감사 — pass. 10개 단언을 독립 재검증했고, vacuous pass 방어가 전 항목에 있음을 확인했다 (파일 부재 시 ENOENT throw,
engines누락 시 타입 단언 선행, 정규식 0-match 시 null 체크,matchAll은 length 먼저).QA 가
withoutComments에 대해 중요한 사실을 밝혔다:즉 구현자가 스스로 발견해 고친 tautology 는 장식이 아니라 실제 반전이었다.
테스트 — 전부 Node v24.18.1 + 진짜 npm 11.16.0 으로 실행:
pnpm verifypnpm test:distributionpnpm test:source-installpnpm test:e2e게이트 실측 — 실제 런타임 3종으로 확인:
mutation check:
engines→>=24.5.09.9.9(3파일 각각)documents pnpm 9.9.9, packageManager is 10.29.3no "pnpm x.y.z" mention to check.nvmrc를 floor 미만으로major < 20으로 두고 메시지만 갱신node-version재하드코딩 /pnpm/action-setup복구 / corepack 순서 반전 / 바레corepack enabletsuptarget 을 floor 위로전부 원복 후 green 재확인.
제거한 테스트 — 없음. 기존 기대값 수정도 없음.
로컬 환경 주의사항 (개발자용)
이 저장소를 로컬에서 검증할 때
npm이 corepack shim 인지 확인해라. 구현자와 메인 세션 모두 여기 걸려test:distribution이 한 번 실패했다.이 메시지가 나오면 진짜 npm 이 아니다. CI 는
corepack enable pnpm으로 스코프를 좁히므로 해당 없다.CI 에서 확인할 것
self-check 2건은 성격상 로컬에서 닫을 수 없다. 머지 전 CI 로그에서 아래를 확인한다.
verify (ubuntu-latest)/verify (windows-latest)둘 다 green (fail-fast: false이므로 각각 확인)pnpm --version이10.29.3출력 — 다른 값이면packageManager가 단일 출처가 아니라는 뜻actions/setup-node로그에Cache restored from key: ...pnpm...(첫 실행이면 job 끝에Cache saved with key:).Unable to locate executable file: pnpm이 뜨거나 캐시 섹션이 아예 없으면 corepack-before-setup-node 순서가 깨진 것Setup Node.js가.nvmrc를 24.x 로 해석pnpm test:distribution이 양쪽 OS 에서 통과알려진 갭 (의도적)
commander@15같은 전이 의존성이 자기 floor 를 24 위로 올리면 아무도 못 잡는다. 이번 승격을 촉발한 게 바로 그 제약인데, 다음번엔 설치 시점까지 모른다. 별도 이슈감이다..node-version파일은 만들지 않았다..nvmrc를 canonical 로 택했고 현재 이 저장소에 둘 다 없다.리뷰 포인트
engines파괴적 변경에 동의하는가.nvmrc를24(bare major)로 둔 선택이 적절한가 — 보안 패치 자동 추종 vs CI 재현성enable pnpm)이 올바른 해법인가머지 후
engines상향은 파괴적 변경이므로 1.0.4 릴리스가 필요하다. 이 PR 에는 버전 범프를 포함하지 않았다 — #11 로 이제package.json한 곳만 올리고pnpm sync-version을 돌리면 된다.