From 4e3c7d818f8b8bf490823a3e16e7bad1f7a5b413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:33:20 +0200 Subject: [PATCH 1/8] chore: update deps --- package.json | 5 +- yarn.lock | 526 +++++++++++++++++++++++++-------------------------- 2 files changed, 266 insertions(+), 265 deletions(-) diff --git a/package.json b/package.json index b762340..b0ceed8 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,8 @@ "@vitest/coverage-v8": "^4.1.5", "adio": "^3.0.0", "happy-dom": "^20.9.0", - "oxfmt": "^0.47.0", - "oxlint": "^1.62.0", + "oxfmt": "^0.48.0", + "oxlint": "^1.63.0", "vitest": "^4.1.5" }, "scripts": { @@ -53,6 +53,7 @@ "format:check": "oxfmt --check", "lint": "oxlint --deny-warnings", "lint:fix": "oxlint --fix", + "check:imports": "adio", "typecheck": "tsgo -p tsconfig.check.common.json && tsgo -p tsconfig.check.node.json && tsgo -p tsconfig.check.browser.json && tsgo -p tsconfig.check.scripts.json" } } diff --git a/yarn.lock b/yarn.lock index a59dd1b..c5b8090 100644 --- a/yarn.lock +++ b/yarn.lock @@ -241,10 +241,10 @@ __metadata: languageName: node linkType: hard -"@oxc-project/types@npm:=0.127.0": - version: 0.127.0 - resolution: "@oxc-project/types@npm:0.127.0" - checksum: 10c0/52c0947ac64a9ca119fe971f947e784a35ecd14a072fa3f542a58a5f6c42010b53f2bf92731e39b9899b83c990a9517bbd29d1e5a5b7b489e52616685c6a9278 +"@oxc-project/types@npm:=0.128.0": + version: 0.128.0 + resolution: "@oxc-project/types@npm:0.128.0" + checksum: 10c0/b6999b1b6b012d979364231a2c0c9204bca814a73f8417234edd39bf352a081779dad72aaf18ac60a676fb904c1408b63553e4e1230d7408a4f885002d66c809 languageName: node linkType: hard @@ -255,268 +255,268 @@ __metadata: languageName: node linkType: hard -"@oxfmt/binding-android-arm-eabi@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-android-arm-eabi@npm:0.47.0" +"@oxfmt/binding-android-arm-eabi@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-android-arm-eabi@npm:0.48.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@oxfmt/binding-android-arm64@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-android-arm64@npm:0.47.0" +"@oxfmt/binding-android-arm64@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-android-arm64@npm:0.48.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@oxfmt/binding-darwin-arm64@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-darwin-arm64@npm:0.47.0" +"@oxfmt/binding-darwin-arm64@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-darwin-arm64@npm:0.48.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@oxfmt/binding-darwin-x64@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-darwin-x64@npm:0.47.0" +"@oxfmt/binding-darwin-x64@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-darwin-x64@npm:0.48.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@oxfmt/binding-freebsd-x64@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-freebsd-x64@npm:0.47.0" +"@oxfmt/binding-freebsd-x64@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-freebsd-x64@npm:0.48.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@oxfmt/binding-linux-arm-gnueabihf@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-arm-gnueabihf@npm:0.47.0" +"@oxfmt/binding-linux-arm-gnueabihf@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-arm-gnueabihf@npm:0.48.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxfmt/binding-linux-arm-musleabihf@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-arm-musleabihf@npm:0.47.0" +"@oxfmt/binding-linux-arm-musleabihf@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-arm-musleabihf@npm:0.48.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxfmt/binding-linux-arm64-gnu@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-arm64-gnu@npm:0.47.0" +"@oxfmt/binding-linux-arm64-gnu@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-arm64-gnu@npm:0.48.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@oxfmt/binding-linux-arm64-musl@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-arm64-musl@npm:0.47.0" +"@oxfmt/binding-linux-arm64-musl@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-arm64-musl@npm:0.48.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@oxfmt/binding-linux-ppc64-gnu@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-ppc64-gnu@npm:0.47.0" +"@oxfmt/binding-linux-ppc64-gnu@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-ppc64-gnu@npm:0.48.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@oxfmt/binding-linux-riscv64-gnu@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-riscv64-gnu@npm:0.47.0" +"@oxfmt/binding-linux-riscv64-gnu@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-riscv64-gnu@npm:0.48.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@oxfmt/binding-linux-riscv64-musl@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-riscv64-musl@npm:0.47.0" +"@oxfmt/binding-linux-riscv64-musl@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-riscv64-musl@npm:0.48.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@oxfmt/binding-linux-s390x-gnu@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-s390x-gnu@npm:0.47.0" +"@oxfmt/binding-linux-s390x-gnu@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-s390x-gnu@npm:0.48.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@oxfmt/binding-linux-x64-gnu@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-x64-gnu@npm:0.47.0" +"@oxfmt/binding-linux-x64-gnu@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-x64-gnu@npm:0.48.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@oxfmt/binding-linux-x64-musl@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-linux-x64-musl@npm:0.47.0" +"@oxfmt/binding-linux-x64-musl@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-linux-x64-musl@npm:0.48.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@oxfmt/binding-openharmony-arm64@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-openharmony-arm64@npm:0.47.0" +"@oxfmt/binding-openharmony-arm64@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-openharmony-arm64@npm:0.48.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@oxfmt/binding-win32-arm64-msvc@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-win32-arm64-msvc@npm:0.47.0" +"@oxfmt/binding-win32-arm64-msvc@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-win32-arm64-msvc@npm:0.48.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@oxfmt/binding-win32-ia32-msvc@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-win32-ia32-msvc@npm:0.47.0" +"@oxfmt/binding-win32-ia32-msvc@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-win32-ia32-msvc@npm:0.48.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@oxfmt/binding-win32-x64-msvc@npm:0.47.0": - version: 0.47.0 - resolution: "@oxfmt/binding-win32-x64-msvc@npm:0.47.0" +"@oxfmt/binding-win32-x64-msvc@npm:0.48.0": + version: 0.48.0 + resolution: "@oxfmt/binding-win32-x64-msvc@npm:0.48.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@oxlint/binding-android-arm-eabi@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-android-arm-eabi@npm:1.62.0" +"@oxlint/binding-android-arm-eabi@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-android-arm-eabi@npm:1.63.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@oxlint/binding-android-arm64@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-android-arm64@npm:1.62.0" +"@oxlint/binding-android-arm64@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-android-arm64@npm:1.63.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@oxlint/binding-darwin-arm64@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-darwin-arm64@npm:1.62.0" +"@oxlint/binding-darwin-arm64@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-darwin-arm64@npm:1.63.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@oxlint/binding-darwin-x64@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-darwin-x64@npm:1.62.0" +"@oxlint/binding-darwin-x64@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-darwin-x64@npm:1.63.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@oxlint/binding-freebsd-x64@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-freebsd-x64@npm:1.62.0" +"@oxlint/binding-freebsd-x64@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-freebsd-x64@npm:1.63.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@oxlint/binding-linux-arm-gnueabihf@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-arm-gnueabihf@npm:1.62.0" +"@oxlint/binding-linux-arm-gnueabihf@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-arm-gnueabihf@npm:1.63.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxlint/binding-linux-arm-musleabihf@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-arm-musleabihf@npm:1.62.0" +"@oxlint/binding-linux-arm-musleabihf@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-arm-musleabihf@npm:1.63.0" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@oxlint/binding-linux-arm64-gnu@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-arm64-gnu@npm:1.62.0" +"@oxlint/binding-linux-arm64-gnu@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-arm64-gnu@npm:1.63.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@oxlint/binding-linux-arm64-musl@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-arm64-musl@npm:1.62.0" +"@oxlint/binding-linux-arm64-musl@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-arm64-musl@npm:1.63.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@oxlint/binding-linux-ppc64-gnu@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-ppc64-gnu@npm:1.62.0" +"@oxlint/binding-linux-ppc64-gnu@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-ppc64-gnu@npm:1.63.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@oxlint/binding-linux-riscv64-gnu@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-riscv64-gnu@npm:1.62.0" +"@oxlint/binding-linux-riscv64-gnu@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-riscv64-gnu@npm:1.63.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@oxlint/binding-linux-riscv64-musl@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-riscv64-musl@npm:1.62.0" +"@oxlint/binding-linux-riscv64-musl@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-riscv64-musl@npm:1.63.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@oxlint/binding-linux-s390x-gnu@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-s390x-gnu@npm:1.62.0" +"@oxlint/binding-linux-s390x-gnu@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-s390x-gnu@npm:1.63.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@oxlint/binding-linux-x64-gnu@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-x64-gnu@npm:1.62.0" +"@oxlint/binding-linux-x64-gnu@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-x64-gnu@npm:1.63.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@oxlint/binding-linux-x64-musl@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-linux-x64-musl@npm:1.62.0" +"@oxlint/binding-linux-x64-musl@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-linux-x64-musl@npm:1.63.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@oxlint/binding-openharmony-arm64@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-openharmony-arm64@npm:1.62.0" +"@oxlint/binding-openharmony-arm64@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-openharmony-arm64@npm:1.63.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@oxlint/binding-win32-arm64-msvc@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-win32-arm64-msvc@npm:1.62.0" +"@oxlint/binding-win32-arm64-msvc@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-win32-arm64-msvc@npm:1.63.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@oxlint/binding-win32-ia32-msvc@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-win32-ia32-msvc@npm:1.62.0" +"@oxlint/binding-win32-ia32-msvc@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-win32-ia32-msvc@npm:1.63.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@oxlint/binding-win32-x64-msvc@npm:1.62.0": - version: 1.62.0 - resolution: "@oxlint/binding-win32-x64-msvc@npm:1.62.0" +"@oxlint/binding-win32-x64-msvc@npm:1.63.0": + version: 1.63.0 + resolution: "@oxlint/binding-win32-x64-msvc@npm:1.63.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -528,93 +528,93 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-android-arm64@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.17" +"@rolldown/binding-android-arm64@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.18" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.17" +"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.18" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-x64@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.17" +"@rolldown/binding-darwin-x64@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.18" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.17" +"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.18" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.17" +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.18" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.17" +"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.18" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.17" +"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.18" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.17" +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.18" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.17" +"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.18" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.17" +"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.18" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.17" +"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.18" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.17" +"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.18" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.17" +"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.18" dependencies: "@emnapi/core": "npm:1.10.0" "@emnapi/runtime": "npm:1.10.0" @@ -623,24 +623,24 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.17" +"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.18" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.17" +"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.18" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rolldown/pluginutils@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "@rolldown/pluginutils@npm:1.0.0-rc.17" - checksum: 10c0/5e840b20cc531910c093c1ca36e550952cf4936465a50d89f0a98fc9d0dfd7d319d06a10a5f4376209d89e9bf4d60af6cc8363ebf0dcc5e60842f7fef438b2f0 +"@rolldown/pluginutils@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.18" + checksum: 10c0/c09f2ebe53762df23b725f452a3f7ee45968824b062a38ec06054e368551e8c5e1874b0ef28143ff3b1b9d6d5ca60177a34378bdd672e899c3646fb8d0bd5aff languageName: node linkType: hard @@ -678,9 +678,9 @@ __metadata: linkType: hard "@types/estree@npm:^1.0.0": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 languageName: node linkType: hard @@ -916,8 +916,8 @@ __metadata: adio: "npm:^3.0.0" fast-glob: "npm:^3.3.3" happy-dom: "npm:^20.9.0" - oxfmt: "npm:^0.47.0" - oxlint: "npm:^1.62.0" + oxfmt: "npm:^0.48.0" + oxlint: "npm:^1.63.0" pino: "npm:^10.3.1" pino-pretty: "npm:^13.1.3" type-fest: "npm:^5.6.0" @@ -1519,9 +1519,9 @@ __metadata: linkType: hard "lru-cache@npm:^11.0.0": - version: 11.3.5 - resolution: "lru-cache@npm:11.3.5" - checksum: 10c0/5b54ef7b88afb4bd25b7a778f1b2b1cde32d9770913e530da34ab203cf0442413bcaa6e372800cbab9562557a4480e4d8bf32e3a368bb5a91b12218eca085c66 + version: 11.3.6 + resolution: "lru-cache@npm:11.3.6" + checksum: 10c0/3afe3e3000e424c18b640dcea5776b5c1de8684b7dac9718d58792dff1a4692b38cc14e263cbb41bdab98ffcf5408f003b33133b179ce5d271284be72a3ff2a9 languageName: node linkType: hard @@ -1706,29 +1706,29 @@ __metadata: languageName: node linkType: hard -"oxfmt@npm:^0.47.0": - version: 0.47.0 - resolution: "oxfmt@npm:0.47.0" - dependencies: - "@oxfmt/binding-android-arm-eabi": "npm:0.47.0" - "@oxfmt/binding-android-arm64": "npm:0.47.0" - "@oxfmt/binding-darwin-arm64": "npm:0.47.0" - "@oxfmt/binding-darwin-x64": "npm:0.47.0" - "@oxfmt/binding-freebsd-x64": "npm:0.47.0" - "@oxfmt/binding-linux-arm-gnueabihf": "npm:0.47.0" - "@oxfmt/binding-linux-arm-musleabihf": "npm:0.47.0" - "@oxfmt/binding-linux-arm64-gnu": "npm:0.47.0" - "@oxfmt/binding-linux-arm64-musl": "npm:0.47.0" - "@oxfmt/binding-linux-ppc64-gnu": "npm:0.47.0" - "@oxfmt/binding-linux-riscv64-gnu": "npm:0.47.0" - "@oxfmt/binding-linux-riscv64-musl": "npm:0.47.0" - "@oxfmt/binding-linux-s390x-gnu": "npm:0.47.0" - "@oxfmt/binding-linux-x64-gnu": "npm:0.47.0" - "@oxfmt/binding-linux-x64-musl": "npm:0.47.0" - "@oxfmt/binding-openharmony-arm64": "npm:0.47.0" - "@oxfmt/binding-win32-arm64-msvc": "npm:0.47.0" - "@oxfmt/binding-win32-ia32-msvc": "npm:0.47.0" - "@oxfmt/binding-win32-x64-msvc": "npm:0.47.0" +"oxfmt@npm:^0.48.0": + version: 0.48.0 + resolution: "oxfmt@npm:0.48.0" + dependencies: + "@oxfmt/binding-android-arm-eabi": "npm:0.48.0" + "@oxfmt/binding-android-arm64": "npm:0.48.0" + "@oxfmt/binding-darwin-arm64": "npm:0.48.0" + "@oxfmt/binding-darwin-x64": "npm:0.48.0" + "@oxfmt/binding-freebsd-x64": "npm:0.48.0" + "@oxfmt/binding-linux-arm-gnueabihf": "npm:0.48.0" + "@oxfmt/binding-linux-arm-musleabihf": "npm:0.48.0" + "@oxfmt/binding-linux-arm64-gnu": "npm:0.48.0" + "@oxfmt/binding-linux-arm64-musl": "npm:0.48.0" + "@oxfmt/binding-linux-ppc64-gnu": "npm:0.48.0" + "@oxfmt/binding-linux-riscv64-gnu": "npm:0.48.0" + "@oxfmt/binding-linux-riscv64-musl": "npm:0.48.0" + "@oxfmt/binding-linux-s390x-gnu": "npm:0.48.0" + "@oxfmt/binding-linux-x64-gnu": "npm:0.48.0" + "@oxfmt/binding-linux-x64-musl": "npm:0.48.0" + "@oxfmt/binding-openharmony-arm64": "npm:0.48.0" + "@oxfmt/binding-win32-arm64-msvc": "npm:0.48.0" + "@oxfmt/binding-win32-ia32-msvc": "npm:0.48.0" + "@oxfmt/binding-win32-x64-msvc": "npm:0.48.0" tinypool: "npm:2.1.0" dependenciesMeta: "@oxfmt/binding-android-arm-eabi": @@ -1771,35 +1771,35 @@ __metadata: optional: true bin: oxfmt: bin/oxfmt - checksum: 10c0/2651c383e1a35d88e573a74e714e618cb0dcc0ec9c522dcbd822baa75aa2d793bd657d8abdfbb3e27f0a9886be174ebe620f842a7c0e86a18c7b591d59f649c1 - languageName: node - linkType: hard - -"oxlint@npm:^1.62.0": - version: 1.62.0 - resolution: "oxlint@npm:1.62.0" - dependencies: - "@oxlint/binding-android-arm-eabi": "npm:1.62.0" - "@oxlint/binding-android-arm64": "npm:1.62.0" - "@oxlint/binding-darwin-arm64": "npm:1.62.0" - "@oxlint/binding-darwin-x64": "npm:1.62.0" - "@oxlint/binding-freebsd-x64": "npm:1.62.0" - "@oxlint/binding-linux-arm-gnueabihf": "npm:1.62.0" - "@oxlint/binding-linux-arm-musleabihf": "npm:1.62.0" - "@oxlint/binding-linux-arm64-gnu": "npm:1.62.0" - "@oxlint/binding-linux-arm64-musl": "npm:1.62.0" - "@oxlint/binding-linux-ppc64-gnu": "npm:1.62.0" - "@oxlint/binding-linux-riscv64-gnu": "npm:1.62.0" - "@oxlint/binding-linux-riscv64-musl": "npm:1.62.0" - "@oxlint/binding-linux-s390x-gnu": "npm:1.62.0" - "@oxlint/binding-linux-x64-gnu": "npm:1.62.0" - "@oxlint/binding-linux-x64-musl": "npm:1.62.0" - "@oxlint/binding-openharmony-arm64": "npm:1.62.0" - "@oxlint/binding-win32-arm64-msvc": "npm:1.62.0" - "@oxlint/binding-win32-ia32-msvc": "npm:1.62.0" - "@oxlint/binding-win32-x64-msvc": "npm:1.62.0" + checksum: 10c0/8646b1dc45bac2b2444d5fedf5e26ef23be0b4319e3decf7e4e1b9604d2b5210ef947503adf5a6ffbaf26f34d674717691102923a081396981cc2ab1168332be + languageName: node + linkType: hard + +"oxlint@npm:^1.63.0": + version: 1.63.0 + resolution: "oxlint@npm:1.63.0" + dependencies: + "@oxlint/binding-android-arm-eabi": "npm:1.63.0" + "@oxlint/binding-android-arm64": "npm:1.63.0" + "@oxlint/binding-darwin-arm64": "npm:1.63.0" + "@oxlint/binding-darwin-x64": "npm:1.63.0" + "@oxlint/binding-freebsd-x64": "npm:1.63.0" + "@oxlint/binding-linux-arm-gnueabihf": "npm:1.63.0" + "@oxlint/binding-linux-arm-musleabihf": "npm:1.63.0" + "@oxlint/binding-linux-arm64-gnu": "npm:1.63.0" + "@oxlint/binding-linux-arm64-musl": "npm:1.63.0" + "@oxlint/binding-linux-ppc64-gnu": "npm:1.63.0" + "@oxlint/binding-linux-riscv64-gnu": "npm:1.63.0" + "@oxlint/binding-linux-riscv64-musl": "npm:1.63.0" + "@oxlint/binding-linux-s390x-gnu": "npm:1.63.0" + "@oxlint/binding-linux-x64-gnu": "npm:1.63.0" + "@oxlint/binding-linux-x64-musl": "npm:1.63.0" + "@oxlint/binding-openharmony-arm64": "npm:1.63.0" + "@oxlint/binding-win32-arm64-msvc": "npm:1.63.0" + "@oxlint/binding-win32-ia32-msvc": "npm:1.63.0" + "@oxlint/binding-win32-x64-msvc": "npm:1.63.0" peerDependencies: - oxlint-tsgolint: ">=0.18.0" + oxlint-tsgolint: ">=0.22.1" dependenciesMeta: "@oxlint/binding-android-arm-eabi": optional: true @@ -1844,7 +1844,7 @@ __metadata: optional: true bin: oxlint: bin/oxlint - checksum: 10c0/12045a9ab4054d25d56d55edf73e64dbe9418aeb84e46e5aacfbfe49a50a29d9897dc078e86c3a82c2adeec38df2e756431644d6df78a94265850952f49117bf + checksum: 10c0/ca3e0c36eb02be68494b900cf34242a4d5917a2f63e0bf7833aa017223f9768fa053228483dcb0b86eb077641e60b7c2e5960a3f5d0fa03145b4ee29748b44c6 languageName: node linkType: hard @@ -1967,14 +1967,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.10": - version: 8.5.13 - resolution: "postcss@npm:8.5.13" +"postcss@npm:^8.5.14": + version: 8.5.14 + resolution: "postcss@npm:8.5.14" dependencies: nanoid: "npm:^3.3.11" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10c0/3aa7c8cbdfbfd99b34406a433cef56d164dd135fc9cb9e63d487cc363291f877a55ec7b8ff6ec15348c17c2d98a43be46bfad671e6340403041a3e79f70c2f2f + checksum: 10c0/48138207cf5ef5581be1bfe2cb65ccfe0ac75e43888ba045afc8ed6043d7b56aeb3b9a9fe5b353ff554be943cd0cc15d826ccb991525159175971e5ee8ab0237 languageName: node linkType: hard @@ -2044,27 +2044,27 @@ __metadata: languageName: node linkType: hard -"rolldown@npm:1.0.0-rc.17": - version: 1.0.0-rc.17 - resolution: "rolldown@npm:1.0.0-rc.17" - dependencies: - "@oxc-project/types": "npm:=0.127.0" - "@rolldown/binding-android-arm64": "npm:1.0.0-rc.17" - "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.17" - "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.17" - "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.17" - "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.17" - "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.17" - "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.17" - "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.17" - "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.17" - "@rolldown/pluginutils": "npm:1.0.0-rc.17" +"rolldown@npm:1.0.0-rc.18": + version: 1.0.0-rc.18 + resolution: "rolldown@npm:1.0.0-rc.18" + dependencies: + "@oxc-project/types": "npm:=0.128.0" + "@rolldown/binding-android-arm64": "npm:1.0.0-rc.18" + "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.18" + "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.18" + "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.18" + "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.18" + "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.18" + "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.18" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.18" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.18" + "@rolldown/pluginutils": "npm:1.0.0-rc.18" dependenciesMeta: "@rolldown/binding-android-arm64": optional: true @@ -2098,7 +2098,7 @@ __metadata: optional: true bin: rolldown: bin/cli.mjs - checksum: 10c0/bb99abc62ece4e34edd06d2b8eb9ffb7194dc2f0465a4329bb106cbde3006a10f1575e3580b198b793341109a2109581aed623c537c12b0c3a4ba0d72169b2fb + checksum: 10c0/699b8545a9a8b85ed4c639122163a6f46f84404fd88262bafa9549b01546744db625fd4425fceb4658c888de1671323170de1f837f6f6bb93e243e6e1d48c114 languageName: node linkType: hard @@ -2202,15 +2202,15 @@ __metadata: linkType: hard "tar@npm:^7.5.4": - version: 7.5.13 - resolution: "tar@npm:7.5.13" + version: 7.5.14 + resolution: "tar@npm:7.5.14" dependencies: "@isaacs/fs-minipass": "npm:^4.0.0" chownr: "npm:^3.0.0" minipass: "npm:^7.1.2" minizlib: "npm:^3.1.0" yallist: "npm:^5.0.0" - checksum: 10c0/5c65b8084799bde7a791593a1c1a45d3d6ee98182e3700b24c247b7b8f8654df4191642abbdb07ff25043d45dcff35620827c3997b88ae6c12040f64bed5076b + checksum: 10c0/619573265fa45295ff0b378f1097ab43187ab7b66e9483d3ad8f467c287674fb182ec878ef50a08761b8ab487863cb429902cf65fe361d47e330a95bfc4ca9e8 languageName: node linkType: hard @@ -2301,18 +2301,18 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.0.10 - resolution: "vite@npm:8.0.10" + version: 8.0.11 + resolution: "vite@npm:8.0.11" dependencies: fsevents: "npm:~2.3.3" lightningcss: "npm:^1.32.0" picomatch: "npm:^4.0.4" - postcss: "npm:^8.5.10" - rolldown: "npm:1.0.0-rc.17" + postcss: "npm:^8.5.14" + rolldown: "npm:1.0.0-rc.18" tinyglobby: "npm:^0.2.16" peerDependencies: "@types/node": ^20.19.0 || >=22.12.0 - "@vitejs/devutils": ^0.1.0 + "@vitejs/devtools": ^0.1.18 esbuild: ^0.27.0 || ^0.28.0 jiti: ">=1.21.0" less: ^4.0.0 @@ -2329,7 +2329,7 @@ __metadata: peerDependenciesMeta: "@types/node": optional: true - "@vitejs/devutils": + "@vitejs/devtools": optional: true esbuild: optional: true @@ -2353,7 +2353,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/92188b82654f856dbe562a1b679de695bb6ca18c0f43c4c276f84a869fb78e22dedb7c2df83b5617d6afdca979c059d654b5f61a0936a45f49917f352b9325ca + checksum: 10c0/504ec6064761239e7063426dd123ea68cd540cb2d475bf72f5b1062313b9c79984831f56a20891ed5e08b2753d34171ee7a75cbadf9365e975d1f68634f0a10f languageName: node linkType: hard From dfde9a62f9d8cf44138a66a195060406f1c2698e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:33:27 +0200 Subject: [PATCH 2/8] chore(ci): add adio import check script and vitest coverage thresholds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit adio already installed but had no npm script — adding check:imports so CI and the pre-commit chain can call it uniformly. Coverage thresholds set at 90/80/90/90; current coverage is ~96%, giving ~6 points of headroom before CI breaks on regressions. --- vitest.config.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vitest.config.ts b/vitest.config.ts index e1a6c7c..0429f92 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -13,7 +13,13 @@ export default defineConfig({ coverage: { provider: "v8", include: ["src/**/*.ts"], - exclude: ["**/__tests__/**", "**/index.ts", "**/abstractions/**"] + exclude: ["**/__tests__/**", "**/index.ts", "**/abstractions/**"], + thresholds: { + statements: 90, + branches: 80, + functions: 90, + lines: 90 + } } } }); From 40137ca3d146acba5b24788d385943e9395cf343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:34:56 +0200 Subject: [PATCH 3/8] ci: add main quality-gate workflow Runs lockfile immutability, adio import check, format, lint, typecheck in parallel, then gates build on all passing, then runs test+coverage and pack dry-run in parallel. Also checks that dist/ is not committed. --- .github/workflows/ci.yml | 130 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..faca3d7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,130 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + lockfile: + name: Lockfile immutability + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + + dist-clean: + name: No committed dist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Verify dist is not tracked in git + run: | + tracked=$(git ls-files dist/) + if [ -n "$tracked" ]; then + echo "ERROR: dist/ files are committed to git:" + echo "$tracked" + echo "Fix: git rm -r --cached dist/" + exit 1 + fi + echo "OK: dist/ is not tracked" + + format: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn format:check + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn lint + + imports: + name: Import check (adio) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn check:imports + + typecheck: + name: Typecheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn typecheck + + build: + name: Build + needs: [lockfile, format, lint, imports, typecheck] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn build + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + retention-days: 1 + + test: + name: Test & Coverage + needs: [build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn test:coverage + + pack: + name: Pack dry-run + needs: [build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn build + - run: yarn pack:packages From 4f1d4c1f99eadf6c979e1a41dcfd517978661bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:36:11 +0200 Subject: [PATCH 4/8] ci: remove unused dist artifact upload from build job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither test (uses TS source via vitest alias) nor pack (rebuilds intentionally) downloads the artifact — the upload was pure waste. --- .github/workflows/ci.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faca3d7..7fed0a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,11 +96,6 @@ jobs: cache: yarn - run: yarn install --immutable - run: yarn build - - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ - retention-days: 1 test: name: Test & Coverage From f04182e681181f5230b0c1e9efe705b36b77633e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:36:51 +0200 Subject: [PATCH 5/8] ci: add dependency audit and dependency-review workflows yarn npm audit flags CVEs in installed deps on every push/PR. dependency-review-action blocks PRs that introduce newly vulnerable packages (PR-only because it requires a base ref to diff against). --- .github/workflows/audit.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/audit.yml diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 0000000..9a6f2f4 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,33 @@ +name: Audit + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + audit: + name: Dependency audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn npm audit + + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: actions/dependency-review-action@v4 From 69192a15bdb7b42aa90ce94ba08bee86da6126c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:37:56 +0200 Subject: [PATCH 6/8] ci: add PR title lint (conventional commits) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enforces the same commit types that the publish script uses for version bumping. An unknown type in a merged PR would cause process.exit(1) at release time — this gates it at PR review instead. --- .github/workflows/pr-title.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/pr-title.yml diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 0000000..4d454ef --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,31 @@ +name: PR Title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + title-lint: + name: Conventional commit title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + refactor + test + chore + docs + style + perf + build + ci + revert + requireScope: false From 8886ccb3fb2d9bba00a4c759d48cdb68ce42ea80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:41:12 +0200 Subject: [PATCH 7/8] ci: pin all GitHub Actions to immutable SHAs Mutable tag refs can be redirected to arbitrary commits if an action repo is compromised. SHA pins make the supply chain tamper-evident. --- .github/workflows/audit.yml | 8 ++++---- .github/workflows/ci.yml | 34 +++++++++++++++++----------------- .github/workflows/pr-title.yml | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 9a6f2f4..1e44133 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -13,8 +13,8 @@ jobs: name: Dependency audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -29,5 +29,5 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@v4 - - uses: actions/dependency-review-action@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7fed0a8..49b0878 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,8 @@ jobs: name: Lockfile immutability runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -24,7 +24,7 @@ jobs: name: No committed dist runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Verify dist is not tracked in git run: | tracked=$(git ls-files dist/) @@ -40,8 +40,8 @@ jobs: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -52,8 +52,8 @@ jobs: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -64,8 +64,8 @@ jobs: name: Import check (adio) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -76,8 +76,8 @@ jobs: name: Typecheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -89,8 +89,8 @@ jobs: needs: [lockfile, format, lint, imports, typecheck] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -102,8 +102,8 @@ jobs: needs: [build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn @@ -115,8 +115,8 @@ jobs: needs: [build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 cache: yarn diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index 4d454ef..c462000 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -12,7 +12,7 @@ jobs: name: Conventional commit title runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v5 + - uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From 676fb2808556254da948f845a1ceab8d9f380040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 7 May 2026 17:43:32 +0200 Subject: [PATCH 8/8] docs: add CI hardening implementation plan Records the plan used to drive the ci-hardening branch work. --- .../plans/2026-05-07-ci-hardening.md | 550 ++++++++++++++++++ 1 file changed, 550 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-07-ci-hardening.md diff --git a/docs/superpowers/plans/2026-05-07-ci-hardening.md b/docs/superpowers/plans/2026-05-07-ci-hardening.md new file mode 100644 index 0000000..b1961de --- /dev/null +++ b/docs/superpowers/plans/2026-05-07-ci-hardening.md @@ -0,0 +1,550 @@ +# CI Hardening Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add 14 CI checks to a repo that currently has no GitHub Actions workflows. + +**Architecture:** Four files change — `package.json` gets an `adio` script, `vitest.config.ts` gets coverage thresholds, and three new workflows cover quality gates (`ci.yml`), security (`audit.yml`), and PR title linting (`pr-title.yml`). The quality-gate workflow fans out as: static checks in parallel → build → test + pack in parallel. Pinning action SHAs is a dedicated clean-up task after the workflows are verified. + +**Tech Stack:** GitHub Actions, oxfmt, oxlint, adio, tsgo, vitest v4, yarn 4 (`yarn npm audit`), `actions/dependency-review-action`, `amannn/action-semantic-pull-request` + +--- + +## File Map + +| File | Change | +|------|--------| +| `package.json` | Add `"check:imports": "adio"` to `scripts` | +| `vitest.config.ts` | Add `coverage.thresholds` block | +| `.github/workflows/ci.yml` | Create — checks 10, 7, 1, 2, 3, 4, 5+6, 13, 14 | +| `.github/workflows/audit.yml` | Create — checks 8, 9 | +| `.github/workflows/pr-title.yml` | Create — check 12 | + +--- + +## Task 1: adio script + coverage threshold + +**Files:** +- Modify: `package.json` +- Modify: `vitest.config.ts` + +- [ ] **Step 1: Add `check:imports` to package.json scripts** + +In `package.json`, add after the `"lint:fix"` line: + +```json +"check:imports": "adio", +``` + +Final `scripts` block should contain: + +```json +"scripts": { + "clean": "rm -rf dist", + "build": "node scripts/buildPackages.ts", + "pack:packages": "node scripts/packPackages.ts", + "publish:packages": "node scripts/publishPackages.ts", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "format": "oxfmt", + "format:fix": "oxfmt", + "format:check": "oxfmt --check", + "lint": "oxlint --deny-warnings", + "lint:fix": "oxlint --fix", + "check:imports": "adio", + "typecheck": "tsgo -p tsconfig.check.common.json && tsgo -p tsconfig.check.node.json && tsgo -p tsconfig.check.browser.json && tsgo -p tsconfig.check.scripts.json" +} +``` + +- [ ] **Step 2: Add coverage thresholds to vitest.config.ts** + +Replace the existing `coverage` block in `vitest.config.ts`: + +```ts +coverage: { + provider: "v8", + include: ["src/**/*.ts"], + exclude: ["**/__tests__/**", "**/index.ts", "**/abstractions/**"], + thresholds: { + statements: 90, + branches: 80, + functions: 90, + lines: 90 + } +} +``` + +Note: current coverage is ~96% statements. The 90/80/90/90 floor gives ~6 points of headroom before CI breaks. + +- [ ] **Step 3: Verify both changes work locally** + +```sh +yarn check:imports +# Expected: ✅ All dependencies in order! + +yarn test:coverage +# Expected: all tests pass + coverage report shows thresholds satisfied +``` + +- [ ] **Step 4: Commit** + +```sh +git add package.json vitest.config.ts +git commit -m "$(cat <<'EOF' +chore(ci): add adio import check script and vitest coverage thresholds + +adio already installed but had no npm script — adding check:imports so +CI and the pre-commit chain can call it uniformly. + +Coverage thresholds set at 90/80/90/90; current coverage is ~96%, +giving ~6 points of headroom before CI breaks on regressions. +EOF +)" +``` + +--- + +## Task 2: Main CI workflow + +**Files:** +- Create: `.github/workflows/ci.yml` + +Job dependency graph: + +``` +lockfile ──────┐ +dist-clean │ (no dependents) +format ────────┤ +lint ──────────┤→ build → test +imports ───────┤ → pack +typecheck ─────┘ +``` + +`dist-clean` runs standalone (it's a pure git check — no install needed). All other early jobs run in parallel; `build` gates on all of them; `test` and `pack` gate on `build`. + +- [ ] **Step 1: Create `.github/workflows/ci.yml`** + +```yaml +name: CI + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + lockfile: + name: Lockfile immutability + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + + dist-clean: + name: No committed dist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Verify dist is not tracked in git + run: | + tracked=$(git ls-files dist/) + if [ -n "$tracked" ]; then + echo "ERROR: dist/ files are committed to git:" + echo "$tracked" + echo "Fix: git rm -r --cached dist/" + exit 1 + fi + echo "OK: dist/ is not tracked" + + format: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn format:check + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn lint + + imports: + name: Import check (adio) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn check:imports + + typecheck: + name: Typecheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn typecheck + + build: + name: Build + needs: [lockfile, format, lint, imports, typecheck] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn build + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + retention-days: 1 + + test: + name: Test & Coverage + needs: [build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn test:coverage + + pack: + name: Pack dry-run + needs: [build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn build + - run: yarn pack:packages +``` + +- [ ] **Step 2: Validate the YAML is well-formed** + +```sh +node -e " +const fs = require('fs'); +const yaml = require('js-yaml'); +try { + yaml.load(fs.readFileSync('.github/workflows/ci.yml', 'utf8')); + console.log('YAML valid'); +} catch(e) { console.error(e.message); process.exit(1); } +" 2>/dev/null || python3 -c " +import yaml, sys +with open('.github/workflows/ci.yml') as f: + yaml.safe_load(f) +print('YAML valid') +" +``` + +Expected: `YAML valid` + +- [ ] **Step 3: Commit** + +```sh +git add .github/workflows/ci.yml +git commit -m "$(cat <<'EOF' +ci: add main quality-gate workflow + +Runs lockfile immutability, adio import check, format, lint, typecheck +in parallel, then gates build on all passing, then runs test+coverage +and pack dry-run in parallel. Also checks that dist/ is not committed. +EOF +)" +``` + +--- + +## Task 3: Security / dependency audit workflow + +**Files:** +- Create: `.github/workflows/audit.yml` + +The dependency-review job uses `github.event_name == 'pull_request'` because the action requires a base ref to diff against — it cannot run on push. + +- [ ] **Step 1: Create `.github/workflows/audit.yml`** + +```yaml +name: Audit + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + audit: + name: Dependency audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: yarn + - run: yarn install --immutable + - run: yarn npm audit + + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: actions/dependency-review-action@v4 +``` + +- [ ] **Step 2: Verify YAML** + +```sh +python3 -c " +import yaml +with open('.github/workflows/audit.yml') as f: + yaml.safe_load(f) +print('YAML valid') +" +``` + +Expected: `YAML valid` + +- [ ] **Step 3: Commit** + +```sh +git add .github/workflows/audit.yml +git commit -m "$(cat <<'EOF' +ci: add dependency audit and dependency-review workflows + +yarn npm audit flags CVEs in installed deps on every push/PR. +dependency-review-action blocks PRs that introduce newly vulnerable +packages (PR-only because it requires a base ref to diff against). +EOF +)" +``` + +--- + +## Task 4: PR title lint workflow + +**Files:** +- Create: `.github/workflows/pr-title.yml` + +Allowed types mirror the exact set that the publish script (`scripts/features/PublishPackages/`) recognises. Any type not in this list causes `process.exit(1)` at release time, so the same set must be enforced here: `feat`, `fix`, `refactor`, `test`, `chore`, `docs`, `style`, `perf`, `build`, `ci`, `revert`. + +- [ ] **Step 1: Create `.github/workflows/pr-title.yml`** + +```yaml +name: PR Title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +permissions: + pull-requests: read + +jobs: + title-lint: + name: Conventional commit title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + refactor + test + chore + docs + style + perf + build + ci + revert + requireScope: false +``` + +- [ ] **Step 2: Verify YAML** + +```sh +python3 -c " +import yaml +with open('.github/workflows/pr-title.yml') as f: + yaml.safe_load(f) +print('YAML valid') +" +``` + +Expected: `YAML valid` + +- [ ] **Step 3: Commit** + +```sh +git add .github/workflows/pr-title.yml +git commit -m "$(cat <<'EOF' +ci: add PR title lint (conventional commits) + +Enforces the same commit types that the publish script uses for +version bumping. An unknown type in a merged PR would cause +process.exit(1) at release time — this gates it at PR review instead. +EOF +)" +``` + +--- + +## Task 5: Pin all action SHAs + +**Files:** +- Modify: `.github/workflows/ci.yml` +- Modify: `.github/workflows/audit.yml` +- Modify: `.github/workflows/pr-title.yml` + +Tag refs like `actions/checkout@v4` are mutable — a compromised tag can redirect to malicious code. SHA pins are immutable. + +- [ ] **Step 1: Resolve SHAs for each action** + +Run these `gh` commands to get the commit SHA for each tag: + +```sh +# actions/checkout — latest v4 tag +gh api repos/actions/checkout/git/ref/refs/tags/v4 --jq '.object.sha' +# or: gh release view --repo actions/checkout v4.2.2 --json tagName + +# actions/setup-node — latest v4 tag +gh api repos/actions/setup-node/git/ref/refs/tags/v4 --jq '.object.sha' + +# actions/upload-artifact — latest v4 tag +gh api repos/actions/upload-artifact/git/ref/refs/tags/v4 --jq '.object.sha' + +# actions/dependency-review-action — latest v4 tag +gh api repos/actions/dependency-review-action/git/ref/refs/tags/v4 --jq '.object.sha' + +# amannn/action-semantic-pull-request — latest v5 tag +gh api repos/amannn/action-semantic-pull-request/git/ref/refs/tags/v5 --jq '.object.sha' +``` + +Note: the SHA returned may be a tag object SHA, not a commit SHA. If so, dereference: + +```sh +gh api repos/actions/checkout/git/tags/ --jq '.object.sha' +``` + +- [ ] **Step 2: Replace tag refs with SHA@tag-comment form across all three workflow files** + +Replace every `uses: @` with `uses: @ # `. + +Example substitution (use actual SHAs from Step 1): + +```yaml +# Before +- uses: actions/checkout@v4 + +# After (SHA is illustrative — use the value from Step 1) +- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 +``` + +Apply this to every `uses:` line in all three workflow files: +- `actions/checkout@v4` +- `actions/setup-node@v4` +- `actions/upload-artifact@v4` +- `actions/dependency-review-action@v4` +- `amannn/action-semantic-pull-request@v5` + +- [ ] **Step 3: Verify all three files are still valid YAML** + +```sh +python3 -c " +import yaml, glob +for f in glob.glob('.github/workflows/*.yml'): + with open(f) as fh: + yaml.safe_load(fh) + print(f'OK: {f}') +" +``` + +Expected: three `OK:` lines, one per workflow file. + +- [ ] **Step 4: Commit** + +```sh +git add .github/workflows/ +git commit -m "$(cat <<'EOF' +ci: pin all GitHub Actions to immutable SHAs + +Mutable tag refs can be redirected to arbitrary commits if an action +repo is compromised. SHA pins make the supply chain tamper-evident. +EOF +)" +``` + +--- + +## Self-Review + +**Spec coverage:** + +| Check | Task | +|-------|------| +| 10 — lockfile immutability | Task 2 (`lockfile` job) | +| 7 — adio imports | Task 1 (script) + Task 2 (`imports` job) | +| 1 — format check | Task 2 (`format` job) | +| 2 — lint | Task 2 (`lint` job) | +| 3 — typecheck | Task 2 (`typecheck` job) | +| 4 — build | Task 2 (`build` job) | +| 5 — tests + coverage | Task 2 (`test` job) | +| 6 — coverage threshold | Task 1 (vitest thresholds) | +| 8 — yarn audit | Task 3 (`audit` job) | +| 9 — dependency review | Task 3 (`dependency-review` job) | +| 11 — pinned action SHAs | Task 5 | +| 12 — PR title lint | Task 4 | +| 13 — pack dry-run | Task 2 (`pack` job) | +| 14 — no committed dist | Task 2 (`dist-clean` job) | + +All 14 checks covered. ✓