chore: 提升最低 Node 到 22,兼容 pnpm 9/10/11,引入 vitest 单元测试#648
Conversation
- 所有 package.json 的 engines.node 从 >=18 升级到 >=22 - 新增 engines.pnpm: ">=9" 以兼容 pnpm 9/10/11 - 根 package.json 添加 packageManager: "pnpm@10.14.0" 锁定可复现版本 - @types/node 升至 ^22.10.0
- beta-version/release/manual-publish-core 工作流统一切换到 pnpm@10、Node 22 并启用 setup-node 的 pnpm 缓存 - 新增 ci.yml:Node 22/24/26 × pnpm 10/11 矩阵,PR 与 push 时执行 pnpm test
- 根目录新增 vitest.config.ts,@ 别名指向 packages/core/src, 覆盖率聚焦 utils/** - tests/setup.ts 注入 logger/debug 全局桩,避免触发 utils 之外的副作用 - packages/core/tests:为 common(number/sleep/string/uptime)、 system(time/range)、fs(json/path)、ini、button/convert 共 108 个用例 - tests/run-matrix.sh:在 WSL 内跑 Node 22/24/26 × pnpm 10/11 矩阵 - tests/verify-pnpm11.sh:临时移除 packageManager 钉子以验证 pnpm 11 真正运行 - tests/check-pnpm-version.sh:对比项目内外 pnpm 自版本切换行为
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughUpgrades Node and pnpm toolchain declarations, updates GitHub Actions to Node 22 / pnpm 10 with an expanded CI matrix and smoke-build step, adds Vitest configuration and setup, introduces many utility test suites, and provides local test/run helper scripts. ChangesNode 22 Upgrade and Testing Infrastructure
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Reviewer's Guide将最低支持的 Node.js 版本提升到 22,要求 pnpm >=9(仓库中固定为 pnpm 10),现代化 GitHub Actions 工作流,引入基于 Vitest 的单元测试配置(为核心工具新增 100+ 个测试),并添加用于在 WSL 中验证 Node/pnpm 兼容矩阵的辅助脚本,同时不改变现有的运行时行为。 File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your Experience访问你的 dashboard 来:
Getting HelpOriginal review guide in EnglishReviewer's GuideRaises the minimum supported Node.js version to 22 with pnpm >=9 (pinned to pnpm 10 in the repo), modernizes GitHub Actions workflows, introduces a Vitest-based unit test setup with 100+ tests for core utils, and adds WSL helper scripts for validating Node/pnpm compatibility matrices without changing existing runtime behavior. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Code Review
This pull request upgrades the project's environment requirements to Node.js 22 and pnpm 9, alongside updating related type definitions and lockfile dependencies. It introduces a comprehensive suite of unit tests for core utility modules and adds several shell scripts to verify the engine transition. Feedback focuses on improving the portability of the new test scripts by removing hardcoded absolute paths and enhancing error visibility. Additionally, it is recommended to use fake timers for time-sensitive tests to prevent CI flakiness and to avoid asserting known bugs or typos as expected behavior in the test suite.
| ["24"]="$HOME/node-versions/v24.15.0/bin/node" | ||
| ["26"]="$HOME/node-versions/v26.1.0/bin/node" | ||
| ) | ||
|
|
||
| declare -A NODE_DIRS=( | ||
| ["22"]="$(dirname "$(which node)")" | ||
| ["24"]="$HOME/node-versions/v24.15.0/bin" | ||
| ["26"]="$HOME/node-versions/v26.1.0/bin" |
| PNPM_BIN="$PREFIX/node_modules/.bin" | ||
|
|
||
| PATH="$PNPM_BIN:$SAFE_PATH" pnpm --version | ||
| PATH="$PNPM_BIN:$SAFE_PATH" pnpm test 2>&1 | tail -6 |
| # stays at v11 (instead of self-downgrading to the pinned version) and | ||
| # verify install + tests still work. | ||
| set -uo pipefail | ||
| cd /mnt/d/Github/Karin-test-build |
| ~/node-versions/_pnpm-cache/22/node_modules/.bin/pnpm --version | ||
| echo | ||
| echo "Inside project (with packageManager pin), pnpm 11 binary:" | ||
| cd /mnt/d/Github/Karin-test-build |
| it('drops zero day/min/sec but keeps a quirky "0小时钟" segment for zero hour', () => { | ||
| const t1 = 1_700_000_000_000 | ||
| const t2 = t1 + 5_000 // 5 seconds | ||
| expect(formatTime(t1, t2)).toBe('0小时钟5秒') | ||
| }) |
| it('resolves after at least the requested duration', async () => { | ||
| const start = Date.now() | ||
| await sleep(50) | ||
| const elapsed = Date.now() - start | ||
| // generous lower bound: timers can fire 5-10ms early on busy CI | ||
| expect(elapsed).toBeGreaterThanOrEqual(40) | ||
| expect(elapsed).toBeLessThan(500) | ||
| }) |
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:
tests/目录下的辅助脚本(例如run-matrix.sh、verify-pnpm11.sh、check-pnpm-version.sh)中包含硬编码的绝对路径和用户特定目录(/mnt/d/Github/Karin-test-build、~/node-versions/...),这会导致其他贡献者无法直接使用;建议通过环境变量对这些路径进行参数化,或者通过动态方式推导项目根目录(例如git rev-parse --show-toplevel)。- 在
verify-pnpm11.sh和run-matrix.sh中你修改了PATH,并依赖特定的本地 Node/npm 布局;如果能在必需的二进制缺失时增加更清晰的前置检查和错误信息,会让失败原因更容易理解,也能让这些脚本在稍有差异的环境中运行得更安全。 - CI workflow 在安装 Node 之前安装了 pnpm(
ci.yml),而其他 workflows 则是先安装 Node;如果能统一顺序(先 Node 设置 → 再 pnpm 设置),可以减少困惑,并在后续步骤依赖actions/setup-node中的node-version时,确保运行时环境的一致性。
供 AI Agents 使用的提示
Please address the comments from this code review:
## Overall Comments
- `tests/` 目录下的辅助脚本(例如 `run-matrix.sh`、`verify-pnpm11.sh`、`check-pnpm-version.sh`)中包含硬编码的绝对路径和用户特定目录(`/mnt/d/Github/Karin-test-build`、`~/node-versions/...`),这会导致其他贡献者无法直接使用;建议通过环境变量对这些路径进行参数化,或者通过动态方式推导项目根目录(例如 `git rev-parse --show-toplevel`)。
- 在 `verify-pnpm11.sh` 和 `run-matrix.sh` 中你修改了 `PATH`,并依赖特定的本地 Node/npm 布局;如果能在必需的二进制缺失时增加更清晰的前置检查和错误信息,会让失败原因更容易理解,也能让这些脚本在稍有差异的环境中运行得更安全。
- CI workflow 在安装 Node 之前安装了 pnpm(`ci.yml`),而其他 workflows 则是先安装 Node;如果能统一顺序(先 Node 设置 → 再 pnpm 设置),可以减少困惑,并在后续步骤依赖 `actions/setup-node` 中的 `node-version` 时,确保运行时环境的一致性。
## Individual Comments
### Comment 1
<location path="packages/core/tests/utils/fs/json.test.ts" line_range="48-62" />
<code_context>
+ })
+})
+
+describe('utils/fs/json — async', () => {
+ it('writes and reads JSON', async () => {
+ const file = path.join(tmpDir, 'async.json')
+ expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true)
+ await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] })
+ })
+
+ it('returns null when missing without throwing', async () => {
+ await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull()
+ })
+
+ it('throws when isThrow=true on missing file', async () => {
+ await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined()
+ })
</code_context>
<issue_to_address>
**suggestion (testing):** Add async write failure tests to mirror the sync error-path coverage
异步 helper 目前只覆盖了 “文件缺失” 的情况,而同步 helper 同时覆盖了读/写失败,并区分是否传入 `isThrow`。为了对齐行为并防止回归,请补充异步测试,以覆盖以下场景:
- 在 `tmpDir` 为目录的情况下调用 `writeJson(tmpDir, { ... })`,并断言其返回的 Promise 解析为 `false`(或预期的不抛错失败值)。
- 在相同场景下调用 `writeJson(tmpDir, { ... }, true)`,并断言其返回的 Promise 被拒绝(reject)。
```suggestion
describe('utils/fs/json — async', () => {
it('writes and reads JSON', async () => {
const file = path.join(tmpDir, 'async.json')
expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true)
await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] })
})
it('returns null when missing without throwing', async () => {
await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull()
})
it('throws when isThrow=true on missing file', async () => {
await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined()
})
it('returns false on write failure (invalid target) without throwing', async () => {
// A directory cannot be written to as a file
await expect(writeJson(tmpDir, { foo: 'bar' })).resolves.toBe(false)
})
it('rejects on write failure when isThrow=true', async () => {
// A directory cannot be written to as a file
await expect(writeJson(tmpDir, { foo: 'bar' }, true)).rejects.toBeDefined()
})
})
```
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续评审。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The helper scripts under
tests/(e.g.run-matrix.sh,verify-pnpm11.sh,check-pnpm-version.sh) contain hard-coded absolute paths and user-specific directories (/mnt/d/Github/Karin-test-build,~/node-versions/...), which makes them unusable for other contributors; consider parameterizing these paths via environment variables or deriving the project root dynamically (e.g.git rev-parse --show-toplevel). - In
verify-pnpm11.shandrun-matrix.shyou mutatePATHand rely on specific local Node/npm layouts; adding clearer guard checks and error messages when required binaries are missing would make failures easier to understand and the scripts safer to run in slightly different environments. - The CI workflow installs pnpm before Node (
ci.yml), while other workflows install Node first; aligning the order (Node setup → pnpm setup) across workflows can reduce confusion and ensure a consistent runtime environment if future steps depend onnode-versioninactions/setup-node.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The helper scripts under `tests/` (e.g. `run-matrix.sh`, `verify-pnpm11.sh`, `check-pnpm-version.sh`) contain hard-coded absolute paths and user-specific directories (`/mnt/d/Github/Karin-test-build`, `~/node-versions/...`), which makes them unusable for other contributors; consider parameterizing these paths via environment variables or deriving the project root dynamically (e.g. `git rev-parse --show-toplevel`).
- In `verify-pnpm11.sh` and `run-matrix.sh` you mutate `PATH` and rely on specific local Node/npm layouts; adding clearer guard checks and error messages when required binaries are missing would make failures easier to understand and the scripts safer to run in slightly different environments.
- The CI workflow installs pnpm before Node (`ci.yml`), while other workflows install Node first; aligning the order (Node setup → pnpm setup) across workflows can reduce confusion and ensure a consistent runtime environment if future steps depend on `node-version` in `actions/setup-node`.
## Individual Comments
### Comment 1
<location path="packages/core/tests/utils/fs/json.test.ts" line_range="48-62" />
<code_context>
+ })
+})
+
+describe('utils/fs/json — async', () => {
+ it('writes and reads JSON', async () => {
+ const file = path.join(tmpDir, 'async.json')
+ expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true)
+ await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] })
+ })
+
+ it('returns null when missing without throwing', async () => {
+ await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull()
+ })
+
+ it('throws when isThrow=true on missing file', async () => {
+ await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined()
+ })
</code_context>
<issue_to_address>
**suggestion (testing):** Add async write failure tests to mirror the sync error-path coverage
The async helpers only cover the missing-file case, whereas the sync helpers cover both read/write failures with and without `isThrow`. To match that behavior and guard against regressions, please add async tests that:
- Call `writeJson(tmpDir, { ... })` where `tmpDir` is a directory and assert it resolves to `false` (or the expected non-throwing failure value).
- Call `writeJson(tmpDir, { ... }, true)` in the same scenario and assert it rejects.
```suggestion
describe('utils/fs/json — async', () => {
it('writes and reads JSON', async () => {
const file = path.join(tmpDir, 'async.json')
expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true)
await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] })
})
it('returns null when missing without throwing', async () => {
await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull()
})
it('throws when isThrow=true on missing file', async () => {
await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined()
})
it('returns false on write failure (invalid target) without throwing', async () => {
// A directory cannot be written to as a file
await expect(writeJson(tmpDir, { foo: 'bar' })).resolves.toBe(false)
})
it('rejects on write failure when isThrow=true', async () => {
// A directory cannot be written to as a file
await expect(writeJson(tmpDir, { foo: 'bar' }, true)).rejects.toBeDefined()
})
})
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| describe('utils/fs/json — async', () => { | ||
| it('writes and reads JSON', async () => { | ||
| const file = path.join(tmpDir, 'async.json') | ||
| expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true) | ||
| await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] }) | ||
| }) | ||
|
|
||
| it('returns null when missing without throwing', async () => { | ||
| await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull() | ||
| }) | ||
|
|
||
| it('throws when isThrow=true on missing file', async () => { | ||
| await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined() | ||
| }) | ||
| }) |
There was a problem hiding this comment.
suggestion (testing): Add async write failure tests to mirror the sync error-path coverage
异步 helper 目前只覆盖了 “文件缺失” 的情况,而同步 helper 同时覆盖了读/写失败,并区分是否传入 isThrow。为了对齐行为并防止回归,请补充异步测试,以覆盖以下场景:
- 在
tmpDir为目录的情况下调用writeJson(tmpDir, { ... }),并断言其返回的 Promise 解析为false(或预期的不抛错失败值)。 - 在相同场景下调用
writeJson(tmpDir, { ... }, true),并断言其返回的 Promise 被拒绝(reject)。
| describe('utils/fs/json — async', () => { | |
| it('writes and reads JSON', async () => { | |
| const file = path.join(tmpDir, 'async.json') | |
| expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true) | |
| await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] }) | |
| }) | |
| it('returns null when missing without throwing', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull() | |
| }) | |
| it('throws when isThrow=true on missing file', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined() | |
| }) | |
| }) | |
| describe('utils/fs/json — async', () => { | |
| it('writes and reads JSON', async () => { | |
| const file = path.join(tmpDir, 'async.json') | |
| expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true) | |
| await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] }) | |
| }) | |
| it('returns null when missing without throwing', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull() | |
| }) | |
| it('throws when isThrow=true on missing file', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined() | |
| }) | |
| it('returns false on write failure (invalid target) without throwing', async () => { | |
| // A directory cannot be written to as a file | |
| await expect(writeJson(tmpDir, { foo: 'bar' })).resolves.toBe(false) | |
| }) | |
| it('rejects on write failure when isThrow=true', async () => { | |
| // A directory cannot be written to as a file | |
| await expect(writeJson(tmpDir, { foo: 'bar' }, true)).rejects.toBeDefined() | |
| }) | |
| }) |
Original comment in English
suggestion (testing): Add async write failure tests to mirror the sync error-path coverage
The async helpers only cover the missing-file case, whereas the sync helpers cover both read/write failures with and without isThrow. To match that behavior and guard against regressions, please add async tests that:
- Call
writeJson(tmpDir, { ... })wheretmpDiris a directory and assert it resolves tofalse(or the expected non-throwing failure value). - Call
writeJson(tmpDir, { ... }, true)in the same scenario and assert it rejects.
| describe('utils/fs/json — async', () => { | |
| it('writes and reads JSON', async () => { | |
| const file = path.join(tmpDir, 'async.json') | |
| expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true) | |
| await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] }) | |
| }) | |
| it('returns null when missing without throwing', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull() | |
| }) | |
| it('throws when isThrow=true on missing file', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined() | |
| }) | |
| }) | |
| describe('utils/fs/json — async', () => { | |
| it('writes and reads JSON', async () => { | |
| const file = path.join(tmpDir, 'async.json') | |
| expect(await writeJson(file, { x: [1, 2, 3] })).toBe(true) | |
| await expect(readJson(file)).resolves.toEqual({ x: [1, 2, 3] }) | |
| }) | |
| it('returns null when missing without throwing', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'))).resolves.toBeNull() | |
| }) | |
| it('throws when isThrow=true on missing file', async () => { | |
| await expect(readJson(path.join(tmpDir, 'missing-async.json'), true)).rejects.toBeDefined() | |
| }) | |
| it('returns false on write failure (invalid target) without throwing', async () => { | |
| // A directory cannot be written to as a file | |
| await expect(writeJson(tmpDir, { foo: 'bar' })).resolves.toBe(false) | |
| }) | |
| it('rejects on write failure when isThrow=true', async () => { | |
| // A directory cannot be written to as a file | |
| await expect(writeJson(tmpDir, { foo: 'bar' }, true)).rejects.toBeDefined() | |
| }) | |
| }) |
There was a problem hiding this comment.
Pull request overview
该 PR 主要围绕工程化升级:将全仓最低 Node 版本提升到 22、声明 pnpm 引擎范围并引入 Vitest 单元测试,同时新增 CI 矩阵验证在多 Node / pnpm 组合下的可用性。
Changes:
- 将根与各 package 的
engines.node提升到>=22,并新增engines.pnpm: ">=9",同时根package.json增加packageManager钉子与升级@types/node。 - 引入 Vitest(配置、测试初始化),并在
packages/core增加覆盖多个utils/**模块的单测。 - CI/发布相关 workflow 升级 pnpm action 到 v4、切换到 Node 22,并新增
ci.yml测试矩阵;额外加入 WSL 本地验证脚本。
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.ts | 新增 Vitest 配置(别名、覆盖率范围、setupFiles)。 |
| tests/setup.ts | 为测试注入全局 logger/debug 的桩,避免运行时依赖。 |
| tests/run-matrix.sh | 新增 WSL 本地矩阵脚本,用于多 Node/pnpm 组合自测。 |
| tests/verify-pnpm11.sh | 新增验证脚本:临时移除 packageManager 钉子以测试 pnpm 11。 |
| tests/check-pnpm-version.sh | 新增脚本用于对比项目内外 pnpm 版本表现。 |
| package.json | 提升引擎约束、添加 packageManager 钉子、升级 @types/node,并增加/启用测试脚本。 |
| pnpm-lock.yaml | 锁文件随 @types/node 等依赖升级更新。 |
| packages/core/package.json | engines 升级到 Node>=22 并新增 pnpm 引擎。 |
| packages/cli/package.json | engines 升级到 Node>=22 并新增 pnpm 引擎。 |
| packages/cli-Internal/package.json | engines 升级到 Node>=22 并新增 pnpm 引擎。 |
| packages/create-karin/package.json | 升级 @types/node 并更新 engines。 |
| packages/core/tests/utils/common/number.test.ts | 新增 number 工具函数单测。 |
| packages/core/tests/utils/common/sleep.test.ts | 新增 sleep 工具函数单测。 |
| packages/core/tests/utils/common/string.test.ts | 新增 string 工具函数单测。 |
| packages/core/tests/utils/common/uptime.test.ts | 新增 common/uptime 单测。 |
| packages/core/tests/utils/system/time.test.ts | 新增 system/time(含已知遗留行为锁定)单测。 |
| packages/core/tests/utils/system/range.test.ts | 新增 range 工具函数单测。 |
| packages/core/tests/utils/fs/json.test.ts | 新增 JSON 读写工具函数单测。 |
| packages/core/tests/utils/fs/path.test.ts | 新增 path 工具函数单测。 |
| packages/core/tests/utils/ini/index.test.ts | 新增 ini 读写与 parser 工厂单测。 |
| packages/core/tests/utils/button/convert.test.ts | 新增按钮转换工具单测。 |
| .github/workflows/ci.yml | 新增 CI 测试矩阵(Node 22/24/26 × pnpm 10/11)。 |
| .github/workflows/release.yml | 发布 workflow 调整为 Node 22 + pnpm action v4,并启用 pnpm cache。 |
| .github/workflows/beta-version.yml | beta workflow 升级 pnpm action v4 / Node 22 / pnpm cache(但当前步骤顺序存在问题)。 |
| .github/workflows/manual-publish-core.yml | 手动发布 workflow 升级 pnpm action v4 / Node 22 / pnpm cache(但当前步骤顺序存在问题)。 |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
.github/workflows/beta-version.yml:37
run_install: truerunspnpm installduring the pnpm setup step, which occurs beforeactions/setup-node. Withengines.node >=22, the install will run under the runner’s default Node (currently 20) and can fail the workflow or install with the wrong Node version. Moveactions/setup-nodebefore pnpm installation, or removerun_installand add an explicitpnpm installstep after Node 22 is set.
- name: 安装pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: true
- name: 安装Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - name: 拉取代码 | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # 获取完整历史记录,用于生成版本号 | ||
| ref: ${{ github.event.pull_request.head.ref || github.ref_name }} | ||
| repository: ${{ github.event.pull_request.head.repo.full_name || '' }} | ||
|
|
||
| - name: 安装pnpm | ||
| uses: pnpm/action-setup@v2 | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 9 | ||
| version: 10 | ||
| run_install: true | ||
|
|
||
| - name: 安装Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: pnpm | ||
|
|
| # 安装pnpm | ||
| - name: 配置pnpm | ||
| uses: pnpm/action-setup@v2 | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 9 | ||
| version: 10 | ||
| run_install: true | ||
|
|
||
| - name: 安装Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: pnpm | ||
|
|
| set -uo pipefail | ||
| cd /mnt/d/Github/Karin-test-build | ||
|
|
||
| NODE_BIN="$HOME/node-versions/v22.22.2/bin" | ||
| [ -x "$NODE_BIN/node" ] || NODE_BIN="$(dirname "$(which node)")" | ||
| export PATH="$HOME/node-versions/_pnpm-cache/22/node_modules/.bin:$NODE_BIN:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
| cp package.json package.json.bak | ||
| node -e " | ||
| const fs = require('fs'); | ||
| const pkg = JSON.parse(fs.readFileSync('package.json','utf8')); | ||
| delete pkg.packageManager; | ||
| fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); | ||
| " | ||
|
|
||
| echo "pnpm version (no packageManager pin): $(pnpm --version)" | ||
| pnpm test 2>&1 | tail -10 | ||
| RC=$? | ||
|
|
||
| mv package.json.bak package.json | ||
| exit $RC |
| ~/node-versions/_pnpm-cache/22/node_modules/.bin/pnpm --version | ||
| echo | ||
| echo "Inside project (with packageManager pin), pnpm 11 binary:" | ||
| cd /mnt/d/Github/Karin-test-build |
| declare -A NODE_PATHS=( | ||
| ["22"]="$(which node)" | ||
| ["24"]="$HOME/node-versions/v24.15.0/bin/node" | ||
| ["26"]="$HOME/node-versions/v26.1.0/bin/node" | ||
| ) | ||
|
|
||
| declare -A NODE_DIRS=( | ||
| ["22"]="$(dirname "$(which node)")" | ||
| ["24"]="$HOME/node-versions/v24.15.0/bin" | ||
| ["26"]="$HOME/node-versions/v26.1.0/bin" | ||
| ) | ||
|
|
||
| PNPM_VERSIONS=("10.14.0" "11.1.1") |
| cache: pnpm | ||
|
|
||
| - name: 安装依赖 | ||
| run: pnpm install --frozen-lockfile=false |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (4)
tests/run-matrix.sh (2)
6-10: ⚡ Quick winRemove unused
NODE_PATHSvariable.The
NODE_PATHSassociative array is declared but never referenced in the script. OnlyNODE_DIRSis used (lines 25, 42, 45).♻️ Proposed fix
-declare -A NODE_PATHS=( - ["22"]="$(which node)" - ["24"]="$HOME/node-versions/v24.15.0/bin/node" - ["26"]="$HOME/node-versions/v26.1.0/bin/node" -) - declare -A NODE_DIRS=( ["22"]="$(dirname "$(which node)")" ["24"]="$HOME/node-versions/v24.15.0/bin" ["26"]="$HOME/node-versions/v26.1.0/bin" )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/run-matrix.sh` around lines 6 - 10, Remove the dead associative array declaration NODE_PATHS from the script (the declare -A NODE_PATHS=(...) block) since it is never used; keep and use the existing NODE_DIRS variable as intended (no other code changes required), and run the script to ensure no references to NODE_PATHS remain.
48-48: 💤 Low valueConsider capturing more test output for debugging.
The test output is truncated to the last 6 lines via
tail -6. If tests fail, important error context from earlier in the output may be lost, making debugging more difficult.Consider increasing the tail line count or conditionally showing full output on failure.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/run-matrix.sh` at line 48, The test runner currently pipes the pnpm test output through "tail -6" which truncates logs and loses valuable context; modify the invocation around the PATH="$PNPM_BIN:$SAFE_PATH" pnpm test call to preserve more output by either increasing the tail window (e.g., tail -100) or capturing the full output to a temporary file (using tee) and only tailing the end for success while printing the entire file on failure (check the pnpm test exit status and cat the saved log if non-zero).tests/verify-pnpm11.sh (1)
6-6: ⚡ Quick winAdd error handling for directory change.
The
cdcommand lacks error handling. If the directory change fails, the script will modify the wrongpackage.jsonfile, potentially corrupting an unrelated project.🛡️ Proposed fix
-cd /mnt/d/Github/Karin-test-build +cd /mnt/d/Github/Karin-test-build || exit 1🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/verify-pnpm11.sh` at line 6, The script's lone cd command ("cd /mnt/d/Github/Karin-test-build") has no error handling so a failed directory change could cause subsequent operations to run in the wrong folder; update tests/verify-pnpm11.sh to check the exit status of the cd (e.g., perform the cd and if it fails print a clear error to stderr and exit non‑zero) before continuing, ensuring any subsequent package.json modifications only run after a successful chdir.tests/check-pnpm-version.sh (1)
3-3: ⚡ Quick winAdd error handling for directory changes.
The
cdcommands at lines 3 and 8 lack error handling. If the directory change fails, the script will continue executing in the wrong directory.🛡️ Proposed fix
-cd /tmp +cd /tmp || exit 1Apply the same pattern to line 8.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/check-pnpm-version.sh` at line 3, The script's cd commands (the existing "cd /tmp" at start and the other cd at line 8) lack error handling; update both cd invocations to check their exit status and abort on failure (e.g., append a conditional exit or add a short error message then exit) so the script does not continue running in the wrong directory; apply this pattern to the "cd /tmp" occurrences and ensure any subsequent cd uses follow the same guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci.yml:
- Line 43: The pnpm install step currently uses "pnpm install
--frozen-lockfile=false" without explanation; either add an inline comment above
that run step clarifying that the lockfile is intentionally allowed to float to
exercise compatibility across the pnpm (10/11) and Node (22/24/26) matrix, or
change the command to "pnpm install --frozen-lockfile" and update/commit the
lockfile for reproducible CI (or adopt a strategy to regenerate
per-tool-version); update only the run step referencing "pnpm install
--frozen-lockfile=false" and its surrounding comment to reflect the chosen
approach.
In `@package.json`:
- Line 30: Remove the packageManager field ("packageManager": "pnpm@10.14.0")
from package.json so CI matrix jobs can control pnpm versions, and rely on the
existing engines.pnpm constraint (e.g., "engines": { "pnpm": ">=9" }) for
compatibility; alternatively, if you must keep packageManager for local
reproducibility, update CI workflows that call pnpm/action-setup to remove their
explicit version inputs so they don't conflict with the pinned packageManager
value—ensure you modify either the packageManager entry or the CI job inputs,
not both.
In `@packages/core/tests/utils/fs/path.test.ts`:
- Around line 62-72: The tests in packages/core/tests/utils/fs/path.test.ts use
toBeTruthy()/toBeFalsy() which can mask non-boolean return values from
isSubPath; update the three assertions that reference isSubPath (the cases
"returns truthy for paths under the root", "returns falsy for paths outside the
root", and "returns falsy when target equals root") to assert strict booleans by
using toBe(true) for the positive case and toBe(false) for the two negative
cases so the tests fail if isSubPath returns a non-boolean (the function
referenced isSubPath).
In `@tests/setup.ts`:
- Line 25: The stub assignment currently sets g.debug to a function that returns
noop instead of the no-op itself; change the assignment so g.debug = noop (use
the existing noop function) instead of g.debug = () => noop to ensure calls to
g.debug execute the no-op rather than returning it; update the code referencing
g.debug if any assumptions about its return value exist (use the noop symbol and
the g.debug identifier to locate the line).
---
Nitpick comments:
In `@tests/check-pnpm-version.sh`:
- Line 3: The script's cd commands (the existing "cd /tmp" at start and the
other cd at line 8) lack error handling; update both cd invocations to check
their exit status and abort on failure (e.g., append a conditional exit or add a
short error message then exit) so the script does not continue running in the
wrong directory; apply this pattern to the "cd /tmp" occurrences and ensure any
subsequent cd uses follow the same guard.
In `@tests/run-matrix.sh`:
- Around line 6-10: Remove the dead associative array declaration NODE_PATHS
from the script (the declare -A NODE_PATHS=(...) block) since it is never used;
keep and use the existing NODE_DIRS variable as intended (no other code changes
required), and run the script to ensure no references to NODE_PATHS remain.
- Line 48: The test runner currently pipes the pnpm test output through "tail
-6" which truncates logs and loses valuable context; modify the invocation
around the PATH="$PNPM_BIN:$SAFE_PATH" pnpm test call to preserve more output by
either increasing the tail window (e.g., tail -100) or capturing the full output
to a temporary file (using tee) and only tailing the end for success while
printing the entire file on failure (check the pnpm test exit status and cat the
saved log if non-zero).
In `@tests/verify-pnpm11.sh`:
- Line 6: The script's lone cd command ("cd /mnt/d/Github/Karin-test-build") has
no error handling so a failed directory change could cause subsequent operations
to run in the wrong folder; update tests/verify-pnpm11.sh to check the exit
status of the cd (e.g., perform the cd and if it fails print a clear error to
stderr and exit non‑zero) before continuing, ensuring any subsequent
package.json modifications only run after a successful chdir.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 15e1ced1-a0fe-45bf-a477-9322961f99fc
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (24)
.github/workflows/beta-version.yml.github/workflows/ci.yml.github/workflows/manual-publish-core.yml.github/workflows/release.ymlpackage.jsonpackages/cli-Internal/package.jsonpackages/cli/package.jsonpackages/core/package.jsonpackages/core/tests/utils/button/convert.test.tspackages/core/tests/utils/common/number.test.tspackages/core/tests/utils/common/sleep.test.tspackages/core/tests/utils/common/string.test.tspackages/core/tests/utils/common/uptime.test.tspackages/core/tests/utils/fs/json.test.tspackages/core/tests/utils/fs/path.test.tspackages/core/tests/utils/ini/index.test.tspackages/core/tests/utils/system/range.test.tspackages/core/tests/utils/system/time.test.tspackages/create-karin/package.jsontests/check-pnpm-version.shtests/run-matrix.shtests/setup.tstests/verify-pnpm11.shvitest.config.ts
| it('returns truthy for paths under the root', () => { | ||
| expect(isSubPath(process.cwd(), path.join(process.cwd(), 'a', 'b'))).toBeTruthy() | ||
| }) | ||
|
|
||
| it('returns falsy for paths outside the root', () => { | ||
| expect(isSubPath(path.join(process.cwd(), 'a'), path.join(process.cwd(), 'b'))).toBeFalsy() | ||
| }) | ||
|
|
||
| it('returns falsy when target equals root (relative is empty)', () => { | ||
| expect(isSubPath(process.cwd(), process.cwd())).toBeFalsy() | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether isSubPath is typed/implemented as a strict boolean predicate.
# Expected: declaration/signature or implementation should indicate boolean return semantics.
rg -nP -C3 '\bisSubPath\b'Repository: KarinJS/Karin
Length of output: 2904
🏁 Script executed:
cat -n packages/core/src/utils/fs/path.ts | sed -n '105,130p'Repository: KarinJS/Karin
Length of output: 885
Replace toBeTruthy/toBeFalsy with strict boolean assertions.
The isSubPath function returns relative && !relative.startsWith('..') && !path.isAbsolute(relative) (line 119), which can return an empty string instead of the strict boolean false. Using toBeTruthy()/toBeFalsy() at lines 63, 67, and 71 masks this behavior; replace with toBe(true)/toBe(false) to enforce strict boolean semantics.
Suggested fix
it('returns truthy for paths under the root', () => {
- expect(isSubPath(process.cwd(), path.join(process.cwd(), 'a', 'b'))).toBeTruthy()
+ expect(isSubPath(process.cwd(), path.join(process.cwd(), 'a', 'b'))).toBe(true)
})
it('returns falsy for paths outside the root', () => {
- expect(isSubPath(path.join(process.cwd(), 'a'), path.join(process.cwd(), 'b'))).toBeFalsy()
+ expect(isSubPath(path.join(process.cwd(), 'a'), path.join(process.cwd(), 'b'))).toBe(false)
})
it('returns falsy when target equals root (relative is empty)', () => {
- expect(isSubPath(process.cwd(), process.cwd())).toBeFalsy()
+ expect(isSubPath(process.cwd(), process.cwd())).toBe(false)
})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('returns truthy for paths under the root', () => { | |
| expect(isSubPath(process.cwd(), path.join(process.cwd(), 'a', 'b'))).toBeTruthy() | |
| }) | |
| it('returns falsy for paths outside the root', () => { | |
| expect(isSubPath(path.join(process.cwd(), 'a'), path.join(process.cwd(), 'b'))).toBeFalsy() | |
| }) | |
| it('returns falsy when target equals root (relative is empty)', () => { | |
| expect(isSubPath(process.cwd(), process.cwd())).toBeFalsy() | |
| }) | |
| it('returns truthy for paths under the root', () => { | |
| expect(isSubPath(process.cwd(), path.join(process.cwd(), 'a', 'b'))).toBe(true) | |
| }) | |
| it('returns falsy for paths outside the root', () => { | |
| expect(isSubPath(path.join(process.cwd(), 'a'), path.join(process.cwd(), 'b'))).toBe(false) | |
| }) | |
| it('returns falsy when target equals root (relative is empty)', () => { | |
| expect(isSubPath(process.cwd(), process.cwd())).toBe(false) | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/core/tests/utils/fs/path.test.ts` around lines 62 - 72, The tests in
packages/core/tests/utils/fs/path.test.ts use toBeTruthy()/toBeFalsy() which can
mask non-boolean return values from isSubPath; update the three assertions that
reference isSubPath (the cases "returns truthy for paths under the root",
"returns falsy for paths outside the root", and "returns falsy when target
equals root") to assert strict booleans by using toBe(true) for the positive
case and toBe(false) for the two negative cases so the tests fail if isSubPath
returns a non-boolean (the function referenced isSubPath).
|
|
||
| const g = globalThis as Record<string, unknown> | ||
| if (!g.logger) g.logger = stubLogger | ||
| if (!g.debug) g.debug = () => noop |
There was a problem hiding this comment.
Fix debug stub assignment to a direct no-op function.
Line 25 currently sets debug to a function that returns noop, not to noop itself.
Proposed fix
-if (!g.debug) g.debug = () => noop
+if (!g.debug) g.debug = noop📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!g.debug) g.debug = () => noop | |
| if (!g.debug) g.debug = noop |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/setup.ts` at line 25, The stub assignment currently sets g.debug to a
function that returns noop instead of the no-op itself; change the assignment so
g.debug = noop (use the existing noop function) instead of g.debug = () => noop
to ensure calls to g.debug execute the no-op rather than returning it; update
the code referencing g.debug if any assumptions about its return value exist
(use the noop symbol and the g.debug identifier to locate the line).
- ci.yml 矩阵从 22/24/26 扩到 22/24/25/26,非 LTS 版本只配对 pnpm 11 控规模 - 新增构建步:pnpm --filter create-karin build - 新增烟测步:node packages/create-karin/dist/index.mjs --help 捕获 import 级 Node 兼容性回归(ora/prompts/kolorist 等) - 配套本地校验脚本: - tests/verify-create-karin.sh:跑本地 dist 的 --help + 环境探测 - tests/verify-create-karin-published.sh:跑发布版 pnpm create karin - tests/verify-create-karin-deep.sh:跑完整 -y 静默建项目流程
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/verify-create-karin-deep.sh`:
- Around line 8-9: The script uses a hardcoded WSL path in the cd command and
then builds CLI="$(pwd)/packages/create-karin/dist/index.mjs", which will fail
on other machines; change the cd + CLI setup to detect the repository root
dynamically (e.g. use git rev-parse --show-toplevel or resolve the script's
directory) and then set CLI relative to that root (keep the CLI variable name
and the call that points to packages/create-karin/dist/index.mjs so other logic
remains unchanged).
In `@tests/verify-create-karin.sh`:
- Around line 10-11: The script uses a hardcoded absolute path in the cd command
which breaks on other machines; replace that with portable repo-root detection
by computing the script directory or git repo root (e.g., via dirname "$0" or
git rev-parse --show-toplevel) and cd to that computed path instead; also set
CLI=packages/create-karin/dist/index.mjs relative to the computed root so both
the cd and CLI assignment use the repository root resolution (refer to the cd
command and the CLI variable in the script).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 735ceb48-85e8-45bd-b629-aa63df13ada5
📒 Files selected for processing (4)
.github/workflows/ci.ymltests/verify-create-karin-deep.shtests/verify-create-karin-published.shtests/verify-create-karin.sh
| cd /mnt/d/Github/Karin-test-build | ||
| CLI="$(pwd)/packages/create-karin/dist/index.mjs" |
There was a problem hiding this comment.
Replace hardcoded WSL path with portable repository root detection.
The absolute path /mnt/d/Github/Karin-test-build is specific to your WSL environment and will break for any other developer or CI system. Use relative paths or detect the repository root dynamically.
🔧 Proposed fix using git to find repo root
-cd /mnt/d/Github/Karin-test-build
-CLI="$(pwd)/packages/create-karin/dist/index.mjs"
+REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+cd "$REPO_ROOT"
+CLI="$REPO_ROOT/packages/create-karin/dist/index.mjs"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cd /mnt/d/Github/Karin-test-build | |
| CLI="$(pwd)/packages/create-karin/dist/index.mjs" | |
| REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" | |
| cd "$REPO_ROOT" | |
| CLI="$REPO_ROOT/packages/create-karin/dist/index.mjs" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/verify-create-karin-deep.sh` around lines 8 - 9, The script uses a
hardcoded WSL path in the cd command and then builds
CLI="$(pwd)/packages/create-karin/dist/index.mjs", which will fail on other
machines; change the cd + CLI setup to detect the repository root dynamically
(e.g. use git rev-parse --show-toplevel or resolve the script's directory) and
then set CLI relative to that root (keep the CLI variable name and the call that
points to packages/create-karin/dist/index.mjs so other logic remains
unchanged).
| cd /mnt/d/Github/Karin-test-build | ||
| CLI=packages/create-karin/dist/index.mjs |
There was a problem hiding this comment.
Replace hardcoded WSL path with portable repository root detection.
The absolute path /mnt/d/Github/Karin-test-build is specific to your WSL environment and will break for any other developer. Use relative path resolution instead.
🔧 Proposed fix using relative path from script location
-cd /mnt/d/Github/Karin-test-build
-CLI=packages/create-karin/dist/index.mjs
+REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+CLI="$REPO_ROOT/packages/create-karin/dist/index.mjs"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| cd /mnt/d/Github/Karin-test-build | |
| CLI=packages/create-karin/dist/index.mjs | |
| REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" | |
| CLI="$REPO_ROOT/packages/create-karin/dist/index.mjs" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/verify-create-karin.sh` around lines 10 - 11, The script uses a
hardcoded absolute path in the cd command which breaks on other machines;
replace that with portable repo-root detection by computing the script directory
or git repo root (e.g., via dirname "$0" or git rev-parse --show-toplevel) and
cd to that computed path instead; also set
CLI=packages/create-karin/dist/index.mjs relative to the computed root so both
the cd and CLI assignment use the repository root resolution (refer to the cd
command and the CLI variable in the script).
- 删 package.json 里的 packageManager: pnpm@10.14.0:和 pnpm/action-setup 的 version 输入冲突 (ERR_PNPM_BAD_PM_VERSION),且本地用着也烦 - beta-version / release / manual-publish-core 三个发布相关 workflow 统一回退到 pnpm 9,setup-node 步骤提前到 pnpm install 之前 - ci.yml 矩阵新增 pnpm 9 作为 baseline (22×9、24×9), --frozen-lockfile=false 改成更稳的 --no-frozen-lockfile - 新增 tests/verify-pnpm9.sh:本地复现 CI 的 pnpm 9 安装 + 测试路径
pnpm 11 把 onlyBuiltDependencies 的语义收紧了:列在白名单里的依赖也得通过 'pnpm approve-builds' 显式批准,否则装包后直接以 exit 1 报错。 单测/构建-create-karin 路径用不到 native 模块(sqlite3/node-pty/parcel-watcher 等),直接 --ignore-scripts 跳过 postinstall,跨 pnpm 9/10/11 行为一致。 本地用 pnpm 11.1.1 全量复现:install → pnpm test (108 passed) → build create-karin → --help 烟测,全通过。
|
你可以通过以下命令安装该版本: |
Summary
engines.node从>=18升至>=22;新增engines.pnpm: ">=9"覆盖 9/10/11;根package.json添加packageManager: "pnpm@10.14.0"锁定可复现安装版本;@types/node升到^22.10.0。pnpm/action-setup全部升到 v4 并改用 pnpm@10,发布相关 workflow 增加actions/setup-node@v4与 pnpm 缓存;新增.github/workflows/ci.yml,对 Node 22/24/26 × pnpm 10/11 跑pnpm test矩阵。vitest.config.ts(@别名映射packages/core/src,覆盖率聚焦utils/**);tests/setup.ts注入logger/debug全局桩;packages/core/tests/共 108 个用例,覆盖utils/common(number/sleep/string/uptime)、utils/system(time/range)、utils/fs(json/path)、utils/ini、utils/button/convert。tests/run-matrix.sh(Node 22/24/26 × pnpm 10/11)、tests/verify-pnpm11.sh(临时摘掉packageManager钉子,验证 pnpm 11 自身真正能跑),tests/check-pnpm-version.sh(对比项目内外 pnpm 自版本切换)。本地验证
在 WSL Ubuntu 24.04 下跑过 6 个组合,每组 108/108 全绿:
另外
verify-pnpm11.sh摘掉packageManager钉子后直接以 pnpm 11.1.1 跑,108/108 通过,确认 pnpm 11 本身能够真正驱动安装与测试。已知遗留(未在本 PR 修复,仅由测试锁定当前行为)
packages/core/src/utils/system/time.ts的formatTime:/0[天时分秒]/g漏掉0小时(因为0后面是小不是时),10 位秒级时间戳会被错误地放大成天级负数。toBe('0小时钟5秒')等断言锁定当前行为,留待单独的 fix PR 处理。Test plan
pnpm install不再因engines报错pnpm test在 Node 22/24/26 上均 108 用例通过Summary by Sourcery
将最低支持的 Node.js 版本提升到 22,使项目与 pnpm 9+ 以及锁定的 pnpm 10 工具链保持一致,并为核心工具引入基于 vitest 的测试套件,同时更新 CI 以在现代 Node/pnpm 组合下运行测试。
New Features:
'@'引入,并在测试中接入全局 logger/debug 的桩实现。Enhancements:
pnpm@10.14.0,以确保本地和 CI 安装的可重现性。CI:
Tests:
Original summary in English
Summary by Sourcery
Raise the minimum supported Node.js version to 22, align the project with pnpm 9+ and a pinned pnpm 10 toolchain, and introduce a vitest-based test suite for core utilities, with CI updated to run the tests across modern Node/pnpm combinations.
New Features:
Enhancements:
CI:
Tests:
Summary by CodeRabbit
Chores
Tests