diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 1b31bb8394..2d57c2807f 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -73,3 +73,18 @@ jobs: - name: Audit build and test tooling continue-on-error: true run: pnpm audit --audit-level high + + # The docs site keeps its own lockfile and is not a workspace member, so + # neither audit above can see it. Without this step a website advisory is + # invisible — which is how two of them sat open long enough to need a + # manual override. + # + # Same blocking rule as the published-dependency audit: advisory on pull + # requests, blocking on the weekly schedule and on pushes to main. Green + # here has to mean the site is clean, or the step just relocates the blind + # spot into a passing log. `!cancelled()` because the two audits above can + # fail hard, and a root advisory must not silently skip this one. + - name: Audit documentation site + if: ${{ !cancelled() }} + continue-on-error: ${{ github.event_name == 'pull_request' }} + run: pnpm audit --audit-level high --dir website diff --git a/test/commands/config-profile.test.ts b/test/commands/config-profile.test.ts index ab18e4e6b7..bb130a8f64 100644 --- a/test/commands/config-profile.test.ts +++ b/test/commands/config-profile.test.ts @@ -126,8 +126,7 @@ describe('config profile interactive flow', () => { beforeEach(() => { vi.resetModules(); - tempDir = path.join(os.tmpdir(), `openspec-config-profile-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-config-profile-test-')); originalEnv = { ...process.env }; originalCwd = process.cwd(); diff --git a/test/commands/config.test.ts b/test/commands/config.test.ts index 1e4f7e73d0..1a6c8d8cea 100644 --- a/test/commands/config.test.ts +++ b/test/commands/config.test.ts @@ -20,8 +20,7 @@ describe('config command integration', () => { beforeEach(() => { // Create unique temp directory for each test - tempDir = path.join(os.tmpdir(), `openspec-config-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-config-test-')); // Save original env and set XDG_CONFIG_HOME originalEnv = { ...process.env }; @@ -245,8 +244,7 @@ describe('config profile command', () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(() => { - tempDir = path.join(os.tmpdir(), `openspec-profile-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-profile-test-')); originalEnv = { ...process.env }; process.env.XDG_CONFIG_HOME = tempDir; }); diff --git a/test/commands/schema.test.ts b/test/commands/schema.test.ts index c614038aa1..9722b8150b 100644 --- a/test/commands/schema.test.ts +++ b/test/commands/schema.test.ts @@ -12,11 +12,7 @@ describe('schema command', () => { beforeEach(() => { // Create unique temp directory for each test - tempDir = path.join( - os.tmpdir(), - `openspec-schema-test-${Date.now()}-${Math.random().toString(36).slice(2)}` - ); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-schema-test-')); // Create openspec directory structure fs.mkdirSync(path.join(tempDir, 'openspec', 'schemas'), { recursive: true }); diff --git a/test/core/artifact-graph/outputs.test.ts b/test/core/artifact-graph/outputs.test.ts index 988200e2c1..64c3267190 100644 --- a/test/core/artifact-graph/outputs.test.ts +++ b/test/core/artifact-graph/outputs.test.ts @@ -11,8 +11,7 @@ describe('artifact-graph/outputs', () => { const canonical = (targetPath: string): string => FileSystemUtils.canonicalizeExistingPath(targetPath); beforeEach(() => { - tempDir = path.join(os.tmpdir(), `openspec-outputs-test-${Date.now()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-outputs-test-')); }); afterEach(() => { diff --git a/test/core/artifact-graph/resolver.test.ts b/test/core/artifact-graph/resolver.test.ts index 3436151933..b37c745eb9 100644 --- a/test/core/artifact-graph/resolver.test.ts +++ b/test/core/artifact-graph/resolver.test.ts @@ -19,8 +19,7 @@ describe('artifact-graph/resolver', () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(() => { - tempDir = path.join(os.tmpdir(), `openspec-resolver-test-${Date.now()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-resolver-test-')); originalEnv = { ...process.env }; }); diff --git a/test/core/artifact-graph/state.test.ts b/test/core/artifact-graph/state.test.ts index 758a7675b8..13eddd348c 100644 --- a/test/core/artifact-graph/state.test.ts +++ b/test/core/artifact-graph/state.test.ts @@ -16,8 +16,7 @@ describe('artifact-graph/state', () => { }); beforeEach(() => { - tempDir = path.join(os.tmpdir(), `openspec-state-test-${Date.now()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-state-test-')); }); afterEach(() => { diff --git a/test/core/available-tools.test.ts b/test/core/available-tools.test.ts index 2556d29a35..ef13effe30 100644 --- a/test/core/available-tools.test.ts +++ b/test/core/available-tools.test.ts @@ -2,15 +2,13 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { getAvailableTools } from '../../src/core/available-tools.js'; describe('available-tools', () => { let testDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); }); afterEach(async () => { diff --git a/test/core/commands/change-command.list.test.ts b/test/core/commands/change-command.list.test.ts index 6bf24420e1..9ec1df5a1d 100644 --- a/test/core/commands/change-command.list.test.ts +++ b/test/core/commands/change-command.list.test.ts @@ -12,7 +12,7 @@ describe('ChangeCommand.list', () => { beforeAll(async () => { cmd = new ChangeCommand(); originalCwd = process.cwd(); - tempRoot = path.join(os.tmpdir(), `openspec-change-command-list-${Date.now()}`); + tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-change-command-list-')); const changeDir = path.join(tempRoot, 'openspec', 'changes', 'demo'); await fs.mkdir(changeDir, { recursive: true }); const proposal = `# Change: Demo\n\n## Why\nTest list.\n\n## What Changes\n- **auth:** Add requirement`; diff --git a/test/core/commands/change-command.show-validate.test.ts b/test/core/commands/change-command.show-validate.test.ts index fcaa00ad53..5442a52cbf 100644 --- a/test/core/commands/change-command.show-validate.test.ts +++ b/test/core/commands/change-command.show-validate.test.ts @@ -13,7 +13,7 @@ describe('ChangeCommand.show/validate', () => { beforeAll(async () => { cmd = new ChangeCommand(); originalCwd = process.cwd(); - tempRoot = path.join(os.tmpdir(), `openspec-change-command-${Date.now()}`); + tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-change-command-')); const changesDir = path.join(tempRoot, 'openspec', 'changes', 'sample-change'); await fs.mkdir(changesDir, { recursive: true }); const proposal = `# Change: Sample Change\n\n## Why\nConsistency in tests.\n\n## What Changes\n- **auth:** Add requirement`; diff --git a/test/core/completions/completion-provider.test.ts b/test/core/completions/completion-provider.test.ts index 2af6dc2437..8f14798675 100644 --- a/test/core/completions/completion-provider.test.ts +++ b/test/core/completions/completion-provider.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { CompletionProvider } from '../../../src/core/completions/completion-provider.js'; describe('CompletionProvider', () => { @@ -10,8 +9,7 @@ describe('CompletionProvider', () => { let provider: CompletionProvider; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); provider = new CompletionProvider(2000, testDir); }); diff --git a/test/core/completions/installers/bash-installer.test.ts b/test/core/completions/installers/bash-installer.test.ts index e289d90e38..a251031ee3 100644 --- a/test/core/completions/installers/bash-installer.test.ts +++ b/test/core/completions/installers/bash-installer.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { BashInstaller } from '../../../../src/core/completions/installers/bash-installer.js'; describe('BashInstaller', () => { @@ -11,8 +10,7 @@ describe('BashInstaller', () => { beforeEach(async () => { // Create a temporary home directory for testing - testHomeDir = path.join(os.tmpdir(), `openspec-bash-test-${randomUUID()}`); - await fs.mkdir(testHomeDir, { recursive: true }); + testHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-bash-test-')); installer = new BashInstaller(testHomeDir); }); @@ -208,8 +206,7 @@ describe('BashInstaller', () => { it('should handle paths with spaces in .bashrc config', async () => { // Create a test home directory with spaces - const testHomeDirWithSpaces = path.join(os.tmpdir(), `openspec bash test ${randomUUID()}`); - await fs.mkdir(testHomeDirWithSpaces, { recursive: true }); + const testHomeDirWithSpaces = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec bash test ')); const installerWithSpaces = new BashInstaller(testHomeDirWithSpaces); try { diff --git a/test/core/completions/installers/fish-installer.test.ts b/test/core/completions/installers/fish-installer.test.ts index d8eb3021e1..35a69b359c 100644 --- a/test/core/completions/installers/fish-installer.test.ts +++ b/test/core/completions/installers/fish-installer.test.ts @@ -3,15 +3,13 @@ import { FishInstaller } from '../../../../src/core/completions/installers/fish- import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; describe('FishInstaller', () => { let testHomeDir: string; let installer: FishInstaller; beforeEach(async () => { - testHomeDir = path.join(os.tmpdir(), `openspec-fish-test-${randomUUID()}`); - await fs.mkdir(testHomeDir, { recursive: true }); + testHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-fish-test-')); installer = new FishInstaller(testHomeDir); }); @@ -179,8 +177,7 @@ complete -c openspec -a 'validate' -d 'Validate specs' }); it('should handle installation with paths containing spaces', async () => { - const spacedHomeDir = path.join(os.tmpdir(), `openspec fish test ${randomUUID()}`); - await fs.mkdir(spacedHomeDir, { recursive: true }); + const spacedHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec fish test ')); const spacedInstaller = new FishInstaller(spacedHomeDir); const result = await spacedInstaller.install(mockCompletionScript); diff --git a/test/core/completions/installers/powershell-installer.test.ts b/test/core/completions/installers/powershell-installer.test.ts index b9e5c7e2f1..a1e90b2cc2 100644 --- a/test/core/completions/installers/powershell-installer.test.ts +++ b/test/core/completions/installers/powershell-installer.test.ts @@ -3,7 +3,6 @@ import { PowerShellInstaller } from '../../../../src/core/completions/installers import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; describe('PowerShellInstaller', () => { let testHomeDir: string; @@ -20,8 +19,7 @@ describe('PowerShellInstaller', () => { }; beforeEach(async () => { - testHomeDir = path.join(os.tmpdir(), `openspec-powershell-test-${randomUUID()}`); - await fs.mkdir(testHomeDir, { recursive: true }); + testHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-powershell-test-')); installer = new PowerShellInstaller(testHomeDir); originalPlatform = process.platform; originalEnv = { ...process.env }; @@ -519,8 +517,7 @@ Register-ArgumentCompleter -CommandName openspec -ScriptBlock $openspecCompleter }); it('should handle installation with paths containing spaces', async () => { - const spacedHomeDir = path.join(os.tmpdir(), `openspec powershell test ${randomUUID()}`); - await fs.mkdir(spacedHomeDir, { recursive: true }); + const spacedHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec powershell test ')); const spacedInstaller = new PowerShellInstaller(spacedHomeDir); const result = await spacedInstaller.install(mockCompletionScript); diff --git a/test/core/completions/installers/zsh-installer.test.ts b/test/core/completions/installers/zsh-installer.test.ts index ff84de4a3f..91100d03e2 100644 --- a/test/core/completions/installers/zsh-installer.test.ts +++ b/test/core/completions/installers/zsh-installer.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { ZshInstaller } from '../../../../src/core/completions/installers/zsh-installer.js'; describe('ZshInstaller', () => { @@ -17,8 +16,7 @@ describe('ZshInstaller', () => { delete process.env.ZSH; // Create a temporary home directory for testing - testHomeDir = path.join(os.tmpdir(), `openspec-zsh-test-${randomUUID()}`); - await fs.mkdir(testHomeDir, { recursive: true }); + testHomeDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-zsh-test-')); installer = new ZshInstaller(testHomeDir); }); @@ -271,8 +269,7 @@ describe('ZshInstaller', () => { it('should handle paths with spaces in .zshrc config', async () => { // Create a test home directory with spaces - const testHomeDirWithSpaces = path.join(os.tmpdir(), `openspec zsh test ${randomUUID()}`); - await fs.mkdir(testHomeDirWithSpaces, { recursive: true }); + const testHomeDirWithSpaces = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec zsh test ')); const installerWithSpaces = new ZshInstaller(testHomeDirWithSpaces); try { diff --git a/test/core/global-config.test.ts b/test/core/global-config.test.ts index 03310060ef..978b6c5b86 100644 --- a/test/core/global-config.test.ts +++ b/test/core/global-config.test.ts @@ -21,8 +21,7 @@ describe('global-config', () => { beforeEach(() => { // Create temp directory for tests - tempDir = path.join(os.tmpdir(), `openspec-global-config-test-${Date.now()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-global-config-test-')); // Save original env originalEnv = { ...process.env }; diff --git a/test/core/init.test.ts b/test/core/init.test.ts index 839c4a28d5..492a23c6a4 100644 --- a/test/core/init.test.ts +++ b/test/core/init.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { promises as fs } from 'fs'; -import { randomUUID } from 'crypto'; import path from 'path'; import os from 'os'; import { InitCommand } from '../../src/core/init.js'; @@ -30,12 +29,10 @@ describe('InitCommand', () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-init-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-init-test-')); originalEnv = { ...process.env }; // Use a temp dir for global config to avoid reading real config - configTempDir = path.join(os.tmpdir(), `openspec-config-init-${randomUUID()}`); - await fs.mkdir(configTempDir, { recursive: true }); + configTempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-config-init-')); process.env.XDG_CONFIG_HOME = configTempDir; process.env.CODEX_HOME = path.join(testDir, 'codex-home'); @@ -646,12 +643,10 @@ describe('InitCommand - profile and detection features', () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-init-profile-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-init-profile-test-')); originalEnv = { ...process.env }; // Use a temp dir for global config to avoid polluting real config - configTempDir = path.join(os.tmpdir(), `openspec-config-test-${randomUUID()}`); - await fs.mkdir(configTempDir, { recursive: true }); + configTempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-config-test-')); process.env.XDG_CONFIG_HOME = configTempDir; process.env.CODEX_HOME = path.join(testDir, 'codex-home'); vi.spyOn(console, 'log').mockImplementation(() => {}); diff --git a/test/core/legacy-cleanup.test.ts b/test/core/legacy-cleanup.test.ts index c048edf91c..48dc941a2a 100644 --- a/test/core/legacy-cleanup.test.ts +++ b/test/core/legacy-cleanup.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { detectLegacyArtifacts, detectLegacyConfigFiles, @@ -32,8 +31,7 @@ describe('legacy-cleanup', () => { beforeEach(async () => { originalEnv = { ...process.env }; - testDir = path.join(os.tmpdir(), `openspec-legacy-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-legacy-test-')); process.env.CODEX_HOME = path.join(testDir, 'codex-home'); // Create openspec directory structure await fs.mkdir(path.join(testDir, 'openspec'), { recursive: true }); diff --git a/test/core/list.test.ts b/test/core/list.test.ts index 096e46a1d8..9e4a08c136 100644 --- a/test/core/list.test.ts +++ b/test/core/list.test.ts @@ -11,8 +11,7 @@ describe('ListCommand', () => { beforeEach(async () => { // Create temp directory - tempDir = path.join(os.tmpdir(), `openspec-list-test-${Date.now()}`); - await fs.mkdir(tempDir, { recursive: true }); + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-list-test-')); // Mock console.log to capture output originalLog = console.log; diff --git a/test/core/migration.test.ts b/test/core/migration.test.ts index e1b6f4f7cb..b819400826 100644 --- a/test/core/migration.test.ts +++ b/test/core/migration.test.ts @@ -1,7 +1,6 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import fs from 'node:fs'; import { promises as fsp } from 'node:fs'; import { AI_TOOLS, type AIToolOption } from '../../src/core/config.js'; @@ -65,10 +64,8 @@ describe('migration', () => { let originalEnv: NodeJS.ProcessEnv; beforeEach(async () => { - projectDir = path.join(os.tmpdir(), `openspec-migration-project-${randomUUID()}`); - configHome = path.join(os.tmpdir(), `openspec-migration-config-${randomUUID()}`); - await fsp.mkdir(projectDir, { recursive: true }); - await fsp.mkdir(configHome, { recursive: true }); + projectDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'openspec-migration-project-')); + configHome = await fsp.mkdtemp(path.join(os.tmpdir(), 'openspec-migration-config-')); originalEnv = { ...process.env }; process.env.XDG_CONFIG_HOME = configHome; }); diff --git a/test/core/profile-sync-drift.test.ts b/test/core/profile-sync-drift.test.ts index 116a6e5706..39f41ca99b 100644 --- a/test/core/profile-sync-drift.test.ts +++ b/test/core/profile-sync-drift.test.ts @@ -41,7 +41,7 @@ describe('profile sync drift detection', () => { let tempDir: string; beforeEach(() => { - tempDir = path.join(os.tmpdir(), `openspec-profile-sync-drift-test-${Date.now()}-${Math.random().toString(36).slice(2)}`); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-profile-sync-drift-test-')); fs.mkdirSync(path.join(tempDir, 'openspec'), { recursive: true }); }); diff --git a/test/core/shared/tool-detection.test.ts b/test/core/shared/tool-detection.test.ts index c4ef3bbb6c..73f19bd1c8 100644 --- a/test/core/shared/tool-detection.test.ts +++ b/test/core/shared/tool-detection.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { SKILL_NAMES, getToolsWithSkillsDir, @@ -18,8 +17,7 @@ describe('tool-detection', () => { let testDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); }); afterEach(async () => { diff --git a/test/core/update.test.ts b/test/core/update.test.ts index c58065fea9..8c801b767b 100644 --- a/test/core/update.test.ts +++ b/test/core/update.test.ts @@ -7,7 +7,6 @@ import type { GlobalConfig } from '../../src/core/global-config.js'; import path from 'path'; import fs from 'fs/promises'; import os from 'os'; -import { randomUUID } from 'crypto'; // Shared mutable mock config state const mockState = { @@ -46,8 +45,7 @@ describe('UpdateCommand', () => { beforeEach(async () => { originalEnv = { ...process.env }; // Create a temporary test directory - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); process.env.CODEX_HOME = path.join(testDir, 'codex-home'); // Create openspec directory diff --git a/test/core/view.test.ts b/test/core/view.test.ts index 653bb8624e..896f88ed6d 100644 --- a/test/core/view.test.ts +++ b/test/core/view.test.ts @@ -12,8 +12,7 @@ describe('ViewCommand', () => { let logOutput: string[] = []; beforeEach(async () => { - tempDir = path.join(os.tmpdir(), `openspec-view-test-${Date.now()}`); - await fs.mkdir(tempDir, { recursive: true }); + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-view-test-')); originalLog = console.log; console.log = (...args: any[]) => { diff --git a/test/telemetry/config.test.ts b/test/telemetry/config.test.ts index ef5726621e..d22d138d40 100644 --- a/test/telemetry/config.test.ts +++ b/test/telemetry/config.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import * as fs from 'node:fs'; import * as path from 'node:path'; import * as os from 'node:os'; -import { randomUUID } from 'node:crypto'; import { getConfigPath, @@ -35,8 +34,7 @@ describe('telemetry/config', () => { beforeEach(() => { // Create temp directory for tests - tempDir = path.join(os.tmpdir(), `openspec-telemetry-test-${randomUUID()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-telemetry-test-')); // Mock HOME/USERPROFILE to point to temp dir // On POSIX, os.homedir() uses HOME; on Windows it uses USERPROFILE diff --git a/test/telemetry/index.test.ts b/test/telemetry/index.test.ts index 73b050a286..e4c6da6c21 100644 --- a/test/telemetry/index.test.ts +++ b/test/telemetry/index.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import * as fs from 'node:fs'; import * as path from 'node:path'; import * as os from 'node:os'; -import { randomUUID } from 'node:crypto'; // Mock posthog-node before importing the module vi.mock('posthog-node', () => { @@ -26,8 +25,7 @@ describe('telemetry/index', () => { beforeEach(() => { // Create unique temp directory for each test using UUID - tempDir = path.join(os.tmpdir(), `openspec-telemetry-test-${randomUUID()}`); - fs.mkdirSync(tempDir, { recursive: true }); + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openspec-telemetry-test-')); // Save original env originalEnv = { ...process.env }; diff --git a/test/utils/change-metadata.test.ts b/test/utils/change-metadata.test.ts index 6d920465ee..0082d03d73 100644 --- a/test/utils/change-metadata.test.ts +++ b/test/utils/change-metadata.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { writeChangeMetadata, readChangeMetadata, @@ -141,7 +140,7 @@ describe('writeChangeMetadata', () => { let changeDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); changeDir = path.join(testDir, 'openspec', 'changes', 'test-change'); await fs.mkdir(changeDir, { recursive: true }); }); @@ -178,7 +177,7 @@ describe('readChangeMetadata', () => { let changeDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); changeDir = path.join(testDir, 'openspec', 'changes', 'test-change'); await fs.mkdir(changeDir, { recursive: true }); }); @@ -255,7 +254,7 @@ describe('resolveSchemaForChange', () => { let changeDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); changeDir = path.join(testDir, 'openspec', 'changes', 'test-change'); await fs.mkdir(changeDir, { recursive: true }); }); diff --git a/test/utils/change-utils.test.ts b/test/utils/change-utils.test.ts index 587a7b75f6..f76a800e7a 100644 --- a/test/utils/change-utils.test.ts +++ b/test/utils/change-utils.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { validateChangeName, createChange } from '../../src/utils/change-utils.js'; describe('validateChangeName', () => { @@ -113,8 +112,7 @@ describe('createChange', () => { const originalTimeZone = process.env.TZ; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); }); afterEach(async () => { diff --git a/test/utils/file-system.test.ts b/test/utils/file-system.test.ts index 5cc670e90b..509030f6aa 100644 --- a/test/utils/file-system.test.ts +++ b/test/utils/file-system.test.ts @@ -3,15 +3,13 @@ import * as nodeFs from 'fs'; import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; -import { randomUUID } from 'crypto'; import { FileSystemUtils } from '../../src/utils/file-system.js'; describe('FileSystemUtils', () => { let testDir: string; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-test-${randomUUID()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-test-')); }); afterEach(async () => { diff --git a/test/utils/marker-updates.test.ts b/test/utils/marker-updates.test.ts index da9a06b6e9..75476aef96 100644 --- a/test/utils/marker-updates.test.ts +++ b/test/utils/marker-updates.test.ts @@ -10,8 +10,7 @@ describe('FileSystemUtils.updateFileWithMarkers', () => { const END_MARKER = ''; beforeEach(async () => { - testDir = path.join(os.tmpdir(), `openspec-marker-test-${Date.now()}`); - await fs.mkdir(testDir, { recursive: true }); + testDir = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-marker-test-')); }); afterEach(async () => { diff --git a/test/utils/task-progress.test.ts b/test/utils/task-progress.test.ts index 33f89794a9..7f714b546b 100644 --- a/test/utils/task-progress.test.ts +++ b/test/utils/task-progress.test.ts @@ -36,7 +36,7 @@ describe('getTaskProgressForChange (#1202 tracked-tasks resolution)', () => { ].join('\n'); beforeEach(async () => { - projectRoot = path.join(os.tmpdir(), `openspec-taskprogress-${Date.now()}-${Math.round(performance.now())}`); + projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'openspec-taskprogress-')); changesDir = path.join(projectRoot, 'openspec', 'changes'); await fs.mkdir(changesDir, { recursive: true }); }); diff --git a/website/package.json b/website/package.json index e9ee6c89d0..eaf7f1159d 100644 --- a/website/package.json +++ b/website/package.json @@ -31,5 +31,11 @@ "serve": "^14.2.6", "tailwindcss": "^4.3.1", "typescript": "^6.0.3" + }, + "pnpm": { + "overrides": { + "postcss": "^8.5.22", + "sharp": "^0.35.3" + } } } diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index eda1bb3bda..97fcd609eb 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -4,6 +4,10 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + postcss: ^8.5.22 + sharp: ^0.35.3 + importers: .: @@ -13,19 +17,19 @@ importers: version: 3.1.18 fumadocs-core: specifier: ^16.10.7 - version: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) + version: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) fumadocs-mdx: specifier: ^15.0.13 - version: 15.2.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) + version: 15.2.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8) fumadocs-ui: specifier: ^16.10.7 - version: 16.11.5(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) + version: 16.11.5(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3) lucide-react: specifier: ^1.22.0 version: 1.25.0(react@19.2.8) next: specifier: 16.2.11 - version: 16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + version: 16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: specifier: ^19.2.7 version: 19.2.8 @@ -52,7 +56,7 @@ importers: specifier: ^19.2.3 version: 19.2.3(@types/react@19.2.17) postcss: - specifier: ^8.5.15 + specifier: ^8.5.22 version: 8.5.22 serve: specifier: ^14.2.6 @@ -266,136 +270,145 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} cpu: [riscv64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -1949,10 +1962,6 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.22: resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==} engines: {node: ^10 || ^12 || >=14} @@ -2091,9 +2100,14 @@ packages: engines: {node: '>= 14'} hasBin: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2418,98 +2432,108 @@ snapshots: '@img/colour@1.1.0': optional: true - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.2 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.2': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.2': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.2': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.2': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.2': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.2': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.2 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.2 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.2 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.2 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.2 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.2 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.3': dependencies: '@emnapi/runtime': 1.11.2 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-win32-arm64@0.35.3': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.3': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.3': optional: true '@jridgewell/gen-mapping@0.3.13': @@ -3434,7 +3458,7 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3): + fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3): dependencies: '@orama/orama': 3.1.18 estree-util-value-to-estree: 3.5.0 @@ -3460,21 +3484,21 @@ snapshots: '@types/mdast': 4.0.4 '@types/react': 19.2.17 lucide-react: 1.25.0(react@19.2.8) - next: 16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 react-dom: 19.2.8(react@19.2.8) zod: 4.4.3 transitivePeerDependencies: - supports-color - fumadocs-mdx@15.2.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): + fumadocs-mdx@15.2.0(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react@19.2.8): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.28.1 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) + fumadocs-core: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) github-slugger: 2.0.0 magic-string: 0.30.21 mdast-util-mdx: 3.0.0 @@ -3493,12 +3517,12 @@ snapshots: '@types/mdast': 4.0.4 '@types/mdx': 2.0.14 '@types/react': 19.2.17 - next: 16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) react: 19.2.8 transitivePeerDependencies: - supports-color - fumadocs-ui@16.11.5(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3): + fumadocs-ui@16.11.5(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(tailwindcss@4.3.3): dependencies: '@fuma-translate/react': 1.0.2(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@fumadocs/tailwind': 0.1.1(tailwindcss@4.3.3) @@ -3514,7 +3538,7 @@ snapshots: '@radix-ui/react-tabs': 1.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) class-variance-authority: 0.7.1 cnfast: 0.0.8 - fumadocs-core: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) + fumadocs-core: 16.11.5(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.5)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.25.0(react@19.2.8))(next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.4.3) lucide-react: 1.25.0(react@19.2.8) motion: 12.42.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) next-themes: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -3528,7 +3552,7 @@ snapshots: optionalDependencies: '@types/mdx': 2.0.14 '@types/react': 19.2.17 - next: 16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + next: 16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) transitivePeerDependencies: - '@emotion/is-prop-valid' - '@types/react-dom' @@ -4226,13 +4250,13 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - next@16.2.11(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + next@16.2.11(@types/node@26.1.1)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: '@next/env': 16.2.11 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.11.1 caniuse-lite: 1.0.30001806 - postcss: 8.4.31 + postcss: 8.5.22 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) styled-jsx: 5.1.6(react@19.2.8) @@ -4245,9 +4269,10 @@ snapshots: '@next/swc-linux-x64-musl': 16.2.11 '@next/swc-win32-arm64-msvc': 16.2.11 '@next/swc-win32-x64-msvc': 16.2.11 - sharp: 0.34.5 + sharp: 0.35.3(@types/node@26.1.1) transitivePeerDependencies: - '@babel/core' + - '@types/node' - babel-plugin-macros npm-run-path@4.0.1: @@ -4292,12 +4317,6 @@ snapshots: picomatch@4.0.5: {} - postcss@8.4.31: - dependencies: - nanoid: 3.3.16 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.22: dependencies: nanoid: 3.3.16 @@ -4502,36 +4521,38 @@ snapshots: transitivePeerDependencies: - supports-color - sharp@0.34.5: + sharp@0.35.3(@types/node@26.1.1): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 26.1.1 optional: true shebang-command@2.0.0: