chore: quality-tightening (yarn 1 -> 4, oxfmt + oxlint + tsc + vitest + husky + first-ever test) - #105
Conversation
… + husky + first-ever test) Yarn 1 -> 4 migration plus the standard quality-tightening rollout. Repo had 0 tests before. - Drops yarn 1 lockfile + .yarnrc; adds .yarnrc.yml + mise.toml (node 20.18.0, yarn 4.14.1, actionlint, shellcheck, gitleaks). - prettier -> oxfmt - eslint (with @typescript-eslint, github, jest, prettier, unicorn) -> oxlint with eslint-plugin-unicorn - jest 26 + jest-circus + ts-jest + @types/jest -> vitest 4 + vite 7 + @vitest/coverage-istanbul (jest.config.js removed) - new: tsgo --noEmit (alongside tsc fallback) - husky 7 -> husky 9 with scripts/ensure-husky.mjs self-heal + lint-staged - new: gitleaks, actionlint, shellcheck as mise-managed binaries - TypeScript bumped 4.x -> 5; tsconfig target ES2022 + lib ES2022 + DOM, skipLibCheck on, types: [node] - Added standard yarn 4 .gitignore entries Refactor + first test: - The action did one thing: call core.setFailed(deprecation message). Extracted DEPRECATION_MESSAGE + main() so the test can drive them directly (the entry point still auto-runs main() outside NODE_ENV ='test'). - New src/index.test.ts asserts: 1. The deprecation message references the updated docs URL (https://game.ci/docs/github/activation). 2. Calling main() forwards that exact message to core.setFailed. Verified locally: lint 0/0, format clean, typecheck clean, test 2/2, build succeeds, actionlint clean.
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ 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 (1)
📝 WalkthroughWalkthroughThis PR performs a comprehensive tooling migration: replacing ESLint with Oxlint, Prettier with Oxfmt, and Jest with Vitest. It also marks the main action as deprecated, updates Husky to v9, and modernizes build configuration with new dependency management. ChangesLinting and Formatting Tooling Migration
Testing Framework Migration
Source Code Deprecation
Build Infrastructure and Development Dependencies
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 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)
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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
vitest.config.mts (1)
12-12: ⚡ Quick winExcluding
src/index.tsfrom coverage hides the very exports you just added tests for.Per the PR description,
DEPRECATION_MESSAGEandmain()were extracted fromsrc/index.tsspecifically sosrc/index.test.tscan exercise them. Excluding the entire file from coverage makes those tests invisible in coverage reports and removes the signal for future regressions.If the goal was to skip the auto-run guard line, prefer an inline ignore (e.g.
/* v8 ignore next */— oxfmt-friendly equivalent for istanbul:/* istanbul ignore next */) over a file-level exclude.♻️ Suggested change
include: ['src/**/*.ts'], - exclude: ['src/**/*.test.ts', 'src/index.ts'], + exclude: ['src/**/*.test.ts'],Then in
src/index.ts, around the auto-run block:/* istanbul ignore next -- entry-point auto-run, not exercised by unit tests */ if (process.env.NODE_ENV !== 'test') { main(); }🤖 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 `@vitest.config.mts` at line 12, Remove src/index.ts from the vitest coverage exclude list so tests can cover DEPRECATION_MESSAGE and main(); then update src/index.ts to keep the auto-run guard but mark that specific block to be ignored by coverage (use an istanbul/coverage comment such as "/* istanbul ignore next */" immediately before the if that calls main()) so the rest of the file remains visible to tests while the runtime-only auto-run line is excluded from coverage.mise.toml (1)
4-6: ⚡ Quick winPin
actionlint,shellcheck, andgitleaksto explicit versions.The whole point of
mise.tomlis reproducible toolchains — using"latest"for these three reintroduces version drift between contributors and CI, which can cause sudden lint/secret-scan failures unrelated to a given PR. Consider pinning them likenodeandyarn.♻️ Suggested change
[tools] node = "20.18.0" yarn = "4.14.1" -actionlint = "latest" -shellcheck = "latest" -gitleaks = "latest" +actionlint = "1.7.7" +shellcheck = "0.10.0" +gitleaks = "8.21.2"(Use whatever current versions you've validated locally.)
🤖 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 `@mise.toml` around lines 4 - 6, The mise.toml currently pins actionlint, shellcheck, and gitleaks to the string "latest", which allows version drift; update the three entries (actionlint, shellcheck, gitleaks) to explicit, tested version strings (e.g., "vX.Y.Z" or "X.Y.Z") used by your team/CI so the toolchain is reproducible, verify those versions locally/CI, and commit the updated mise.toml.tsconfig.json (1)
4-4: 💤 Low valueIs
DOMlib intentional for a Node action?This action runs in Node (per
mise.tomlandvitestenv:'node'), so includingDOMinliblets references todocument,window,fetch(DOM Fetch typings), etc. typecheck successfully even though they would fail or behave differently at runtime in Node 20. If nothing insrc/actually needs DOM types, dropping it tightens the type safety net.♻️ Suggested change
- "lib": ["es2022", "DOM"], + "lib": ["es2022"],🤖 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 `@tsconfig.json` at line 4, The tsconfig "lib" entry currently includes "DOM", which enables browser globals (document/window/fetch) that are inappropriate for a Node-only action; open the tsconfig.json and remove "DOM" from the "lib" array (leave "es2022" or other Node-target libs) or replace it with Node-specific libs if needed, ensuring the "lib" property no longer types browser globals so Node-only code (check src/) typechecks correctly; only re-add DOM if a specific file truly requires browser typings.package.json (2)
12-12: ⚡ Quick win
testscript reinstalls Husky hooks — surprising side effect in CI.
yarn testshouldn't have a side effect of writing/repairing.husky/. In CI the git hooks aren't useful (no commits happen), and on read-only environments or sandboxed runnersensure-husky.mjsmay fail or leave artifacts. Thepreparescript (line 21) andsetup:hooks(line 20) already cover developer-machine bootstrap.♻️ Suggested change
- "test": "node scripts/ensure-husky.mjs && vitest run", + "test": "vitest run",Keep
setup:hooksfor explicit local setup, and rely onprepare(run by Yarn after install) for normal dev flow.🤖 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 `@package.json` at line 12, The "test" npm script currently runs "node scripts/ensure-husky.mjs && vitest run", which causes Husky hooks to be installed as a side effect; remove the call to scripts/ensure-husky.mjs so the "test" script only runs the test runner (e.g., change "test" to run just "vitest run"), and keep Husky setup to the existing "prepare" and "setup:hooks" scripts for developer machines; update any CI documentation or pipelines that invoke "yarn test" to expect no repository modifications.
36-36: 💤 Low valuePin
@typescript/native-previewexactly or document the tracking decision.
^7.0.0-dev.20260505.1is a prerelease range matching frequent date-stamped dev versions (the package publishes many times per day). While caret semver on prerelease versions acts roughly like an exact pin in practice, resolution semantics around-dev.YYYYMMDD.Ntags are easy to misunderstand, and the package explicitly states feature parity is incomplete (declaration emit, API, watch mode still in progress) with behavioral changes expected before the TypeScript 7 release candidate. Sincetypecheck:tsgois a secondary check and the primarytypecheckuses stabletsc, this fallback strategy is sensible—but either remove the^to pin exactly or add a brief comment noting this intentionally tracks a preview build.🤖 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 `@package.json` at line 36, The package.json entry for `@typescript/native-preview` currently uses a caret prerelease range ("@typescript/native-preview": "^7.0.0-dev.20260505.1") which can be misleading given frequent dev publishes; either remove the leading caret to pin the dependency exactly (change the value to "7.0.0-dev.20260505.1") or add an inline comment near the "@typescript/native-preview" declaration explaining that this intentionally tracks a preview/dev build and is only used as a secondary fallback for the typecheck:tsgo script while primary typechecking uses stable tsc.
🤖 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 @.husky/pre-commit:
- Around line 1-7: Add "set -e" immediately after the shebang so the hook aborts
on any failure; specifically modify the pre-commit script containing the
commands yarn lint-staged, yarn typecheck and the gitleaks protect --staged
block so that if yarn lint-staged (or any subsequent command) fails the script
exits immediately instead of continuing to later commands.
In @.yarnrc.yml:
- Around line 1-2: Remove or restrict the overly permissive
approvedGitRepositories entry in .yarnrc.yml: either delete the
approvedGitRepositories: ['**'] key to revert to Yarn's secure default
deny-all-for-git behavior, or replace it with a specific allowlist such as
['https://github.com/yourorg/**'] to only permit trusted repos; also confirm
(and optionally document via a comment) the intentionality of
enableHardenedMode: false—leave it as-is only if you have a justified reason,
otherwise remove or set it to true so Yarn's hardened checks are enforced.
In `@package.json`:
- Around line 39-40: Remove the dead devDependencies "eslint" and
"eslint-plugin-unicorn" from package.json's devDependencies, ensuring any
references to those package names are deleted; after editing package.json run
the package manager install (npm install or yarn install) to update the lockfile
and CI caches so the removed packages are no longer installed or audited.
In `@scripts/ensure-husky.mjs`:
- Around line 25-55: The script should short-circuit when not inside a Git
repository to avoid attempting Husky installation; add an explicit git presence
check (e.g., run execSync('git rev-parse --is-inside-work-tree') or equivalent
and treat failures as "not a git repo") before the existing call that sets
configuredHooksPath, and if that check fails exit 0. Update the logic around
configuredHooksPath, existsSync(sentinelHook) and huskyBin so the new non-git
guard returns early (process.exit(0)) before trying execSync(`node ${huskyBin}`)
or any husky actions; keep existing error handling for real install failures
unchanged.
---
Nitpick comments:
In `@mise.toml`:
- Around line 4-6: The mise.toml currently pins actionlint, shellcheck, and
gitleaks to the string "latest", which allows version drift; update the three
entries (actionlint, shellcheck, gitleaks) to explicit, tested version strings
(e.g., "vX.Y.Z" or "X.Y.Z") used by your team/CI so the toolchain is
reproducible, verify those versions locally/CI, and commit the updated
mise.toml.
In `@package.json`:
- Line 12: The "test" npm script currently runs "node scripts/ensure-husky.mjs
&& vitest run", which causes Husky hooks to be installed as a side effect;
remove the call to scripts/ensure-husky.mjs so the "test" script only runs the
test runner (e.g., change "test" to run just "vitest run"), and keep Husky setup
to the existing "prepare" and "setup:hooks" scripts for developer machines;
update any CI documentation or pipelines that invoke "yarn test" to expect no
repository modifications.
- Line 36: The package.json entry for `@typescript/native-preview` currently uses
a caret prerelease range ("@typescript/native-preview": "^7.0.0-dev.20260505.1")
which can be misleading given frequent dev publishes; either remove the leading
caret to pin the dependency exactly (change the value to "7.0.0-dev.20260505.1")
or add an inline comment near the "@typescript/native-preview" declaration
explaining that this intentionally tracks a preview/dev build and is only used
as a secondary fallback for the typecheck:tsgo script while primary typechecking
uses stable tsc.
In `@tsconfig.json`:
- Line 4: The tsconfig "lib" entry currently includes "DOM", which enables
browser globals (document/window/fetch) that are inappropriate for a Node-only
action; open the tsconfig.json and remove "DOM" from the "lib" array (leave
"es2022" or other Node-target libs) or replace it with Node-specific libs if
needed, ensuring the "lib" property no longer types browser globals so Node-only
code (check src/) typechecks correctly; only re-add DOM if a specific file truly
requires browser typings.
In `@vitest.config.mts`:
- Line 12: Remove src/index.ts from the vitest coverage exclude list so tests
can cover DEPRECATION_MESSAGE and main(); then update src/index.ts to keep the
auto-run guard but mark that specific block to be ignored by coverage (use an
istanbul/coverage comment such as "/* istanbul ignore next */" immediately
before the if that calls main()) so the rest of the file remains visible to
tests while the runtime-only auto-run line is excluded from coverage.
🪄 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: 576e3bf5-0ccb-4a82-980e-a018d30c5ace
⛔ Files ignored due to path filters (4)
dist/index.jsis excluded by!**/dist/**dist/index.js.mapis excluded by!**/dist/**,!**/*.mapdist/licenses.txtis excluded by!**/dist/**yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (19)
.eslintignore.eslintrc.json.gitignore.husky/.gitignore.husky/pre-commit.oxfmtrc.json.oxlintrc.json.prettierignore.prettierrc.json.yarnrc.yarnrc.ymljest.config.jsmise.tomlpackage.jsonscripts/ensure-husky.mjssrc/index.test.tssrc/index.tstsconfig.jsonvitest.config.mts
💤 Files with no reviewable changes (7)
- .eslintignore
- .prettierignore
- .husky/.gitignore
- jest.config.js
- .prettierrc.json
- .yarnrc
- .eslintrc.json
| #!/usr/bin/env sh | ||
| yarn lint-staged | ||
| yarn lint | ||
| yarn test | ||
| yarn typecheck | ||
|
|
||
| yarn build | ||
| git add dist | ||
| if command -v gitleaks >/dev/null 2>&1; then | ||
| gitleaks protect --staged --no-banner --redact | ||
| fi |
There was a problem hiding this comment.
Pre-commit hook does not fail on lint-staged errors.
Without set -e, the script continues past failures and the hook's exit status becomes that of the last command executed. Concretely:
- If
yarn lint-stagedfails (oxlint/oxfmt errors) butyarn typecheckpasses, the commit goes through with lint errors. - If
yarn typecheckfails, gitleaks is never reached, and only typecheck's exit code blocks the commit (acceptable, but inconsistent).
Add set -e so any failing step aborts the hook.
🐛 Proposed fix
#!/usr/bin/env sh
+set -e
+
yarn lint-staged
yarn typecheck
if command -v gitleaks >/dev/null 2>&1; then
gitleaks protect --staged --no-banner --redact
fi🤖 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 @.husky/pre-commit around lines 1 - 7, Add "set -e" immediately after the
shebang so the hook aborts on any failure; specifically modify the pre-commit
script containing the commands yarn lint-staged, yarn typecheck and the gitleaks
protect --staged block so that if yarn lint-staged (or any subsequent command)
fails the script exits immediately instead of continuing to later commands.
| approvedGitRepositories: | ||
| - '**' |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Yarn 4 enableHardenedMode default behavior and approvedGitRepositories security implications
💡 Result:
In Yarn 4 (Berry), enableHardenedMode is false by default, but automatically enabled (true) when Yarn detects it is running in a public GitHub pull request.[1][2][3] This mode activates --check-resolutions and --refresh-lockfile during installs to validate lockfile contents against registry metadata, protecting against lockfile poisoning attacks at the cost of slower installs.[1][4][3] approvedGitRepositories defaults to an empty array [].[5][6] When empty, Yarn blocks all git dependencies (via git: protocol), refusing to fetch any repository URLs as they won't match any patterns; users must explicitly configure glob patterns (e.g., https://github.com/yarnpkg/*) to allow specific repos.[5][7][8] This prevents arbitrary code execution from untrusted git sources, a security feature added in early 2026.[5] Security implications: Hardened mode mitigates supply-chain attacks in untrusted PRs.[1][4] approvedGitRepositories enforces a strict allowlist for git deps, blocking malicious or unexpected clones by default—critical since git repos are packed and executed.[5][8] Without configuration, projects using git dependencies will fail install; CI like GitHub Actions may need updates.[7] Explicitly set enableHardenedMode: false to disable in trusted envs, but avoid in CI.[1][2]
Citations:
- 1: https://yarnpkg.com/features/security
- 2: hardenedMode behaviour yarnpkg/berry#7026
- 3: https://yarnpkg.com/configuration/yarnrc
- 4: https://yarnpkg.com/blog/release/4.0
- 5: yarnpkg/berry@4bd2b21
- 6: https://github.com/yarnpkg/berry/blob/4bd2b2111867ca3a9dc46438aa3010145e31910b/packages/plugin-git/sources/index.ts
- 7: Problem with yarn v4.14 config approvedGitRepositories actions/setup-node#1534
- 8: https://yarnpkg.com/protocol/git
🏁 Script executed:
cat -n .yarnrc.ymlRepository: game-ci/unity-request-activation-file
Length of output: 289
Reconsider the permissive approvedGitRepositories setting.
approvedGitRepositories: ['**'] (lines 1–2) overrides Yarn's secure default (an empty allowlist that blocks all git dependencies) to permit any git-sourced dependency without vetting. For a public GitHub Action, this increases supply-chain risk if a transitive dependency introduces a malicious git source. Either remove this key entirely to enforce the default allowlist, or restrict it to specific trusted repositories (e.g., ['https://github.com/yourorg/**']).
enableHardenedMode: false (line 8) is a lower-priority concern for this action: Yarn 4 automatically enables hardened mode when running in public GitHub PR contexts, so the lockfile/registry tampering checks are active where they matter most. That said, confirm these settings were intentional choices rather than defaults; a comment in the file documenting the rationale would help future maintainers.
🤖 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 @.yarnrc.yml around lines 1 - 2, Remove or restrict the overly permissive
approvedGitRepositories entry in .yarnrc.yml: either delete the
approvedGitRepositories: ['**'] key to revert to Yarn's secure default
deny-all-for-git behavior, or replace it with a specific allowlist such as
['https://github.com/yourorg/**'] to only permit trusted repos; also confirm
(and optionally document via a comment) the intentionality of
enableHardenedMode: false—leave it as-is only if you have a justified reason,
otherwise remove or set it to true so Yarn's hardened checks are enforced.
| "eslint": "^10.3.0", | ||
| "eslint-plugin-unicorn": "^64.0.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm there are no remaining ESLint configs or invocations.
fd -H -t f -e json -e js -e cjs -e mjs -e yaml -e yml '\.eslintrc' || true
rg -nP '\b(eslint|eslint-plugin-unicorn)\b' --hidden -g '!yarn.lock' -g '!**/node_modules/**'Repository: game-ci/unity-request-activation-file
Length of output: 50395
Remove dead eslint and eslint-plugin-unicorn devDeps from package.json.
The PR explicitly migrates from ESLint to oxlint. No .eslintrc configs or ESLint invocations remain in the codebase. Keeping these dependencies inflates install size, lockfile churn, and security audit surface.
Suggested removal
"@vitest/coverage-istanbul": "^4.1.5",
- "eslint": "^10.3.0",
- "eslint-plugin-unicorn": "^64.0.0",
"husky": "9",🤖 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 `@package.json` around lines 39 - 40, Remove the dead devDependencies "eslint"
and "eslint-plugin-unicorn" from package.json's devDependencies, ensuring any
references to those package names are deleted; after editing package.json run
the package manager install (npm install or yarn install) to update the lockfile
and CI caches so the removed packages are no longer installed or audited.
| try { | ||
| configuredHooksPath = execSync('git config --get core.hooksPath', { | ||
| encoding: 'utf8', | ||
| stdio: ['ignore', 'pipe', 'ignore'], | ||
| }).trim(); | ||
| } catch { | ||
| // not a git repo or config unset — fall through and try to install | ||
| } | ||
|
|
||
| if (configuredHooksPath === expectedHooksPath && existsSync(sentinelHook)) { | ||
| process.exit(0); | ||
| } | ||
|
|
||
| if (!huskyBin) { | ||
| // husky not installed yet (yarn install hasn't run) — silent no-op | ||
| process.exit(0); | ||
| } | ||
|
|
||
| console.log('· installing git hooks (husky self-heal)…'); | ||
| try { | ||
| execSync(`node ${huskyBin}`, { stdio: 'inherit' }); | ||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| console.error( | ||
| `\n❌ husky install failed: ${message}\n\n` + | ||
| ` git pre-commit hooks are NOT installed; commits will skip lint/format/tests.\n` + | ||
| ` Fix the underlying error above, then run \`yarn setup:hooks\` to retry.\n` + | ||
| ` To bypass this guard temporarily (NOT recommended): HUSKY=0 yarn <cmd>.\n`, | ||
| ); | ||
| process.exit(1); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the current script lacks an explicit git worktree guard and can proceed to husky install paths.
set -euo pipefail
echo "Check for existing early worktree guard:"
rg -n "rev-parse --is-inside-work-tree|is-inside-work-tree" scripts/ensure-husky.mjs || true
echo
echo "Show control-flow region around git config + install attempt:"
nl -ba scripts/ensure-husky.mjs | sed -n '17,60p'Repository: game-ci/unity-request-activation-file
Length of output: 247
🏁 Script executed:
# Check if file exists and determine its size
wc -l scripts/ensure-husky.mjs
echo "---"
# Show lines 17-60 using available tools
sed -n '17,60p' scripts/ensure-husky.mjs | cat -nRepository: game-ci/unity-request-activation-file
Length of output: 1734
Add an explicit non-git early-exit guard before attempting Husky install.
The code currently catches failures from git config --get core.hooksPath but cannot distinguish between "config unset" and "not a git repository". In non-git contexts, the code proceeds to attempt a Husky install which will fail hard with process.exit(1), unnecessarily blocking workflows.
Suggested fix
import { execSync } from 'node:child_process';
import { existsSync } from 'node:fs';
if (process.env.CI || process.env.HUSKY === '0') process.exit(0);
+try {
+ execSync('git rev-parse --is-inside-work-tree', {
+ stdio: ['ignore', 'ignore', 'ignore'],
+ });
+} catch {
+ // Not a git repository; hooks are not applicable.
+ process.exit(0);
+}
+
const expectedHooksPath = '.husky/_';
const sentinelHook = '.husky/_/pre-commit';🤖 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 `@scripts/ensure-husky.mjs` around lines 25 - 55, The script should
short-circuit when not inside a Git repository to avoid attempting Husky
installation; add an explicit git presence check (e.g., run execSync('git
rev-parse --is-inside-work-tree') or equivalent and treat failures as "not a git
repo") before the existing call that sets configuredHooksPath, and if that check
fails exit 0. Update the logic around configuredHooksPath,
existsSync(sentinelHook) and huskyBin so the new non-git guard returns early
(process.exit(0)) before trying execSync(`node ${huskyBin}`) or any husky
actions; keep existing error handling for real install failures unchanged.
The previous workflow used the runner's global yarn 1.22 and ran 'yarn lint' (the old combined prettier+eslint script). It failed in CI because the package.json has 'packageManager: yarn@4.14.1' and yarn 1 refuses to run when corepack is required. Aligned with the standard ci.yml shape used across the rest of the rollout: - Read node version from mise.toml. - corepack enable + corepack install before any yarn invocation. - Cache node_modules + yarn cache folder + install-state. - Format + Lint + Typecheck + Test + Build steps.
Yarn 1 \u2192 4 migration plus the standard quality-tightening rollout. Repo had 0 tests before.
Migrations
Refactor + first test
core.setFailed(deprecation message). ExtractedDEPRECATION_MESSAGE+main()so the test can drive them directly (the entry point still auto-runsmain()outsideNODE_ENV='test').src/index.test.tsasserts:main()forwards that exact message tocore.setFailed.Verified locally
yarn lint\u2014 0 errors, 0 warningsyarn format:check\u2014 cleanyarn typecheck\u2014 cleanyarn test\u2014 2 / 2yarn build\u2014 succeeds (ncc bundle 950kB)actionlint\u2014 cleanSummary by CodeRabbit