diff --git a/.github/workflows/dead-code-pr.yml b/.github/workflows/dead-code-pr.yml new file mode 100644 index 00000000..452bcd4b --- /dev/null +++ b/.github/workflows/dead-code-pr.yml @@ -0,0 +1,64 @@ +name: dead-code-pr +# Advisory dead-code detection gate (issue #282, cairn MVG gate #6). +# Steps use continue-on-error so findings surface as annotations without +# blocking the merge queue. Flips to required/blocking once the knip +# baseline (knip-baseline.json) is driven to zero. The eslint no-unused-vars +# half of the gate is already blocking via the `build` check. +on: + pull_request: {} + merge_group: {} + workflow_dispatch: {} + +permissions: + contents: read + +concurrency: + group: dead-code-pr-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + dead-code: + name: Dead-code detection (advisory) + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + env: + CI: "true" + MISE_EXPERIMENTAL: "1" + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Install mise + uses: jdx/mise-action@dba19683ed58901619b14f395a24841710cb4925 # v4.1.0 + with: + cache: true + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22.x + + - name: Install dependencies + run: mise run install + + - name: TS dead-code ratchet (knip, advisory) + continue-on-error: true + run: | + if mise run check:deadcode-ratchet; then + echo "::notice title=knip ratchet::Dead-code count is at or below baseline." + else + echo "::warning title=knip ratchet::Dead-code count increased above the baseline (knip-baseline.json). Run 'yarn knip' locally and remove the new dead code, or suppress a false positive in knip.json." + fi + + - name: Python dead-code scan (vulture, advisory) + continue-on-error: true + run: | + if mise //agent:lint:deadcode; then + echo "::notice title=vulture::No Python dead code above the confidence threshold." + else + echo "::warning title=vulture::vulture found unused Python code. Remove it, or add an intentional keep to agent/.vulture_allowlist.py." + fi diff --git a/agent/.vulture_allowlist.py b/agent/.vulture_allowlist.py new file mode 100644 index 00000000..7f59bc59 --- /dev/null +++ b/agent/.vulture_allowlist.py @@ -0,0 +1,23 @@ +# Vulture allowlist (issue #282, cairn MVG gate #6). +# +# Names here are reported by vulture as unused but are intentionally kept. +# vulture "uses" every attribute access in this file, so listing a name +# suppresses its finding. Only entries that fire at `--min-confidence 80` +# (the CI threshold) belong here — lower-confidence noise (Pydantic +# `model_config`, FastAPI route handlers, dynamically-dispatched methods) +# is below the threshold and must NOT be blanket-allowlisted, so that real +# dead code in those forms still surfaces. +# +# Regenerate/extend (then hand-review the diff): +# cd agent && uvx vulture src --make-whitelist +# +# Keep this list MINIMAL. Prefer deleting dead code over allowlisting it. + +# claude-agent-sdk invokes hooks positionally as +# (hook_input, tool_use_id, hook_context). The dispatcher in hooks.py passes +# its own `ctx`, so the `hook_context` positional is part of the required +# signature but unread in these three hook bodies. Cannot be removed without +# breaking the SDK calling convention. +hook_context # unused variable (src/hooks.py:132) +hook_context # unused variable (src/hooks.py:918) +hook_context # unused variable (src/hooks.py:1258) diff --git a/agent/mise.toml b/agent/mise.toml index 069de8ea..ce24de3c 100644 --- a/agent/mise.toml +++ b/agent/mise.toml @@ -44,6 +44,10 @@ run = "uvx ruff format --check" description = "Type check with ty" run = "uv run ty check" +[tasks."lint:deadcode"] +description = "Dead-code detection with vulture (#282, cairn MVG gate #6): unused functions/classes/methods ruff F cannot see. Config + allowlist in pyproject.toml / .vulture_allowlist.py." +run = "uv run vulture" + [tasks.test] description = "Run tests with pytest (coverage floor enforced; use `uv run pytest --no-cov` for focused runs)" run = "uv run pytest --cov=src --cov-branch --cov-fail-under=72 --cov-report=term-missing:skip-covered --cov-report=lcov:coverage/lcov.info --cov-report=json:coverage/coverage.json" diff --git a/agent/pyproject.toml b/agent/pyproject.toml index d21f340c..89aa4bee 100644 --- a/agent/pyproject.toml +++ b/agent/pyproject.toml @@ -55,6 +55,14 @@ constraint-dependencies = [ "pydantic-settings>=2.14.2", # GHSA-4xgf-cpjx-pc3j — transitive via mcp; remove when mcp bumps floor ] +# Dead-code detection (#282, cairn MVG gate #6). ruff "F" catches unused +# imports/locals; vulture catches unused module-level functions/classes/methods +# that ruff cannot see. min_confidence 80 keeps the signal high; intentional +# keeps (e.g. SDK-mandated hook params) live in .vulture_allowlist.py. +[tool.vulture] +paths = ["src", ".vulture_allowlist.py"] +min_confidence = 80 + [tool.bandit] exclude_dirs = ["tests", ".venv"] skips = [ @@ -73,11 +81,16 @@ dev = [ "pytest", "pygments==2.20.0", "pytest-cov==7.1.0", + "vulture==2.16", # dead-code detection (#282): unused functions/classes ruff F can't see ] [tool.ruff] target-version = "py313" line-length = 100 +# The vulture allowlist is bare-name expressions by design (that is how vulture +# "uses" a name to suppress it). ruff would flag every line F821/B018, so it is +# not Python source ruff should lint. See .vulture_allowlist.py (#282). +extend-exclude = [".vulture_allowlist.py"] [tool.ruff.lint] select = [ @@ -124,3 +137,9 @@ skip_covered = true [tool.ty.environment] python-version = "3.13" extra-paths = ["src"] + +[tool.ty.src] +# The vulture allowlist is bare-name expressions by design, not type-checkable +# Python — ty flags each line unresolved-reference. Excluded here for the same +# reason ruff excludes it via extend-exclude (#282). +exclude = [".vulture_allowlist.py"] diff --git a/agent/uv.lock b/agent/uv.lock index 04010e22..24400215 100644 --- a/agent/uv.lock +++ b/agent/uv.lock @@ -158,6 +158,7 @@ dev = [ { name = "pytest-cov" }, { name = "ruff" }, { name = "ty" }, + { name = "vulture" }, ] [package.metadata] @@ -182,6 +183,7 @@ dev = [ { name = "pytest-cov", specifier = "==7.1.0" }, { name = "ruff" }, { name = "ty" }, + { name = "vulture", specifier = "==2.16" }, ] [[package]] @@ -2183,6 +2185,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/41/ac2dfdbc1f60c7af4f994c7a335cfa7040c01642b605d65f611cecc2a1e4/uvicorn-0.47.0-py3-none-any.whl", hash = "sha256:2c5715bc12d1892d84752049f400cd1c3cb018514967fdfeb97640443a6a9432", size = 71301, upload-time = "2026-05-14T18:16:51.762Z" }, ] +[[package]] +name = "vulture" +version = "2.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/3e/4d08c5903b2c0c70cad583c170cc4a663fc6a61e2ad00b711fcda61358cd/vulture-2.16.tar.gz", hash = "sha256:f8d9f6e2af03011664a3c6c240c9765b3f392917d3135fddca6d6a68d359f717", size = 52680, upload-time = "2026-03-25T14:41:27.141Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/be/f935130312330614811dae2ea9df3f395f6d63889eb6c2e68c14507152ee/vulture-2.16-py3-none-any.whl", hash = "sha256:6e0f1c312cef1c87856957e5c2ca9608834a7c794c2180477f30bf0e4cc58eee", size = 26993, upload-time = "2026-03-25T14:41:26.21Z" }, +] + [[package]] name = "websockets" version = "16.0" diff --git a/cdk/eslint.config.mjs b/cdk/eslint.config.mjs index 6ff27c2b..fbd92691 100644 --- a/cdk/eslint.config.mjs +++ b/cdk/eslint.config.mjs @@ -156,6 +156,19 @@ export default [ }], // TypeScript rules + // Dead-code parity with Python ruff F401 (#282): unused imports/locals/params + // are errors. `^_` opts out an intentionally-unused binding. Base rule must be + // off so the typescript-eslint variant (type-aware) is the only one active. + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + args: 'all', + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + ignoreRestSiblings: true, + destructuredArrayIgnorePattern: '^_', + }], // AI007 guard (#258): inline numeric literals should be named constants. // Values shared across Python/TypeScript belong in contracts/constants.json // (see contracts/constants.md). Baseline cleaned in #312; blocking like cli/. diff --git a/cdk/src/bootstrap/index.ts b/cdk/src/bootstrap/index.ts deleted file mode 100644 index 68432c5a..00000000 --- a/cdk/src/bootstrap/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * MIT No Attribution - * - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -export { infrastructurePolicy, applicationPolicy, observabilityPolicy, allPolicies } from './policies'; -export { BOOTSTRAP_VERSION, computeBootstrapHash } from './version'; diff --git a/cdk/src/handlers/confirm-uploads.ts b/cdk/src/handlers/confirm-uploads.ts index 2457a4d3..a45da344 100644 --- a/cdk/src/handlers/confirm-uploads.ts +++ b/cdk/src/handlers/confirm-uploads.ts @@ -294,9 +294,9 @@ export async function handler(event: APIGatewayProxyEvent, context: Context): Pr async function screenSingleAttachment( att: AttachmentRecord, - task: TaskRecord, + _task: TaskRecord, screeningConfig: ScreeningConfig, - taskId: string, + _taskId: string, meta: S3ObjectMeta, ): Promise { const { s3Key, versionId, sizeBytes } = meta; @@ -530,7 +530,7 @@ async function transitionToSubmitted( // --------------------------------------------------------------------------- async function failTaskOnScreening( - task: TaskRecord, + _task: TaskRecord, taskId: string, filename: string, reason: string, diff --git a/cdk/src/handlers/shared/create-task-core.ts b/cdk/src/handlers/shared/create-task-core.ts index 447d6812..b9482753 100644 --- a/cdk/src/handlers/shared/create-task-core.ts +++ b/cdk/src/handlers/shared/create-task-core.ts @@ -53,7 +53,7 @@ import { type TaskRecord, toTaskDetail, } from './types'; -import { computeTtlEpoch, DEFAULT_MAX_TURNS, hasTaskSpec, isValidIdempotencyKey, isValidRepo, isValidTaskDescriptionLength, MAX_ATTACHMENT_SIZE_BYTES, MAX_TASK_DESCRIPTION_LENGTH, validateAttachments, validateMaxBudgetUsd, validateMaxTurns, validatePrNumber } from './validation'; +import { computeTtlEpoch, hasTaskSpec, isValidIdempotencyKey, isValidRepo, isValidTaskDescriptionLength, MAX_ATTACHMENT_SIZE_BYTES, MAX_TASK_DESCRIPTION_LENGTH, validateAttachments, validateMaxBudgetUsd, validateMaxTurns, validatePrNumber } from './validation'; import { disallowedWorkflowModel, getWorkflowDescriptor, isValidWorkflowRef, resolveWorkflowRef, resolveWorkflowRefError } from './workflows'; import { ATTACHMENT_OBJECT_KEY_PREFIX } from '../../constructs/attachments-bucket'; import { TaskStatus } from '../../constructs/task-status'; @@ -522,7 +522,6 @@ export async function createTaskCore( if (att.delivery !== 'presigned') continue; const presignedAtt = att as PresignedAttachment; const attachmentId = ulid(); - const s3Key = `${ATTACHMENT_OBJECT_KEY_PREFIX}${context.userId}/${taskId}/${attachmentId}/${presignedAtt.filename}`; attachmentRecords.push(createAttachmentRecord({ attachment_id: attachmentId, diff --git a/cdk/src/handlers/shared/linear-verify.ts b/cdk/src/handlers/shared/linear-verify.ts index 4b1dfb42..deff3baf 100644 --- a/cdk/src/handlers/shared/linear-verify.ts +++ b/cdk/src/handlers/shared/linear-verify.ts @@ -28,9 +28,6 @@ import { logger } from './logger'; const sm = new SecretsManagerClient({}); const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({})); -/** Prefix for Linear-related secrets in Secrets Manager. */ -export const LINEAR_SECRET_PREFIX = 'bgagent/linear/'; - // In-memory secret cache with 5-minute TTL (same pattern as slack-verify.ts). const secretCache = new Map(); const CACHE_TTL_MINUTES = 5; diff --git a/cdk/src/handlers/shared/validation.ts b/cdk/src/handlers/shared/validation.ts index 763a54f4..e30405dd 100644 --- a/cdk/src/handlers/shared/validation.ts +++ b/cdk/src/handlers/shared/validation.ts @@ -286,7 +286,15 @@ export const MAX_TOTAL_ATTACHMENT_SIZE_BYTES = MAX_TOTAL_ATTACHMENT_SIZE_MB * 10 /** Compile-time exhaustiveness check for AttachmentType. */ const ATTACHMENT_TYPE_LIST = ['image', 'file', 'url'] as const satisfies readonly AttachmentType[]; type _AssertAttachmentExhaustive = Exclude extends never ? true : never; +// The ASSIGNMENT is the guard: if AttachmentType gains a member missing from +// ATTACHMENT_TYPE_LIST, _AssertAttachmentExhaustive resolves to `never` and +// assigning `true` is a hard compile error. (A `true as never` assertion would +// NOT error — assertions are permitted whenever either side is assignable — so +// it must stay an assignment.) `void` consumes the binding to satisfy +// tsconfig noUnusedLocals, which — unlike @typescript-eslint/no-unused-vars, +// already exempt via its ^_ varsIgnorePattern — does not honor the _ prefix. const _attachmentExhaustiveCheck: _AssertAttachmentExhaustive = true; +void _attachmentExhaustiveCheck; const VALID_ATTACHMENT_TYPES = new Set(ATTACHMENT_TYPE_LIST); /** Allowed image MIME types (PNG and JPEG only — passed directly to Bedrock). */ @@ -411,7 +419,7 @@ export function isValidFilename(filename: string): boolean { } /** Generate a default filename when none was provided. */ -function generateFilename(type: string, contentType: string, index: number): string { +function generateFilename(_type: string, contentType: string, index: number): string { const ext = MIME_TO_EXTENSION[contentType] ?? 'bin'; return `attachment_${index}.${ext}`; } diff --git a/cdk/test/handlers/confirm-uploads.test.ts b/cdk/test/handlers/confirm-uploads.test.ts index 7ece5931..dfa211fc 100644 --- a/cdk/test/handlers/confirm-uploads.test.ts +++ b/cdk/test/handlers/confirm-uploads.test.ts @@ -234,9 +234,7 @@ describe('confirm-uploads handler', () => { }); // Use mockImplementation for S3 calls to handle interleaving - let s3CallCount = 0; s3Send.mockImplementation((cmd: any) => { - s3CallCount++; if (cmd._type === 'S3Head') { // HeadObject — return valid metadata const isAtt1 = cmd.input.Key?.includes('att-1'); diff --git a/cdk/test/handlers/shared/context-hydration.test.ts b/cdk/test/handlers/shared/context-hydration.test.ts index 1e2f92dc..c8171dc9 100644 --- a/cdk/test/handlers/shared/context-hydration.test.ts +++ b/cdk/test/handlers/shared/context-hydration.test.ts @@ -54,7 +54,6 @@ import { hydrateContext, resolveGitHubToken, screenWithGuardrail, - type ContentTrustLevel, type GitHubIssueContext, type GuardrailScreeningResult, type IssueComment, diff --git a/cdk/test/handlers/shared/resolve-url-attachments.test.ts b/cdk/test/handlers/shared/resolve-url-attachments.test.ts index 8a80374d..77034d75 100644 --- a/cdk/test/handlers/shared/resolve-url-attachments.test.ts +++ b/cdk/test/handlers/shared/resolve-url-attachments.test.ts @@ -166,7 +166,7 @@ jest.mock('../../../src/handlers/shared/logger', () => ({ describe('resolveUrlAttachments', () => { const dns = jest.requireMock('dns').promises; const { screenImage } = jest.requireMock('../../../src/handlers/shared/attachment-screening'); - const { isAllowedMimeType, validateMagicBytes } = jest.requireMock('../../../src/handlers/shared/validation'); + const { isAllowedMimeType } = jest.requireMock('../../../src/handlers/shared/validation'); const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); diff --git a/cdk/test/handlers/slack-command-processor.test.ts b/cdk/test/handlers/slack-command-processor.test.ts index f5d299da..d96e0805 100644 --- a/cdk/test/handlers/slack-command-processor.test.ts +++ b/cdk/test/handlers/slack-command-processor.test.ts @@ -121,7 +121,7 @@ describe('slack-command-processor handler', () => { test('slash submit tells user to use @mention', async () => { await handler(slashCommand({ text: 'submit org/repo fix' })); const posted = fetchMock.mock.calls.find( - ([url, opts]) => String((opts as { body: string }).body).includes('Use `@Shoof` to submit tasks'), + ([_url, opts]) => String((opts as { body: string }).body).includes('Use `@Shoof` to submit tasks'), ); expect(posted).toBeTruthy(); expect(createTaskCoreMock).not.toHaveBeenCalled(); @@ -215,7 +215,7 @@ describe('slack-command-processor handler', () => { expect(putCall![0].input.Item.slack_identity).toMatch(/^pending#/); expect(putCall![0].input.Item.status).toBe('pending'); const posted = fetchMock.mock.calls.find( - ([url, opts]) => String((opts as { body: string }).body).includes('bgagent slack link'), + ([_url, opts]) => String((opts as { body: string }).body).includes('bgagent slack link'), ); expect(posted).toBeTruthy(); }); @@ -223,7 +223,7 @@ describe('slack-command-processor handler', () => { test('help subcommand replies with usage text', async () => { await handler(slashCommand({ text: 'help' })); const posted = fetchMock.mock.calls.find( - ([url, opts]) => String((opts as { body: string }).body).includes('Using Shoof'), + ([_url, opts]) => String((opts as { body: string }).body).includes('Using Shoof'), ); expect(posted).toBeTruthy(); }); diff --git a/cdk/tsconfig.json b/cdk/tsconfig.json index eca6683a..3ec29eea 100644 --- a/cdk/tsconfig.json +++ b/cdk/tsconfig.json @@ -18,8 +18,8 @@ "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, - "noUnusedLocals": false, - "noUnusedParameters": false, + "noUnusedLocals": true, + "noUnusedParameters": true, "resolveJsonModule": true, "strict": true, "strictNullChecks": true, diff --git a/cli/eslint.config.mjs b/cli/eslint.config.mjs index 9aa34e99..1165c7bf 100644 --- a/cli/eslint.config.mjs +++ b/cli/eslint.config.mjs @@ -153,6 +153,19 @@ export default [ }], // TypeScript rules + // Dead-code parity with Python ruff F401 (#282): unused imports/locals/params + // are errors. `^_` opts out an intentionally-unused binding. Base rule must be + // off so the typescript-eslint variant (type-aware) is the only one active. + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + args: 'all', + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + ignoreRestSiblings: true, + destructuredArrayIgnorePattern: '^_', + }], // AI007 guard (#258): inline numeric literals should be named constants. // Values shared across Python/TypeScript belong in contracts/constants.json // (see contracts/constants.md). diff --git a/cli/src/linear-oauth.ts b/cli/src/linear-oauth.ts index 5975478e..7a5024ea 100644 --- a/cli/src/linear-oauth.ts +++ b/cli/src/linear-oauth.ts @@ -253,7 +253,7 @@ async function parseTokenResponse( let body: unknown; try { body = await response.json(); - } catch (err) { + } catch (_err) { throw new CliError( `Linear /oauth/token returned non-JSON during ${contextLabel}: HTTP ${response.status}`, ); diff --git a/cli/test/commands/github-token.test.ts b/cli/test/commands/github-token.test.ts index fbe5cfd6..37a85781 100644 --- a/cli/test/commands/github-token.test.ts +++ b/cli/test/commands/github-token.test.ts @@ -17,7 +17,7 @@ * SOFTWARE. */ -import { GetSecretValueCommand, PutSecretValueCommand } from '@aws-sdk/client-secrets-manager'; +import { PutSecretValueCommand } from '@aws-sdk/client-secrets-manager'; import { GetCommand } from '@aws-sdk/lib-dynamodb'; import { CliError } from '../../src/errors'; import { diff --git a/knip-baseline.json b/knip-baseline.json new file mode 100644 index 00000000..5349b3e4 --- /dev/null +++ b/knip-baseline.json @@ -0,0 +1,4 @@ +{ + "count": 78, + "comment": "Dead-code ratchet baseline for issue #282 (cairn MVG gate #6). This is the knip issue count at the time the gate was introduced — pre-existing unused exports/types that are out of scope to remove in the gate PR. The ratchet (scripts/check-deadcode-ratchet.mjs) fails the build only if the count rises above this number. When dead code is removed and the count drops, lower this value in the same PR to lock in the gain. Per-category false positives belong in knip.json, not here." +} diff --git a/knip.json b/knip.json new file mode 100644 index 00000000..77cbfed1 --- /dev/null +++ b/knip.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "ignore": [ + ".semgrep/**", + "scripts/**" + ], + "ignoreBinaries": [ + "mise" + ], + "workspaces": { + "cdk": { + "entry": ["src/main.ts!", "src/handlers/*.ts!"], + "project": ["src/**/*.ts!"], + "ignoreDependencies": ["esbuild", "ts-node", "@aws-cdk/integ-runner", "@aws-cdk/integ-tests-alpha"] + }, + "cli": { + "entry": ["src/bin/bgagent.ts!", "src/index.ts!"], + "project": ["src/**/*.ts!"] + }, + "docs": { + "entry": ["astro.config.mjs", "src/content.config.ts", "src/components/**/*.astro"], + "project": ["src/**/*.{astro,ts,tsx}"], + "ignoreDependencies": ["@astrojs/check", "remark-gfm", "@pagefind/default-ui", "jest"] + } + } +} diff --git a/mise.toml b/mise.toml index d9cf5bb8..cc7c577f 100644 --- a/mise.toml +++ b/mise.toml @@ -94,6 +94,14 @@ run = "node --experimental-strip-types scripts/check-coverage-thresholds-sync.ts description = "Generate commands stubs from .abca/commands for multiple AI assistants" run = "node scripts/sync-abca-commands.mjs" +[tasks.deadcode] +description = "Dead-code detection across TS workspaces via knip (#282, cairn MVG gate #6). Lists unused files/exports/deps; run `yarn knip --fix` locally to auto-remove." +run = "yarn knip" + +[tasks."check:deadcode-ratchet"] +description = "Dead-code ratchet (#282): fail only if knip's issue count rises above knip-baseline.json. Advisory in CI for now; flips to blocking once the baseline is driven to zero." +run = "node scripts/check-deadcode-ratchet.mjs" + [tasks."drift-prevention"] description = "Run checks to prevent drift in contracts between packages" run = [ diff --git a/package.json b/package.json index 714aef1e..ab5f02e2 100644 --- a/package.json +++ b/package.json @@ -14,10 +14,12 @@ ], "scripts": { "install:all": "MISE_EXPERIMENTAL=1 mise run install", - "build": "MISE_EXPERIMENTAL=1 mise run build" + "build": "MISE_EXPERIMENTAL=1 mise run build", + "knip": "knip" }, "devDependencies": { - "@astrojs/check": "^0.9.8" + "@astrojs/check": "^0.9.8", + "knip": "6.20.0" }, "resolutions": { "basic-ftp": "^5.2.2", diff --git a/scripts/check-deadcode-ratchet.mjs b/scripts/check-deadcode-ratchet.mjs new file mode 100644 index 00000000..d7430f9d --- /dev/null +++ b/scripts/check-deadcode-ratchet.mjs @@ -0,0 +1,138 @@ +#!/usr/bin/env node +/** + * MIT No Attribution + * + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Dead-code ratchet for the TS project graph (issue #282, cairn MVG gate #6). + * + * knip has no native baseline file, so this wraps it: run knip in JSON mode, + * count the issues, and compare against the committed baseline in + * `knip-baseline.json`. The build fails only when the count *increases* — the + * cairn "dead-code count should not increase" metric. When the count drops + * (someone cleaned up), it prints the new lower number so the baseline can be + * tightened in the same PR. + * + * Counted categories are knip 6.x's array-valued issue keys (unused files, + * dependencies, unlisted/unresolved, binaries, exports, types, enum and + * namespace members, duplicates, catalog) — see COUNTED_KEYS below. + * Per-category false positives are suppressed in `knip.json`, not here. + */ + +import { execFileSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..'); +const baselinePath = join(repoRoot, 'knip-baseline.json'); + +// knip 6.x emits one issues[] entry per file; each entry carries these +// array-valued issue keys. `file` and `owners` are labels, not findings, so +// they are excluded. `files` (unused files) is counted here — knip lists them +// inside issues[].files[], NOT at the top level. `duplicates` is an +// array-of-arrays (one inner array per duplicate group), so its `.length` +// counts groups, which is the unit we ratchet on. +// +// This is the complete set of countable keys for the installed knip (6.20.0, +// pinned exactly). There is no `nsExports`/`nsTypes`/`classMembers` in this +// schema — namespace/enum members surface as `namespaceMembers`/`enumMembers`. +// If knip is bumped, re-derive this list from its JSON (the countIssues guard +// below will fail loud if the top-level shape changes). +const COUNTED_KEYS = [ + 'files', + 'dependencies', + 'devDependencies', + 'optionalPeerDependencies', + 'unlisted', + 'binaries', + 'unresolved', + 'exports', + 'types', + 'duplicates', + 'enumMembers', + 'namespaceMembers', + 'catalog', +]; + +function runKnip() { + const knipBin = join(repoRoot, 'node_modules', '.bin', 'knip'); + // knip exits non-zero when it finds issues; that is expected here — we parse + // its JSON regardless and decide pass/fail from the count vs. the baseline. + let stdout; + try { + stdout = execFileSync(knipBin, ['--reporter', 'json', '--no-progress'], { + cwd: repoRoot, + encoding: 'utf8', + maxBuffer: 64 * 1024 * 1024, + }); + } catch (err) { + stdout = err.stdout?.toString() ?? ''; + if (!stdout.trim()) { + console.error('check-deadcode-ratchet: knip produced no JSON output.'); + console.error(err.stderr?.toString() ?? String(err)); + process.exit(2); + } + } + return JSON.parse(stdout); +} + +function countIssues(report) { + // Fail loud, not open: if a future knip reshapes its JSON so `issues` is no + // longer an array, `?? []` would yield count 0 — silently below any baseline, + // reporting a passing build and disabling the gate. Require the array shape so + // a schema change surfaces as an error instead. (knip is pinned exactly in + // package.json to make such a change a deliberate, reviewed bump.) + if (!Array.isArray(report.issues)) { + console.error( + 'check-deadcode-ratchet: knip JSON has no `issues` array — its output schema may have changed. ' + + 'Re-validate COUNTED_KEYS against the installed knip before trusting the count.', + ); + process.exit(2); + } + let total = 0; + for (const issue of report.issues) { + for (const key of COUNTED_KEYS) { + if (Array.isArray(issue[key])) total += issue[key].length; + } + } + return total; +} + +const baseline = JSON.parse(readFileSync(baselinePath, 'utf8')).count; +const current = countIssues(runKnip()); + +if (current > baseline) { + console.error( + `❌ Dead-code count increased: ${current} (baseline ${baseline}, +${current - baseline}).`, + ); + console.error(' Run `yarn knip` to see the new findings, then remove the dead code.'); + console.error(' If a finding is a false positive, suppress it in knip.json (not the baseline).'); + process.exit(1); +} + +if (current < baseline) { + console.log( + `✅ Dead-code count dropped to ${current} (baseline ${baseline}). ` + + `Lower the "count" in knip-baseline.json to ${current} to ratchet it down.`, + ); + process.exit(0); +} + +console.log(`✅ Dead-code count holding at baseline (${current}).`); +process.exit(0); diff --git a/yarn.lock b/yarn.lock index ca1d67f7..3b98810a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1539,6 +1539,22 @@ "@emnapi/wasi-threads" "1.2.1" tslib "^2.4.0" +"@emnapi/core@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.11.0.tgz#8a655042dbbb10d0266670c9903c34a7001c705b" + integrity sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q== + dependencies: + "@emnapi/wasi-threads" "1.2.2" + tslib "^2.4.0" + +"@emnapi/core@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.11.1.tgz#b9e1064f3a6b1631e241e638eb48d736bfd372a6" + integrity sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ== + dependencies: + "@emnapi/wasi-threads" "1.2.2" + tslib "^2.4.0" + "@emnapi/runtime@1.10.0": version "1.10.0" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.10.0.tgz#4b260c0d3534204e98c6110b8db1a987d26ec87c" @@ -1546,7 +1562,14 @@ dependencies: tslib "^2.4.0" -"@emnapi/runtime@^1.7.0": +"@emnapi/runtime@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.11.0.tgz#ce16b3674ff7266bbf50f9668bde8a04f3014d4e" + integrity sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg== + dependencies: + tslib "^2.4.0" + +"@emnapi/runtime@1.11.1", "@emnapi/runtime@^1.7.0": version "1.11.1" resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.11.1.tgz#58f1f3d5d81a9b12f793ab688c96371901027c24" integrity sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw== @@ -1560,6 +1583,13 @@ dependencies: tslib "^2.4.0" +"@emnapi/wasi-threads@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz#4c93becf5bfa3b13d1bbdcc06aee38321ad8139a" + integrity sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA== + dependencies: + tslib "^2.4.0" + "@es-joy/jsdoccomment@~0.86.0": version "0.86.0" resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz#f7276904ed73bf2136993627033aeb5183b4392a" @@ -2296,6 +2326,13 @@ dependencies: "@tybys/wasm-util" "^0.10.2" +"@napi-rs/wasm-runtime@^1.1.5": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz#ed33806d0f9be98dc76d0c3d4fd872fda701b5d5" + integrity sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg== + dependencies: + "@tybys/wasm-util" "^0.10.3" + "@nodable/entities@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@nodable/entities/-/entities-2.2.0.tgz#a1d45a992b022591b1c2b03a77935c939375b642" @@ -2306,6 +2343,214 @@ resolved "https://registry.yarnpkg.com/@oslojs/encoding/-/encoding-1.1.0.tgz#55f3d9a597430a01f2a5ef63c6b42f769f9ce34e" integrity sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ== +"@oxc-parser/binding-android-arm-eabi@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.137.0.tgz#441c14eb3ead3ffc6eec93d897fdb3f1a1f1d29a" + integrity sha512-KDs+0VPdEmasOkpuJHW9V5WCF+cvYdMQv2Jd+aJXt+cxIx12NToRQRbXaRwUEDsZw+/jMk81Ve8ZFbjUkJTOwA== + +"@oxc-parser/binding-android-arm64@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.137.0.tgz#bb83d21d3586dc44d760367a46103a32d9d23026" + integrity sha512-WhALNzfy3x/RfC6bsqX+csavuUY0yHHE7XfgPE5M542uhoBZUUoGTPG+nkMbGoG4+gcfss5s7urMyn5QBHu0sw== + +"@oxc-parser/binding-darwin-arm64@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.137.0.tgz#b2970f16473641b37bae0929bfb268b5b4442fb2" + integrity sha512-bFPr5hgmNMOMoyPTGtdsK4Ug21RovIPojRMgDDhSp1LtCnc/DkLwGONKjgRjszg677RlGnkYSviQ8hHaUPOVYA== + +"@oxc-parser/binding-darwin-x64@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.137.0.tgz#fbf25e40f331dcbb6e5cac93fbbe53c557e61f2b" + integrity sha512-CL5dMm1asqXIDZHg14FLxj3Mc36w8PI7xCWh1uA4is6z8g2XrIILoTcQYOxDbwzuk34RDPX5IAGUxZr6LA9KAg== + +"@oxc-parser/binding-freebsd-x64@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.137.0.tgz#46a3e99c19d85a2b58cd489727992685a6a71b5d" + integrity sha512-79h8rYGnSlKPGWo7mHr2ixO6ea7aW8B0CT965SZ8SLbNnCOH5aOYBTeVXUY6eMvEaiLyWr8Skuiugr5pDYgLGw== + +"@oxc-parser/binding-linux-arm-gnueabihf@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.137.0.tgz#dbd9e3b297553b5f26162248a1431874fe044ef1" + integrity sha512-ASgmlSimhGyr0lksgVIo6hibz1obnDq4qJbiMX/AzltfgPnanRrzG1Q+23g8ljOHOjv6dsznkUuCYL3gg0sY1Q== + +"@oxc-parser/binding-linux-arm-musleabihf@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.137.0.tgz#c4023131e94f08f65a7ad3a08c41aea21c0c7e8b" + integrity sha512-AU2J9aa22Sx32wRGnDjybOU9TQXXQUud5sdUi+ZB0XxwM8aToWLweV+yA0wlQm0yIUVqljquqoHCYEq9II8gJQ== + +"@oxc-parser/binding-linux-arm64-gnu@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.137.0.tgz#5f30967006be1e1e554effc33c205822d974b2b7" + integrity sha512-GdEtiG89yMr7XkUGxifgodXEEm2f+xW2f9CpDjlgAnBOwhTmrpQMvhOGobLVKUyzf/qHBXW16smk5zbF3nZU6w== + +"@oxc-parser/binding-linux-arm64-musl@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.137.0.tgz#2e652f77fca49126a24dfc4aecec3fb470d37f7e" + integrity sha512-EGJ+Bs8iXx8KBH8DQ5BLoEm5lnHaYjlh4/8j8vFhrr/6z4tqONy5BZDzLpKmmNWlN6Hlc5r8YOuBVHqZ9vRFEQ== + +"@oxc-parser/binding-linux-ppc64-gnu@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.137.0.tgz#52794f00bbb18e365f16f394fe5496aa46c0f890" + integrity sha512-vzFUQENy/fnbSe5DZWovq6tIBc1uhuMztanSW6rz1e9WdQE4gHwYuD7ZII6JnrJifd1R3RSoqiZbgRFlVL2tYQ== + +"@oxc-parser/binding-linux-riscv64-gnu@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.137.0.tgz#ff434ce4bcc30a01d2d81bb5491dedcecf4dfd21" + integrity sha512-SfVI14HBQs9gtLcUD5hTt5hsNbdrqSUNg9S8muN+LhVQ5nf1WwH3hAoK6B9NKgdYgWAQSXFXGiiBedQ4r/BKuw== + +"@oxc-parser/binding-linux-riscv64-musl@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.137.0.tgz#2d9d4de64ec60a7590fc40c12cd363111b1f0c1e" + integrity sha512-e7Ppy4FCIFNQxT/ikSeIWFoQ0l+N9vgtRBtLcyZXeolTzApyVoPqEXsYPrcdM/9i0Bwk8knvYd37vaEMxHyi6g== + +"@oxc-parser/binding-linux-s390x-gnu@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.137.0.tgz#f5e6397bbc07f7cd97ef332ef2a0011a609d2e03" + integrity sha512-Bho5qFwdhqsIFR7gipYEUlqvi3SRrY8sugxXig380MIaakBB1PyU9+7dBiBVScfImTNWhijUxdBwqrprGdq5WA== + +"@oxc-parser/binding-linux-x64-gnu@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.137.0.tgz#058b6589186549bd999c4245cdab0e2639676cf4" + integrity sha512-36mGWtg7PyFzjJwGDkH6/F4o2nIDEoKXLPr/X/lwqklkomQwJJt1I5GJVmGhovUEmgPK5WAeAZMqlFCehwiy9Q== + +"@oxc-parser/binding-linux-x64-musl@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.137.0.tgz#6cb15cddcacfeec0adc6b3c3c9eb017e8de0257d" + integrity sha512-/Jqx6+N7A44n2BdvUr7pXhVr2vFjs6WGH3unZRczwrfiH0H1zY0QwKQMG/dtRiTlKGDKGukznPT8lx84/oEsZg== + +"@oxc-parser/binding-openharmony-arm64@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.137.0.tgz#d3911eb99259552a01d8d2c7e34caa6b1bcbad89" + integrity sha512-9Uj0qHNNl+OgT1UTGwF7ixIXU6T1u2SbMidmgPy/h1h/fl2gRS6YpAxxY1gwHofcWjoTwkoMFd8xs5Vuj6GOFA== + +"@oxc-parser/binding-wasm32-wasi@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.137.0.tgz#38dfe9c608d0ad19b01045783a2f22ecf0e7fc82" + integrity sha512-gW2vfkytNGgMVADiuzdvOfw0mWG9za20F/1fCJsif5aBMAvWJTSbpIXbIe0XkOe0VENk+PadpQ7cZgUy2sUJcA== + dependencies: + "@emnapi/core" "1.11.1" + "@emnapi/runtime" "1.11.1" + "@napi-rs/wasm-runtime" "^1.1.5" + +"@oxc-parser/binding-win32-arm64-msvc@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.137.0.tgz#dc734c98f37b133eb9aa0a2743c7e7b24e121fd2" + integrity sha512-x+pFANF0yL5uK/6T7lu6SlR5qid6sp//eZXKLq5iNsIE+EQg6EaS8/wsW7E91nXXjpnPhSoMOHXShSVhGRdn8w== + +"@oxc-parser/binding-win32-ia32-msvc@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.137.0.tgz#9148c2db7bffaca9f09b1dcb58f01d11aeb16841" + integrity sha512-sQUqym80PFi6McRsIqfJrSu2JrSClEZIXXD+/FjAFoULEKzOPsldIdFBG96xdX8aVMzCNQ9792FPx3MfkEIrFA== + +"@oxc-parser/binding-win32-x64-msvc@0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.137.0.tgz#3480900c6fca4e843017f6de991fe6af57b7358c" + integrity sha512-2AsevxlvNN4WKxpEn3RtqD5zbqMaXF+T7JXblsP4gVuY+vC9dXS4ED/PwfRCliFqoeisYS3Iro4DHzxr0TEvVA== + +"@oxc-project/types@^0.137.0": + version "0.137.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.137.0.tgz#56e77f8bb221fa05f18b1cd34d73f94f0954a773" + integrity sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA== + +"@oxc-resolver/binding-android-arm-eabi@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.21.3.tgz#f7ca42d94614eec97e20b9afaa7173efd6019ee9" + integrity sha512-eNU11A2WNizh04v3uyaJCootrHIaS0B9aHYXvAvVnPNk4xYSjMUjHnhQ6dewPN2MRYDskV85d1N0Aw0WNWhcyg== + +"@oxc-resolver/binding-android-arm64@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.21.3.tgz#f723682c59b4dfe143edcb6d364d5a03de3e949e" + integrity sha512-8Q+ZjTLvn2dIcWsrmhdrEihm7q+ag/k+mkry7Z+t0QbbHaVxXQfvH9AewyVMh/WrpEKhQ3DDgx9fYbqeCpeOEw== + +"@oxc-resolver/binding-darwin-arm64@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.21.3.tgz#e7c4f3741c87911c40c429a20a05b781369cabaa" + integrity sha512-wkh0qKZGHXVUDxFw3oA1TXnU2BDYY/r775oJflGeIr8uDPPoN2pk8gijQIzYRT6hoql/lg3+Tx/SaTn9e2/aGg== + +"@oxc-resolver/binding-darwin-x64@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.21.3.tgz#8d2345cd2d8d4dcfa50422e26f3b008dae91bfc1" + integrity sha512-HbNc23FAQYbuyDV2vBWMez4u4mrsm5RAkniGZAWqr6lYZ3N4beeqIb776jzwRl8qL2zRhHVXpUj97X0QgogVzg== + +"@oxc-resolver/binding-freebsd-x64@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.21.3.tgz#b7554c3ab7903a95aad610ba5d163996f4b71095" + integrity sha512-K6xNsTUPEUdfrn0+kbMq5nOUB5w1C5pavPQngt4TM2FpN91lP0PBe2srSpamb4d69O7h86oAi/qWX/kZNRSjkw== + +"@oxc-resolver/binding-linux-arm-gnueabihf@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.21.3.tgz#2a717d6f79bdd75a5ccdc875bcd0a9fee585f1c3" + integrity sha512-VcFmOpcpWX1zoEy8M58tR2M9YxM+Z9RuQhqAx5q0CTmrruaP7Gveejg75hzd/5sg5nk9G3aLALEa3hE2FsmmTQ== + +"@oxc-resolver/binding-linux-arm-musleabihf@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.21.3.tgz#2cfd5234de2913c2805e42b5fae5aa9354d99ba9" + integrity sha512-quVoxFLBy43hWaQbbDtQNRwAX5vX76mv7n64icAtQcJ3eNgVeblqmkupF/hAneNthdqSlnd1sTjb3aQSaDPaCQ== + +"@oxc-resolver/binding-linux-arm64-gnu@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.21.3.tgz#32172fbd1b66d7dd6dca05fcd85cee7b0e32060a" + integrity sha512-X0AqNZgcD07Q4V3RDK18/vYOj/HQT/FnmEFGYS2jTWqY7JO13ryE3TEs3eAIgUJhBnNkpEaiXqz3VK8M7qQhWQ== + +"@oxc-resolver/binding-linux-arm64-musl@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.21.3.tgz#ac31e4894cbb0c00bda5be1e526641073923bfdc" + integrity sha512-YkaQnaKYdbuaXvRt5Qd0GpbihzVnyfR6z1SpYfIUC6RTu4NF7lDKPjVkYb+jRI2gedVO2rVpN35Y6akG6ud4Lw== + +"@oxc-resolver/binding-linux-ppc64-gnu@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.21.3.tgz#a8ae7ecc1125918124d18749efd71a4e04e0a856" + integrity sha512-gB9HwhrPiFqUzDeEq+y/CgAijz1YdI6BnXz5GaH2Pa9cWdutchlkGFAiAuGb/PjVQpiK6NFKzFuztxrweoit7A== + +"@oxc-resolver/binding-linux-riscv64-gnu@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.21.3.tgz#d24ced9b321f660f1a859f9912deab3f87fd3115" + integrity sha512-zjDWBlYk8QGv0H8dsPUWqkfjYIIjG2TvspGkzXL0eImbgxtZorA/klKeHyolevoT3Kvbi+1iMr9Lhrh7jf54Og== + +"@oxc-resolver/binding-linux-riscv64-musl@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.21.3.tgz#b20cd6b6d4c61ea627189bc939ac5f469a5a6c89" + integrity sha512-4UfsQvacV388y1zpXL7C1x1FNYaV52JtuNRiuzrfQA2z1z6ElVrsidkGsrvQ5EgeSq1Pj7kaKqrgGkvFuxJ/tw== + +"@oxc-resolver/binding-linux-s390x-gnu@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.21.3.tgz#d3f4aec82b4cba187e50e211c60f956bc6116f7f" + integrity sha512-b5uH+HKH0MP5mNBYaK75SKsJbw52URqrx2LavYdq6wb0l3ExAG5niYRP9DWUNHdKilpaBVM2bXk9HNWrH3ew7Q== + +"@oxc-resolver/binding-linux-x64-gnu@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.21.3.tgz#add3b76293ef1e8959e00bc6b62ada766e18485c" + integrity sha512-PjYlmilBpNRh2ntXNYAK3Am5w/nPfEpnU/96iNx7CI8EzAn12J4JRiec63wHJTH31nLoCNxBg/829pN+3CfG3Q== + +"@oxc-resolver/binding-linux-x64-musl@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.21.3.tgz#4b4c79bd2688a0f9a02c0a0b671015ff2f7c65fc" + integrity sha512-QTBAb7JuHlZ7JUEyM8UiQi2f7m/L4swBhP2TNpYIDc9Wp/wRw1G/8sl6i13aIzQAXH7LKIm294LeOHd0lQR8zA== + +"@oxc-resolver/binding-openharmony-arm64@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.21.3.tgz#3dc33a159aaef37d2d77d10df045adefab5852df" + integrity sha512-4j1DFwjwv36ec9kds0jU/ucQ5Ha4ERO/H95BxR5JFf0kqUUAJ1kwII7XhTc1vZrkdJkvLGC9Q2MbpObpum8RBg== + +"@oxc-resolver/binding-wasm32-wasi@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.21.3.tgz#6bc89be053e28d553db100b3505c6b0d2519b0ec" + integrity sha512-i8oluoel5kru/j1WNrjmQSiA3GQ7wvIYVR1IwIoZtKogAhya2iub+ZKIeSIkcJOrnzQ18Tzl/F+kL3fYOxZLvA== + dependencies: + "@emnapi/core" "1.11.0" + "@emnapi/runtime" "1.11.0" + "@napi-rs/wasm-runtime" "^1.1.5" + +"@oxc-resolver/binding-win32-arm64-msvc@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.21.3.tgz#6345ee727a599fec062c48a43b945cb7886e87ea" + integrity sha512-M/8dw8dD6aOs+NlPJax401CZB9I7Aut84isQLgALGGwke4Afvw+/7yYhZb94yXf6t2sPLhQLmSmtSV+2FhsOWg== + +"@oxc-resolver/binding-win32-x64-msvc@11.21.3": + version "11.21.3" + resolved "https://registry.yarnpkg.com/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.21.3.tgz#d0da31fce46d6b85672fa1e7515400fafce45e1a" + integrity sha512-H7BCt/VnS9hnmMp42eGhZ99izSCRvlnWwy/N71K1/J8QoExwY4262Z8QiEkMDtduRJrztayDxETTckmUuAVL9Q== + "@pagefind/darwin-arm64@1.5.2": version "1.5.2" resolved "https://registry.yarnpkg.com/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz#965152ffc22bccd8299e065f7cfbc6869a1bffe0" @@ -2889,6 +3134,13 @@ dependencies: tslib "^2.4.0" +"@tybys/wasm-util@^0.10.3": + version "0.10.3" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz#015cba9e9dd47ce14d03d2a8c5d547bfb169665d" + integrity sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg== + dependencies: + tslib "^2.4.0" + "@types/aws-lambda@^8.10.161": version "8.10.162" resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.162.tgz#589cfecdda3a996e9bdf20a73a26a0811cafb549" @@ -4689,6 +4941,13 @@ fb-watchman@^2.0.2: dependencies: bser "2.1.1" +fd-package-json@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fd-package-json/-/fd-package-json-2.0.0.tgz#03f53ce5a0af552c2f4faf703a24e526310a2411" + integrity sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ== + dependencies: + walk-up-path "^4.0.0" + fdir@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" @@ -4757,6 +5016,13 @@ foreground-child@^3.1.0: cross-spawn "^7.0.6" signal-exit "^4.0.1" +formatly@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/formatly/-/formatly-0.3.0.tgz#5bb3b4e692f5a8c74ad8fe26154dd0a74aac6819" + integrity sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w== + dependencies: + fd-package-json "^2.0.0" + fs-extra@^11.3.5: version "11.3.5" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.5.tgz#07a44eff40bea53e719909a532f91a23bf0769ff" @@ -4796,6 +5062,13 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-tsconfig@4.14.0, get-tsconfig@^4.10.1: + version "4.14.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.14.0.tgz#985d85c52a9903864280ccc2448d413fbf1efed8" + integrity sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA== + dependencies: + resolve-pkg-maps "^1.0.0" + get-tsconfig@5.0.0-beta.4: version "5.0.0-beta.4" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-5.0.0-beta.4.tgz#48e1c84919d16fd1edfebd04e8958da942945c25" @@ -4803,13 +5076,6 @@ get-tsconfig@5.0.0-beta.4: dependencies: resolve-pkg-maps "^1.0.0" -get-tsconfig@^4.10.1: - version "4.14.0" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.14.0.tgz#985d85c52a9903864280ccc2448d413fbf1efed8" - integrity sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA== - dependencies: - resolve-pkg-maps "^1.0.0" - get-uri@^6.0.1: version "6.0.5" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.5.tgz#714892aa4a871db671abc5395e5e9447bc306a16" @@ -5764,6 +6030,11 @@ jest@^30.3.0: import-local "^3.2.0" jest-cli "30.4.2" +jiti@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.7.0.tgz#974228f2f4ca2bc21885a1797b45fea68e950c64" + integrity sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -5857,6 +6128,25 @@ klona@^2.0.6: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22" integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA== +knip@6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/knip/-/knip-6.20.0.tgz#e7b1ac1accf6ef4e556e648479a76012f4ca37a1" + integrity sha512-q+HYrS7FOERk32GM7g43IdTG7TurN7+YMLZrNpCxubZPYZyQwliBgd18yH4oYQL7YgGtOxP2fCqess3K2XaK2Q== + dependencies: + fdir "^6.5.0" + formatly "^0.3.0" + get-tsconfig "4.14.0" + jiti "^2.7.0" + oxc-parser "^0.137.0" + oxc-resolver "11.21.3" + picomatch "^4.0.4" + smol-toml "^1.6.1" + strip-json-comments "5.0.3" + tinyglobby "^0.2.17" + unbash "^4.0.1" + yaml "^2.9.0" + zod "^4.1.11" + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -6811,6 +7101,59 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" +oxc-parser@^0.137.0: + version "0.137.0" + resolved "https://registry.yarnpkg.com/oxc-parser/-/oxc-parser-0.137.0.tgz#b88a1c5ae2b3d367b9d0a1c1cb42ca5c81745ec4" + integrity sha512-yFImD+WLElJpLKy8llG1qe4DCmMsL18peRp8XP1JKfig/gISbJkglnpDtX2aTmAn10kZF7164HbN2H8QPsXxGg== + dependencies: + "@oxc-project/types" "^0.137.0" + optionalDependencies: + "@oxc-parser/binding-android-arm-eabi" "0.137.0" + "@oxc-parser/binding-android-arm64" "0.137.0" + "@oxc-parser/binding-darwin-arm64" "0.137.0" + "@oxc-parser/binding-darwin-x64" "0.137.0" + "@oxc-parser/binding-freebsd-x64" "0.137.0" + "@oxc-parser/binding-linux-arm-gnueabihf" "0.137.0" + "@oxc-parser/binding-linux-arm-musleabihf" "0.137.0" + "@oxc-parser/binding-linux-arm64-gnu" "0.137.0" + "@oxc-parser/binding-linux-arm64-musl" "0.137.0" + "@oxc-parser/binding-linux-ppc64-gnu" "0.137.0" + "@oxc-parser/binding-linux-riscv64-gnu" "0.137.0" + "@oxc-parser/binding-linux-riscv64-musl" "0.137.0" + "@oxc-parser/binding-linux-s390x-gnu" "0.137.0" + "@oxc-parser/binding-linux-x64-gnu" "0.137.0" + "@oxc-parser/binding-linux-x64-musl" "0.137.0" + "@oxc-parser/binding-openharmony-arm64" "0.137.0" + "@oxc-parser/binding-wasm32-wasi" "0.137.0" + "@oxc-parser/binding-win32-arm64-msvc" "0.137.0" + "@oxc-parser/binding-win32-ia32-msvc" "0.137.0" + "@oxc-parser/binding-win32-x64-msvc" "0.137.0" + +oxc-resolver@11.21.3: + version "11.21.3" + resolved "https://registry.yarnpkg.com/oxc-resolver/-/oxc-resolver-11.21.3.tgz#0fde1bd801ce1c2c95ef010406073aa7cd0fe8cc" + integrity sha512-2Mx3fKQz7+xgrBONjsxOgCGtMHOn38/HxMzW1I5efwXB5a4lRN0Vp40gYUJFBWJslcrvwoofTrqoTnLbwTd3pA== + optionalDependencies: + "@oxc-resolver/binding-android-arm-eabi" "11.21.3" + "@oxc-resolver/binding-android-arm64" "11.21.3" + "@oxc-resolver/binding-darwin-arm64" "11.21.3" + "@oxc-resolver/binding-darwin-x64" "11.21.3" + "@oxc-resolver/binding-freebsd-x64" "11.21.3" + "@oxc-resolver/binding-linux-arm-gnueabihf" "11.21.3" + "@oxc-resolver/binding-linux-arm-musleabihf" "11.21.3" + "@oxc-resolver/binding-linux-arm64-gnu" "11.21.3" + "@oxc-resolver/binding-linux-arm64-musl" "11.21.3" + "@oxc-resolver/binding-linux-ppc64-gnu" "11.21.3" + "@oxc-resolver/binding-linux-riscv64-gnu" "11.21.3" + "@oxc-resolver/binding-linux-riscv64-musl" "11.21.3" + "@oxc-resolver/binding-linux-s390x-gnu" "11.21.3" + "@oxc-resolver/binding-linux-x64-gnu" "11.21.3" + "@oxc-resolver/binding-linux-x64-musl" "11.21.3" + "@oxc-resolver/binding-openharmony-arm64" "11.21.3" + "@oxc-resolver/binding-wasm32-wasi" "11.21.3" + "@oxc-resolver/binding-win32-arm64-msvc" "11.21.3" + "@oxc-resolver/binding-win32-x64-msvc" "11.21.3" + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -7582,7 +7925,7 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -smol-toml@^1.6.0: +smol-toml@^1.6.0, smol-toml@^1.6.1: version "1.7.0" resolved "https://registry.yarnpkg.com/smol-toml/-/smol-toml-1.7.0.tgz#ed1b259ce7e05907df1abe758971bd0a0ef2c0dd" integrity sha512-aqVvWoyO21L23mb+drl4RmMXbf6N7FdHjAhTRA9ZBL7apWBgfWC16KjrASI+1p9GAroljyMHj6fK67i0UiTNvQ== @@ -7741,6 +8084,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-json-comments@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" + integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -7836,7 +8184,7 @@ tinyexec@^1.0.4: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.2.4.tgz#ae45bb2edebda94c70f4ea897e0f1243e470db71" integrity sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg== -tinyglobby@^0.2.14, tinyglobby@^0.2.15, tinyglobby@^0.2.16: +tinyglobby@^0.2.14, tinyglobby@^0.2.15, tinyglobby@^0.2.16, tinyglobby@^0.2.17: version "0.2.17" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== @@ -7975,6 +8323,11 @@ ultrahtml@^1.6.0: resolved "https://registry.yarnpkg.com/ultrahtml/-/ultrahtml-1.6.0.tgz#0d1aad7bbfeae512438d30e799c11622127a1ac8" integrity sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw== +unbash@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/unbash/-/unbash-4.0.1.tgz#efa4876b0f95ab86931546aa1e699e7e353de7ad" + integrity sha512-1ajSo3813sDoVIHx4inJdUS4l5L2ic5cFiddemPiyjb/PZEoBAhFwHtbaEdRDFxbAKy7FCG7s5ww3/uCFawuIA== + uncrypto@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" @@ -8380,6 +8733,11 @@ vscode-uri@^3.0.2, vscode-uri@^3.0.8, vscode-uri@^3.1.0: resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== +walk-up-path@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-4.0.0.tgz#590666dcf8146e2d72318164f1f2ac6ef51d4198" + integrity sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A== + walkdir@0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39" @@ -8506,7 +8864,7 @@ yaml-language-server@~1.20.0: vscode-uri "^3.0.2" yaml "2.7.1" -yaml@1.10.3, yaml@2.7.1, yaml@^2.8.3: +yaml@1.10.3, yaml@2.7.1, yaml@^2.8.3, yaml@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.9.0.tgz#78274afd93598a1dfdd6130df6a566defcbf9aa4" integrity sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA== @@ -8554,7 +8912,7 @@ zod@^3.22.4: resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== -zod@^4.3.6: +zod@^4.1.11, zod@^4.3.6: version "4.4.3" resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.3.tgz#b680f172885d18bbebf21a834ea25e55a1bbf356" integrity sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==