diff --git a/packages/tgpu/.gitignore b/packages/tgpu/.gitignore new file mode 100644 index 0000000000..960dd8addf --- /dev/null +++ b/packages/tgpu/.gitignore @@ -0,0 +1 @@ +.test diff --git a/packages/tgpu/README.md b/packages/tgpu/README.md new file mode 100644 index 0000000000..710cc02c54 --- /dev/null +++ b/packages/tgpu/README.md @@ -0,0 +1,19 @@ +# tgpu +Enhance your project with TypeGPU. + +## Usage +Run inside the root of an existing Vite or React Native project: + +```sh +pnpm dlx tgpu@latest +# or +npx tgpu@latest +# or +yarn dlx tgpu@latest +# or +bunx tgpu@latest +``` + +> [!CAUTION] +> **Back up your project before running this tool.** Even though every modification is gated behind an explicit "yes/no" prompt, the changes the script makes are not reversible by it. +--- diff --git a/packages/tgpu/package.json b/packages/tgpu/package.json new file mode 100644 index 0000000000..48d2a1caa3 --- /dev/null +++ b/packages/tgpu/package.json @@ -0,0 +1,45 @@ +{ + "name": "tgpu", + "version": "0.0.1", + "description": "Add TypeGPU to your project", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/software-mansion/TypeGPU.git#main", + "directory": "packages/tgpu" + }, + "bin": { + "tgpu": "./dist/index.js" + }, + "files": [ + "dist" + ], + "type": "module", + "scripts": { + "dev": "tsdown && node ./dist/index.js", + "build": "tsdown", + "test:types": "pnpm tsc --p ./tsconfig.json --noEmit", + "prepublishOnly": "pnpm run build", + "test:vite-project": "tsdown && cd .test/vite && node ../../dist/index.js" + }, + "dependencies": { + "@antfu/ni": "^25.0.0", + "@clack/prompts": "^0.9.1", + "comment-json": "^5.0.0", + "cross-spawn": "^7.0.6", + "magicast": "^0.5.2", + "mri": "^1.2.0", + "package-manager-detector": "^1.3.0" + }, + "devDependencies": { + "@types/cross-spawn": "^6.0.6", + "@types/node": "catalog:types", + "arktype": "catalog:", + "tsdown": "catalog:build", + "typescript": "catalog:types" + }, + "engines": { + "node": ">=24.0.0" + }, + "packageManager": "pnpm@10.15.1" +} diff --git a/packages/tgpu/src/index.ts b/packages/tgpu/src/index.ts new file mode 100644 index 0000000000..6764e8543f --- /dev/null +++ b/packages/tgpu/src/index.ts @@ -0,0 +1,85 @@ +#!/usr/bin/env node + +import fs from 'node:fs'; +import path from 'node:path'; +import mri from 'mri'; +import * as p from '@clack/prompts'; +import { detect, type Agent } from 'package-manager-detector'; +import { type } from 'arktype'; + +import { PackageJsonSchema, type PackageJson } from './utils/types.ts'; +import { pmInstall } from './utils/pm.ts'; + +import { cancelExit, failAndExit } from './utils/prompts.ts'; +import { ensureWebgpuTypes } from './steps/webgpu-types.ts'; +import { ensureTypegpu } from './steps/typegpu.ts'; +import { ensureVite } from './steps/vite.ts'; + +// 0-255 range +function rgbText(text: string, r: number, g: number, b: number) { + return `\x1b[38;2;${r};${g};${b}m${text}\x1b[39m`; +} + +async function runViteFlow(cwd: string, pm: Agent, pkg: PackageJson) { + await ensureWebgpuTypes(cwd, pm, pkg); + await ensureVite(cwd, pm, pkg); + await ensureTypegpu(pm, pkg); +} + +async function runReactNativeFlow(cwd: string, pm: Agent, pkg: PackageJson) { + await ensureWebgpuTypes(cwd, pm, pkg); +} + +// real script starts here +const argv = mri(process.argv.slice(2), { + alias: { h: 'help' }, + boolean: ['help'], +}); + +if (argv.help) { + console.log('Usage: node tgpu'); + process.exit(0); +} + +p.intro('Enhancing project with TypeGPU'); + +const cwd = process.cwd(); +const pm = await detect({ cwd }); +if (!pm) { + failAndExit('Could not detect package manager.'); +} +const pmAgent = pm.agent; +p.log.info(`Detected package manager: ${pmAgent}`); + +const pkgPath = path.join(cwd, 'package.json'); +if (!fs.existsSync(pkgPath)) { + failAndExit('No package.json found in the current directory.'); +} +const pkg = PackageJsonSchema(JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))); +if (pkg instanceof type.errors) { + failAndExit('Could not parse package.json', pkg.summary); +} + +const projectKind = await p.select({ + message: 'What kind of project is this?', + options: [ + { value: 'vite', label: rgbText('Vite', 175, 105, 245) }, + { value: 'react-native', label: rgbText('React Native', 100, 108, 238) }, + ], +}); +if (p.isCancel(projectKind)) { + cancelExit(); +} + +switch (projectKind) { + case 'vite': + await runViteFlow(cwd, pm.agent, pkg); + break; + case 'react-native': + // await runReactNativeFlow(cwd, pm.agent, pkg); + break; + default: + failAndExit('Unsupported project kind.'); +} +await pmInstall(pm.agent); +p.outro('Done! Get ready for a shaderful experience.'); diff --git a/packages/tgpu/src/steps/typegpu.ts b/packages/tgpu/src/steps/typegpu.ts new file mode 100644 index 0000000000..889198556c --- /dev/null +++ b/packages/tgpu/src/steps/typegpu.ts @@ -0,0 +1,16 @@ +import type { Agent } from 'package-manager-detector'; +import * as p from '@clack/prompts'; + +import { hasDependency } from '../utils/pkg.ts'; +import type { PackageJson } from '../utils/types.ts'; +import { pmAdd } from '../utils/pm.ts'; +import { confirmStep } from '../utils/prompts.ts'; + +export async function ensureTypegpu(pm: Agent, pkg: PackageJson) { + if (hasDependency(pkg, 'typegpu')) { + p.log.info('typegpu is already installed.'); + return; + } + if (!(await confirmStep('Install typegpu?'))) return; + await pmAdd(pm, ['typegpu'], false); +} diff --git a/packages/tgpu/src/steps/vite.ts b/packages/tgpu/src/steps/vite.ts new file mode 100644 index 0000000000..e8fcdc994d --- /dev/null +++ b/packages/tgpu/src/steps/vite.ts @@ -0,0 +1,68 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import * as p from '@clack/prompts'; +import type { Agent } from 'package-manager-detector'; +import { loadFile, writeFile } from 'magicast'; +import { addVitePlugin } from 'magicast/helpers'; + +import { hasDependency } from '../utils/pkg.ts'; +import { pmAdd } from '../utils/pm.ts'; +import { confirmStep } from '../utils/prompts.ts'; +import type { PackageJson } from '../utils/types.ts'; + +const VITE_CONFIG_NAMES = [ + 'vite.config.ts', + 'vite.config.js', + 'vite.config.mts', + 'vite.config.mjs', + 'vite.config.cts', + 'vite.config.cjs', +]; + +const TEMPLATE = `import { defineConfig } from 'vite'; +import typegpuPlugin from 'unplugin-typegpu/vite'; + +export default defineConfig({ + plugins: [typegpuPlugin()], +}); +`; + +function findViteConfig(cwd: string) { + for (const name of VITE_CONFIG_NAMES) { + const viteConfigPath = path.join(cwd, name); + if (fs.existsSync(viteConfigPath)) return viteConfigPath; + } + return undefined; +} + +async function setupViteConfig(filePath: string) { + const config = await loadFile(filePath); + addVitePlugin(config, { from: 'unplugin-typegpu/vite', constructor: 'typegpuPlugin' }); + await writeFile(config, filePath); + p.log.success(`Updated ${path.basename(filePath)}.`); +} + +function createViteConfig(cwd: string) { + fs.writeFileSync(path.join(cwd, 'vite.config.ts'), TEMPLATE); + p.log.success('Created vite.config.ts.'); +} + +export async function ensureVite(cwd: string, pm: Agent, pkg: PackageJson) { + if (hasDependency(pkg, 'unplugin-typegpu')) { + p.log.info('unplugin-typegpu is already installed.'); + return; + } + + if (!(await confirmStep('Install unplugin-typegpu and configure vite?'))) { + return; + } + + await pmAdd(pm, ['unplugin-typegpu'], true); + + const viteConfigPath = findViteConfig(cwd); + if (viteConfigPath) { + await setupViteConfig(viteConfigPath); + } else if (await confirmStep('No vite config found. Create vite.config.ts?')) { + createViteConfig(cwd); + } +} diff --git a/packages/tgpu/src/steps/webgpu-types.ts b/packages/tgpu/src/steps/webgpu-types.ts new file mode 100644 index 0000000000..52acc7ada5 --- /dev/null +++ b/packages/tgpu/src/steps/webgpu-types.ts @@ -0,0 +1,67 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import * as p from '@clack/prompts'; +import { parse, stringify } from 'comment-json'; + +import { hasDependency } from '../utils/pkg.ts'; +import { pmAdd } from '../utils/pm.ts'; +import { confirmStep, failAndExit } from '../utils/prompts.ts'; +import { TsConfigSchema, type PackageJson } from '../utils/types.ts'; +import type { Agent } from 'package-manager-detector'; +import { type } from 'arktype'; + +function findTsconfig(cwd: string) { + for (const name of ['tsconfig.app.json', 'tsconfig.json']) { + const full = path.join(cwd, name); + if (fs.existsSync(full)) return full; + } + return undefined; +} + +function addWebgpuTypesToTsconfig(filePath: string) { + const content = fs.readFileSync(filePath, 'utf-8'); + const parsed = parse(content); + if (!parsed) { + failAndExit(`Could not parse tsconfig.`); + } + const tsconfig = TsConfigSchema(parsed); + if (tsconfig instanceof type.errors) { + failAndExit(`Could not parse tsconfig.`, tsconfig.summary); + } + + if (!tsconfig.compilerOptions) { + tsconfig.compilerOptions = {}; + } + + if (!tsconfig.compilerOptions.types) { + tsconfig.compilerOptions.types = []; + } + + if (tsconfig.compilerOptions.types?.includes('@webgpu/types')) { + return; + } + + tsconfig.compilerOptions.types.push('@webgpu/types'); + fs.writeFileSync(filePath, stringify(tsconfig, null, 2) + '\n'); +} + +export async function ensureWebgpuTypes(cwd: string, pm: Agent, pkg: PackageJson) { + if (hasDependency(pkg, '@webgpu/types')) { + p.log.info('@webgpu/types is already installed.'); + return; + } + + if (!(await confirmStep('Install @webgpu/types and add to tsconfig?'))) { + return; + } + + const tsconfig = findTsconfig(cwd); + if (!tsconfig) { + failAndExit('No tsconfig found, cannot register @webgpu/types.'); + } + + await pmAdd(pm, ['@webgpu/types'], true); + + addWebgpuTypesToTsconfig(tsconfig); + p.log.success(`Added @webgpu/types to ${path.basename(tsconfig)}.`); +} diff --git a/packages/tgpu/src/utils/pkg.ts b/packages/tgpu/src/utils/pkg.ts new file mode 100644 index 0000000000..b384bdfffa --- /dev/null +++ b/packages/tgpu/src/utils/pkg.ts @@ -0,0 +1,12 @@ +import type { PackageJson } from './types.ts'; + +export function hasDependency(pkg: PackageJson, name: string) { + const deps = pkg.dependencies ?? {}; + const devDeps = pkg.devDependencies ?? {}; + const peerDeps = pkg.peerDependencies ?? {}; + return name in deps || name in devDeps || name in peerDeps; +} + +export function isExpoProject(pkg: PackageJson) { + return hasDependency(pkg, 'expo'); +} diff --git a/packages/tgpu/src/utils/pm.ts b/packages/tgpu/src/utils/pm.ts new file mode 100644 index 0000000000..2506594a43 --- /dev/null +++ b/packages/tgpu/src/utils/pm.ts @@ -0,0 +1,91 @@ +import spawn from 'cross-spawn'; +import * as p from '@clack/prompts'; +import { resolveCommand } from '@antfu/ni'; +import type { Agent } from 'package-manager-detector'; +import { failAndExit } from './prompts.ts'; + +type RunCommandOptions = { + cwd?: string; + interactive?: boolean; +}; + +async function runCommand(command: string, args: string[], options: RunCommandOptions = {}) { + const child = spawn(command, args, { + cwd: options.cwd, + stdio: options.interactive ? 'inherit' : ['inherit', 'ignore', 'inherit'], + }); + + return await new Promise((resolve, reject) => { + child.on('error', reject); + child.on('close', (code) => resolve(code ?? 1)); + }); +} + +export function runInteractive(command: string, args: string[], cwd?: string) { + const result = spawn.sync(command, args, { cwd, stdio: 'inherit' }); + return result.status ?? 1; +} + +export async function pmAdd(pm: Agent, pkgs: string[], dev: boolean) { + const args = dev ? ['-D', ...pkgs] : pkgs; + const cmd = resolveCommand(pm, 'add', args); + if (!cmd) { + failAndExit(`Cannot resolve add command for ${pm}.`); + } + + const label = pkgs.join(', '); + const s = p.spinner(); + s.start(`Installing ${label}`); + const status = await runCommand(cmd.command, cmd.args); + if (status !== 0) { + s.stop(`Failed to install ${label}.`, 1); + failAndExit('Package installation failed.'); + } + s.stop(`Installed ${label}`); +} + +export async function pmInstall(pm: Agent) { + const cmd = resolveCommand(pm, 'install', []); + if (!cmd) { + failAndExit(`Cannot resolve install command for ${pm}.`); + } + + const s = p.spinner(); + s.start('Installing dependencies'); + const status = await runCommand(cmd.command, cmd.args); + if (status !== 0) { + s.stop('Failed to install dependencies.', 1); + failAndExit('Dependency installation failed.'); + } + s.stop('Installed dependencies'); +} + +export async function pmExec( + pm: Agent, + bin: string, + args: string[] = [], + options: RunCommandOptions = {}, +) { + const cmd = resolveCommand(pm, 'execute-local', [bin, ...args]); + if (!cmd) { + failAndExit(`Cannot resolve exec command for ${pm}.`); + } + + const label = `${cmd.command}${cmd.args.length ? ` ${cmd.args.join(' ')}` : ''}`; + if (options.interactive) { + const status = await runCommand(cmd.command, cmd.args, options); + if (status !== 0) { + failAndExit(`\`${label}\` failed.`); + } + return; + } + + const s = p.spinner(); + s.start(`Running \`${label}\``); + const status = await runCommand(cmd.command, cmd.args, options); + if (status !== 0) { + s.stop(`\`${label}\` failed.`, 1); + failAndExit('Command failed.'); + } + s.stop(`\`${label}\` done.`); +} diff --git a/packages/tgpu/src/utils/prompts.ts b/packages/tgpu/src/utils/prompts.ts new file mode 100644 index 0000000000..bc1b8c0ce7 --- /dev/null +++ b/packages/tgpu/src/utils/prompts.ts @@ -0,0 +1,20 @@ +import * as p from '@clack/prompts'; + +export function cancelExit(): never { + p.cancel('Operation cancelled.'); + process.exit(0); +} + +export function failAndExit(message: string, detail?: string): never { + p.cancel(message); + if (detail) console.error(detail); + process.exit(1); +} + +export async function confirmStep(message: string) { + const res = await p.confirm({ message }); + if (p.isCancel(res)) { + cancelExit(); + } + return res; +} diff --git a/packages/tgpu/src/utils/types.ts b/packages/tgpu/src/utils/types.ts new file mode 100644 index 0000000000..eb847c8287 --- /dev/null +++ b/packages/tgpu/src/utils/types.ts @@ -0,0 +1,15 @@ +import { type } from 'arktype'; + +export const PackageJsonSchema = type({ + 'dependencies?': 'Record', + 'devDependencies?': 'Record', + 'peerDependencies?': 'Record', +}); +export type PackageJson = typeof PackageJsonSchema.infer; + +export const TsConfigSchema = type({ + 'compilerOptions?': { + 'types?': 'string[]', + }, +}); +export type TsConfig = typeof TsConfigSchema.infer; diff --git a/packages/tgpu/tsconfig.json b/packages/tgpu/tsconfig.json new file mode 100644 index 0000000000..e612d05821 --- /dev/null +++ b/packages/tgpu/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], +} diff --git a/packages/tgpu/tsdown.config.ts b/packages/tgpu/tsdown.config.ts new file mode 100644 index 0000000000..16b645e6a1 --- /dev/null +++ b/packages/tgpu/tsdown.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + target: 'esnext', + dts: false, + clean: true, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fdc3d551a..3d74c086a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,7 +43,7 @@ catalogs: version: 0.181.0 '@webgpu/types': specifier: ^0.1.66 - version: 0.1.66 + version: 0.1.69 overrides: rollup: ^4.60.0 @@ -72,7 +72,7 @@ importers: version: 3.1.2(@vitest/browser@3.2.4(msw@2.10.2(@types/node@24.10.0)(tsover@5.9.11))(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@24.10.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.3))(vitest@4.1.2))(vitest@4.1.2) '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 bun: specifier: 'catalog:' version: 1.3.10 @@ -130,7 +130,7 @@ importers: devDependencies: '@types/bun': specifier: latest - version: 1.3.12 + version: 1.3.13 apps/infra-benchmarks: devDependencies: @@ -391,7 +391,7 @@ importers: version: 4.1.2(msw@2.10.2(@types/node@24.10.0)(tsover@5.9.11))(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@24.10.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.3))(vitest@4.1.2) '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 astro-vtbot: specifier: ^2.1.10 version: 2.1.10(prettier@3.8.0)(tsover@5.9.11) @@ -448,6 +448,46 @@ importers: specifier: ^4.0.17 version: 4.0.18(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@24.10.0)(@vitest/browser-preview@4.1.2(msw@2.10.2(@types/node@24.10.0)(tsover@5.9.11))(vite@8.0.5(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(@types/node@24.10.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.3))(vitest@4.1.2))(esbuild@0.27.5)(jiti@2.6.1)(jsdom@27.0.0(canvas@3.2.0)(postcss@8.5.8))(msw@2.10.2(@types/node@24.10.0)(tsover@5.9.11))(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.3) + packages/tgpu: + dependencies: + '@antfu/ni': + specifier: ^25.0.0 + version: 25.0.0 + '@clack/prompts': + specifier: ^0.9.1 + version: 0.9.1 + comment-json: + specifier: ^5.0.0 + version: 5.0.0 + cross-spawn: + specifier: ^7.0.6 + version: 7.0.6 + magicast: + specifier: ^0.5.2 + version: 0.5.2 + mri: + specifier: ^1.2.0 + version: 1.2.0 + package-manager-detector: + specifier: ^1.3.0 + version: 1.6.0 + devDependencies: + '@types/cross-spawn': + specifier: ^6.0.6 + version: 6.0.6 + '@types/node': + specifier: ^24.10.0 + version: 24.10.0 + arktype: + specifier: 'catalog:' + version: 2.1.28 + tsdown: + specifier: catalog:build + version: 0.15.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(tsover@5.9.11)(unrun@0.2.34(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)) + typescript: + specifier: npm:tsover@^5.9.11 + version: tsover@5.9.11 + packages/tgpu-dev-cli: dependencies: arg: @@ -563,7 +603,7 @@ importers: version: 24.10.0 '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 arktype: specifier: 'catalog:' version: 2.1.28 @@ -597,7 +637,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 typegpu: specifier: workspace:* version: link:../typegpu @@ -619,7 +659,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 typegpu: specifier: workspace:* version: link:../typegpu @@ -641,7 +681,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 tinyest: specifier: workspace:^0.3.0 version: link:../tinyest @@ -672,7 +712,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 typegpu: specifier: workspace:* version: link:../typegpu @@ -694,7 +734,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 tsdown: specifier: catalog:build version: 0.15.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(tsover@5.9.11)(unrun@0.2.34(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)) @@ -735,7 +775,7 @@ importers: version: 19.1.6(@types/react@19.1.8) '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 jiti: specifier: catalog:build version: 2.6.1 @@ -769,7 +809,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 tsdown: specifier: catalog:build version: 0.15.12(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)(tsover@5.9.11)(unrun@0.2.34(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)) @@ -791,7 +831,7 @@ importers: version: link:../tgpu-dev-cli '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 typegpu: specifier: workspace:* version: link:../typegpu @@ -836,7 +876,7 @@ importers: version: 0.181.0 '@webgpu/types': specifier: catalog:types - version: 0.1.66 + version: 0.1.69 typegpu: specifier: workspace:* version: link:../typegpu @@ -940,6 +980,10 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@antfu/ni@25.0.0': + resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} + hasBin: true + '@ark/attest@0.56.0': resolution: {integrity: sha512-Pngs8f1UJiWbeO8LKVdyBL0K3rT/PDVACR7TPyCEULNcN8V1rVec6dKvUnQVpQSj60p4ejlK6dKs+fQoqdUMqA==} hasBin: true @@ -1476,9 +1520,15 @@ packages: resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} engines: {node: '>=18'} + '@clack/core@0.4.1': + resolution: {integrity: sha512-Pxhij4UXg8KSr7rPek6Zowm+5M22rbd2g1nfojHJkxp5YkFqiZ2+YLEM/XGVIzvGOcM0nqjIFxrpDwWRZYWYjA==} + '@clack/core@1.1.0': resolution: {integrity: sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==} + '@clack/prompts@0.9.1': + resolution: {integrity: sha512-JIpyaboYZeWYlyP0H+OoPPxd6nqueG/CmN6ixBiNFsIDHREevjIf0n0Ohh5gr5C8pEDknzgvz+pIJ8dMhzWIeg==} + '@clack/prompts@1.1.0': resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==} @@ -4046,12 +4096,18 @@ packages: '@types/bun@1.3.12': resolution: {integrity: sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A==} + '@types/bun@1.3.13': + resolution: {integrity: sha512-9fqXWk5YIHGGnUau9TEi+qdlTYDAnOj+xLCmSTwXfAIqXr2x4tytJb43E9uCvt09zJURKXwAtkoH4nLQfzeTXw==} + '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/cross-spawn@6.0.6': + resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -4235,6 +4291,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@vitejs/plugin-basic-ssl@2.1.0': resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==} @@ -4446,8 +4503,8 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - '@webgpu/types@0.1.66': - resolution: {integrity: sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA==} + '@webgpu/types@0.1.69': + resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} '@webpack-cli/configtest@3.0.1': resolution: {integrity: sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==} @@ -4610,6 +4667,9 @@ packages: array-iterate@2.0.1: resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -4786,6 +4846,9 @@ packages: bun-types@1.3.12: resolution: {integrity: sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA==} + bun-types@1.3.13: + resolution: {integrity: sha512-QXKeHLlOLqQX9LgYaHJfzdBaV21T63HhFJnvuRCcjZiaUDpbs5ED1MgxbMra71CsryN/1dAoXuJJJwIv/2drVA==} + bun@1.3.10: resolution: {integrity: sha512-S/CXaXXIyA4CMjdMkYQ4T2YMqnAn4s0ysD3mlsY4bUiOCqGlv28zck4Wd4H4kpvbekx15S9mUeLQ7Uxd0tYTLA==} cpu: [arm64, x64] @@ -4978,6 +5041,10 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + comment-json@5.0.0: + resolution: {integrity: sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==} + engines: {node: '>= 6'} + common-ancestor-path@2.0.0: resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} engines: {node: '>= 18'} @@ -5804,6 +5871,9 @@ packages: resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} engines: {node: '>=10'} + fzf@0.5.2: + resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -5824,9 +5894,6 @@ packages: resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} engines: {node: '>=18'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} - get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} @@ -7064,6 +7131,10 @@ packages: react-dom: optional: true + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -9439,6 +9510,13 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 + '@antfu/ni@25.0.0': + dependencies: + ansis: 4.2.0 + fzf: 0.5.2 + package-manager-detector: 1.6.0 + tinyexec: 1.1.1 + '@ark/attest@0.56.0(tsover@5.9.11)': dependencies: '@ark/fs': 0.56.0 @@ -9507,7 +9585,7 @@ snapshots: '@volar/language-server': 2.4.27 '@volar/language-service': 2.4.27 muggle-string: 0.4.1 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 volar-service-css: 0.0.68(@volar/language-service@2.4.27) volar-service-emmet: 0.0.68(@volar/language-service@2.4.27) volar-service-html: 0.0.68(@volar/language-service@2.4.27) @@ -10250,10 +10328,21 @@ snapshots: dependencies: fontkitten: 1.0.3 + '@clack/core@0.4.1': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@clack/core@1.1.0': dependencies: sisteransi: 1.0.5 + '@clack/prompts@0.9.1': + dependencies: + '@clack/core': 0.4.1 + picocolors: 1.1.1 + sisteransi: 1.0.5 + '@clack/prompts@1.1.0': dependencies: '@clack/core': 1.1.0 @@ -12365,6 +12454,10 @@ snapshots: dependencies: bun-types: 1.3.12 + '@types/bun@1.3.13': + dependencies: + bun-types: 1.3.13 + '@types/chai@5.2.2': dependencies: '@types/deep-eql': 4.0.2 @@ -12372,6 +12465,10 @@ snapshots: '@types/cookie@0.6.0': optional: true + '@types/cross-spawn@6.0.6': + dependencies: + '@types/node': 24.10.0 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -12471,7 +12568,7 @@ snapshots: '@tweenjs/tween.js': 23.1.3 '@types/stats.js': 0.17.4 '@types/webxr': 0.5.22 - '@webgpu/types': 0.1.66 + '@webgpu/types': 0.1.69 fflate: 0.8.2 meshoptimizer: 0.22.0 @@ -12961,7 +13058,7 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@webgpu/types@0.1.66': {} + '@webgpu/types@0.1.69': {} '@webpack-cli/configtest@3.0.1(webpack-cli@6.0.1)(webpack@5.104.1)': dependencies: @@ -13087,6 +13184,8 @@ snapshots: array-iterate@2.0.1: {} + array-timsort@1.0.3: {} + asap@2.0.6: {} ast-kit@2.2.0: @@ -13419,6 +13518,10 @@ snapshots: dependencies: '@types/node': 24.10.0 + bun-types@1.3.13: + dependencies: + '@types/node': 24.10.0 + bun@1.3.10: optionalDependencies: '@oven/bun-darwin-aarch64': 1.3.10 @@ -13596,6 +13699,11 @@ snapshots: commander@8.3.0: {} + comment-json@5.0.0: + dependencies: + array-timsort: 1.0.3 + esprima: 4.0.1 + common-ancestor-path@2.0.0: {} commondir@1.0.1: {} @@ -14524,6 +14632,8 @@ snapshots: fuse.js@7.1.0: {} + fzf@0.5.2: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -14537,10 +14647,6 @@ snapshots: '@sec-ant/readable-stream': 0.4.1 is-stream: 4.0.1 - get-tsconfig@4.13.6: - dependencies: - resolve-pkg-maps: 1.0.0 - get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 @@ -16268,6 +16374,8 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) + mri@1.2.0: {} + mrmime@2.0.1: {} ms@2.0.0: {} @@ -18131,7 +18239,7 @@ snapshots: tsx@4.20.6: dependencies: esbuild: 0.25.12 - get-tsconfig: 4.13.6 + get-tsconfig: 4.13.7 optionalDependencies: fsevents: 2.3.3 @@ -18371,7 +18479,7 @@ snapshots: unplugin@2.3.5: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 picomatch: 4.0.4 webpack-virtual-modules: 0.6.2