CLI: Improve CLI interactive experience

This commit is contained in:
Fuma Nama
2026-01-29 21:20:17 +08:00
parent 887d07207f
commit 65ff886132
42 changed files with 773 additions and 650 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@fumadocs/cli': patch
---
Improve CLI interactive experience
+5 -5
View File
@@ -13,8 +13,8 @@
"start": "next start"
},
"dependencies": {
"@ai-sdk/openai-compatible": "^2.0.21",
"@ai-sdk/react": "^3.0.59",
"@ai-sdk/openai-compatible": "^2.0.22",
"@ai-sdk/react": "^3.0.61",
"@fumadocs/mdx-remote": "workspace:*",
"@fumadocs/story": "workspace:*",
"@mixedbread/sdk": "^0.50.1",
@@ -27,8 +27,8 @@
"@radix-ui/react-tooltip": "^1.2.8",
"@shikijs/rehype": "^3.21.0",
"@shikijs/transformers": "^3.21.0",
"@takumi-rs/image-response": "^0.66.5",
"ai": "^6.0.57",
"@takumi-rs/image-response": "^0.66.6",
"ai": "^6.0.59",
"class-variance-authority": "^0.7.1",
"d3-force": "^3.0.0",
"estree-util-build-jsx": "^3.0.1",
@@ -77,7 +77,7 @@
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/mdx": "^2.0.13",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@types/three": "^0.182.0",
+1 -1
View File
@@ -14,7 +14,7 @@
"@astrojs/mdx": "^4.3.13",
"@astrojs/react": "^4.4.2",
"@orama/orama": "^3.1.18",
"astro": "^5.16.15",
"astro": "^5.17.0",
"fumadocs-core": "workspace:*",
"fumadocs-ui": "workspace:*",
"react": "^19.2.4",
+1 -1
View File
@@ -21,7 +21,7 @@
"@remix-run/node-fetch-server": "^0.13.0",
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"express": "^5.2.1",
+2 -2
View File
@@ -11,7 +11,7 @@
"fumadocs-core": "workspace:*",
"fumadocs-ui": "workspace:*",
"github-slugger": "^2.0.0",
"html-react-parser": "^5.2.13",
"html-react-parser": "^5.2.14",
"next": "16.1.6",
"react": "^19.2.4",
"react-dom": "^19.2.4",
@@ -19,7 +19,7 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.18",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
+1 -1
View File
@@ -21,7 +21,7 @@
"devDependencies": {
"@tailwindcss/postcss": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
+1 -1
View File
@@ -21,7 +21,7 @@
"devDependencies": {
"@tailwindcss/postcss": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
+1 -1
View File
@@ -22,7 +22,7 @@
"devDependencies": {
"@tailwindcss/postcss": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"postcss": "^8.5.6",
+1 -1
View File
@@ -24,7 +24,7 @@
"@react-router/dev": "^7.13.0",
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"react-router-devtools": "^6.2.0",
+1 -1
View File
@@ -23,7 +23,7 @@
"@react-router/dev": "^7.13.0",
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-rsc": "^0.5.17",
+1 -1
View File
@@ -23,7 +23,7 @@
"@react-router/dev": "^7.13.0",
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"react-router-devtools": "^6.2.0",
+1 -1
View File
@@ -23,7 +23,7 @@
"@react-router/dev": "^7.13.0",
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"react-router-devtools": "^6.2.0",
+1 -1
View File
@@ -26,7 +26,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
+1 -1
View File
@@ -27,7 +27,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
+1 -1
View File
@@ -27,7 +27,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
+1 -1
View File
@@ -25,7 +25,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
+1 -1
View File
@@ -22,7 +22,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"tailwindcss": "^4.1.18",
+1 -1
View File
@@ -23,7 +23,7 @@
"devDependencies": {
"@tailwindcss/vite": "^4.1.18",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"tailwindcss": "^4.1.18",
+1 -1
View File
@@ -27,7 +27,7 @@
"eslint-plugin-tailwindcss": "^3.18.2",
"oxfmt": "^0.27.0",
"rimraf": "^6.1.2",
"turbo": "2.7.6",
"turbo": "2.8.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0",
"vitest": "^4.0.18"
+1 -1
View File
@@ -106,7 +106,7 @@
"devDependencies": {
"@fumadocs/cli": "workspace:*",
"@tailwindcss/cli": "^4.1.18",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-custom": "workspace:*",
+3 -3
View File
@@ -35,11 +35,11 @@
"types:check": "tsc --noEmit"
},
"dependencies": {
"@clack/prompts": "^0.11.0",
"@clack/prompts": "^1.0.0",
"commander": "^14.0.2",
"magic-string": "^0.30.21",
"oxc-parser": "^0.111.0",
"oxc-resolver": "^11.16.4",
"oxc-resolver": "^11.17.0",
"package-manager-detector": "^1.6.0",
"picocolors": "^1.1.1",
"tinyexec": "^1.0.2",
@@ -47,7 +47,7 @@
},
"devDependencies": {
"@oxc-project/types": "^0.111.0",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"eslint-config-custom": "workspace:*",
"shadcn": "3.7.0",
"tsconfig": "workspace:*",
+58 -10
View File
@@ -1,4 +1,12 @@
import { intro, isCancel, log, multiselect, outro, spinner } from '@clack/prompts';
import {
isCancel,
autocompleteMultiselect,
outro,
spinner,
confirm,
box,
log,
} from '@clack/prompts';
import picocolors from 'picocolors';
import { ComponentInstaller } from '@/registry/installer';
import type { RegistryClient } from '@/registry/client';
@@ -38,7 +46,7 @@ export async function add(input: string[], client: RegistryClient) {
}
spin.stop(picocolors.bold(picocolors.greenBright('registry fetched')));
const value = await multiselect({
const value = await autocompleteMultiselect({
message: 'Select components to install',
options,
});
@@ -60,21 +68,61 @@ export async function add(input: string[], client: RegistryClient) {
export async function install(target: string[], installer: ComponentInstaller) {
for (const name of target) {
intro(picocolors.bold(picocolors.inverse(picocolors.cyanBright(`Add Component: ${name}`))));
const spin = spinner();
spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));
try {
await installer.install(name);
outro(picocolors.bold(picocolors.greenBright(`${name} installed`)));
await installer.install(name, {
onWarn(message) {
spin.message(message);
},
async confirmFileOverride(options) {
spin.clear();
const value = await confirm({
message: `Do you want to override ${options.path}?`,
initialValue: false,
});
if (isCancel(value)) {
outro('Installation terminated');
process.exit(0);
}
spin.start(picocolors.bold(picocolors.cyanBright(`Installing ${name}`)));
return value;
},
onFileDownloaded(options) {
spin.message(options.path);
},
});
spin.stop(picocolors.bold(picocolors.greenBright(`${name} installed`)));
} catch (e) {
log.error(String(e));
throw e;
spin.error(e instanceof Error ? e.message : String(e));
process.exit(-1);
}
}
intro(picocolors.bold('New Dependencies'));
const deps = await installer.deps();
if (deps.hasRequired()) {
log.message();
box([...deps.dependencies, ...deps.devDependencies].join('\n'), 'New Dependencies');
const value = await confirm({
message: `Do you want to install with ${deps.packageManager}?`,
});
if (isCancel(value)) {
outro('Installation terminated');
process.exit(0);
}
if (value) {
const spin = spinner({
errorMessage: 'Failed to install dependencies',
});
spin.start('Installing dependencies');
await deps.installRequired();
spin.stop('Dependencies installed');
}
}
await installer.installDeps();
await installer.onEnd();
outro(picocolors.bold(picocolors.greenBright('Successful')));
}
+4 -4
View File
@@ -7,7 +7,6 @@ import {
import path from 'node:path';
import fs from 'node:fs/promises';
import type { LoadedConfig } from '@/config';
import { log } from '@clack/prompts';
import { createCache } from '@/utils/cache';
export interface RegistryClient {
@@ -50,7 +49,9 @@ export class HttpRegistryClient implements RegistryClient {
return fetchCache.$value<Component>().cached(url.href, async () => {
const res = await fetch(`${this.baseUrl}/${name}.json`);
if (!res.ok) {
log.error(`component ${name} not found at ${url.href}`);
if (res.status === 404) {
throw new Error(`component ${name} not found at ${url.href}`);
}
throw new Error(await res.text());
}
@@ -102,8 +103,7 @@ export class LocalRegistryClient implements RegistryClient {
.readFile(filePath)
.then((res) => JSON.parse(res.toString()))
.catch((e) => {
log.error(`component ${name} not found at ${filePath}`);
throw e;
throw new Error(`component ${name} not found at ${filePath}`, { cause: e });
});
return componentSchema.parse(out);
@@ -1,70 +1,56 @@
import { exists } from '@/utils/fs';
import fs from 'node:fs/promises';
import { getPackageManager } from '@/utils/get-package-manager';
import { confirm, isCancel, spinner } from '@clack/prompts';
import { getPackageManager, PackageManager } from '@/utils/get-package-manager';
import { x } from 'tinyexec';
export class DependencyManager {
private cachedInstalledDeps: Map<string, string> | undefined;
private installedDeps = new Map<string, string>();
dependencies: string[] = [];
devDependencies: string[] = [];
packageManager: PackageManager = 'npm';
/**
* Get dependencies from `package.json`
*/
async getDeps(): Promise<Map<string, string>> {
if (this.cachedInstalledDeps) return this.cachedInstalledDeps;
const dependencies = new Map<string, string>();
async init(deps: Record<string, string | null>, devDeps: Record<string, string | null>) {
this.installedDeps.clear();
if (await exists('package.json')) {
const content = await fs.readFile('package.json');
const parsed = JSON.parse(content.toString()) as object;
if (!(await exists('package.json'))) return dependencies;
if ('dependencies' in parsed && typeof parsed.dependencies === 'object') {
const records = parsed.dependencies as Record<string, string>;
const content = await fs.readFile('package.json');
const parsed = JSON.parse(content.toString()) as object;
for (const [k, v] of Object.entries(records)) {
this.installedDeps.set(k, v);
}
}
if ('dependencies' in parsed && typeof parsed.dependencies === 'object') {
const records = parsed.dependencies as Record<string, string>;
if ('devDependencies' in parsed && typeof parsed.devDependencies === 'object') {
const records = parsed.devDependencies as Record<string, string>;
for (const [k, v] of Object.entries(records)) {
dependencies.set(k, v);
for (const [k, v] of Object.entries(records)) {
this.installedDeps.set(k, v);
}
}
}
if ('devDependencies' in parsed && typeof parsed.devDependencies === 'object') {
const records = parsed.devDependencies as Record<string, string>;
for (const [k, v] of Object.entries(records)) {
dependencies.set(k, v);
}
}
return (this.cachedInstalledDeps = dependencies);
this.dependencies = this.resolveRequiredDependencies(deps);
this.devDependencies = this.resolveRequiredDependencies(devDeps);
this.packageManager = await getPackageManager();
}
private async resolveInstallDependencies(deps: Record<string, string | null>): Promise<string[]> {
const cachedInstalledDeps = await this.getDeps();
private resolveRequiredDependencies(deps: Record<string, string | null>): string[] {
return Object.entries(deps)
.filter(([k]) => !cachedInstalledDeps.has(k))
.filter(([k]) => !this.installedDeps.has(k))
.map(([k, v]) => (v === null || v.length === 0 ? k : `${k}@${v}`));
}
async installDeps(deps: Record<string, string | null>, devDeps: Record<string, string | null>) {
const items = await this.resolveInstallDependencies(deps);
const devItems = await this.resolveInstallDependencies(devDeps);
if (items.length === 0 && devItems.length === 0) return;
hasRequired() {
return this.dependencies.length > 0 || this.devDependencies.length > 0;
}
const manager = await getPackageManager();
const value = await confirm({
message: `Do you want to install with ${manager}?
${[...items, ...devItems].map((v) => `- ${v}`).join('\n')}`,
});
if (isCancel(value) || !value) {
return;
}
const spin = spinner();
spin.start('Installing dependencies...');
if (items.length > 0) await x(manager, ['install', ...items]);
if (devItems.length > 0) await x(manager, ['install', ...devItems, '-D']);
spin.stop('Dependencies installed.');
async installRequired() {
if (this.dependencies.length > 0)
await x(this.packageManager, ['install', ...this.dependencies]);
if (this.devDependencies.length > 0)
await x(this.packageManager, ['install', ...this.devDependencies, '-D']);
}
}
+16 -17
View File
@@ -1,6 +1,5 @@
import path from 'node:path';
import fs from 'node:fs/promises';
import { confirm, isCancel, log, outro } from '@clack/prompts';
import { typescriptExtensions } from '@/constants';
import { toImportSpecifier, transformSpecifiers } from '@/utils/ast';
import type { Component, File } from '@/registry/schema';
@@ -28,6 +27,12 @@ export interface ComponentInstallerPlugin {
}) => void | Promise<void>;
}
export interface IOInterface {
onWarn: (message: string) => void;
confirmFileOverride: (options: { path: string }) => Promise<boolean>;
onFileDownloaded: (options: { path: string; file: File; component: DownloadedComponent }) => void;
}
export class ComponentInstaller {
private readonly installedFiles = new Set<string>();
private readonly downloadCache = createCache<DownloadedComponent[]>();
@@ -39,7 +44,7 @@ export class ComponentInstaller {
private readonly plugins: ComponentInstallerPlugin[] = [],
) {}
async install(name: string) {
async install(name: string, io: IOInterface) {
let downloaded: DownloadedComponent[];
// detect linked registry
const info = await this.rootClient.fetchRegistryInfo();
@@ -68,7 +73,7 @@ export class ComponentInstaller {
this.installedFiles.add(outPath);
const output = typescriptExtensions.includes(path.extname(outPath))
? await this.transform(name, file, comp, downloaded)
? await this.transform(io, name, file, comp, downloaded)
: file.content;
const status = await fs
@@ -82,28 +87,21 @@ export class ComponentInstaller {
if (status === 'ignore') continue;
if (status === 'need-update') {
const override = await confirm({
message: `Do you want to override ${outPath}?`,
initialValue: false,
});
if (isCancel(override)) {
outro('Ended');
process.exit(0);
}
const override = await io.confirmFileOverride({ path: outPath });
if (!override) continue;
}
await fs.mkdir(path.dirname(outPath), { recursive: true });
await fs.writeFile(outPath, output);
log.step(`downloaded ${outPath}`);
io.onFileDownloaded({ path: outPath, file, component: comp });
}
}
}
async installDeps() {
await new DependencyManager().installDeps(this.dependencies, this.devDependencies);
async deps() {
const manager = new DependencyManager();
await manager.init(this.dependencies, this.devDependencies);
return manager;
}
async onEnd() {
@@ -158,6 +156,7 @@ export class ComponentInstaller {
private readonly pathToFileCache = createCache<Map<string, File>>();
private async transform(
io: IOInterface,
taskId: string,
file: File,
component: DownloadedComponent,
@@ -190,7 +189,7 @@ export class ComponentInstaller {
if (target) {
specifier = toImportSpecifier(filePath, this.resolveOutputPath(target));
} else {
console.warn(`cannot find the referenced file of ${specifier}`);
io.onWarn(`cannot find the referenced file of ${specifier}`);
}
}
+1 -1
View File
@@ -43,7 +43,7 @@
"devDependencies": {
"@content-collections/core": "^0.13.1",
"@content-collections/mdx": "^0.2.2",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"eslint-config-custom": "workspace:*",
"fumadocs-core": "workspace:*",
"tsconfig": "workspace:*",
+1 -1
View File
@@ -149,7 +149,7 @@
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/negotiator": "^0.6.4",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"algoliasearch": "5.47.0",
+2 -2
View File
@@ -42,7 +42,7 @@
"sync": "bun ./scripts/sync.ts"
},
"dependencies": {
"@clack/prompts": "^0.11.0",
"@clack/prompts": "^1.0.0",
"@commander-js/extra-typings": "^14.0.0",
"commander": "^14.0.2",
"picocolors": "^1.1.1",
@@ -51,7 +51,7 @@
},
"devDependencies": {
"@types/cross-spawn": "^6.0.6",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"eslint-config-custom": "workspace:*",
"tinyglobby": "^0.2.15",
"tsconfig": "workspace:*",
+1 -1
View File
@@ -51,7 +51,7 @@
"@types/estree": "^1.0.8",
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"eslint-config-custom": "workspace:*",
"fumadocs-core": "workspace:*",
"mdast-util-mdx-jsx": "^3.2.0",
+1 -1
View File
@@ -47,7 +47,7 @@
},
"devDependencies": {
"@types/mdx": "^2.0.13",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
"fumadocs-core": "workspace:*",
+1 -1
View File
@@ -91,7 +91,7 @@
"@types/js-yaml": "^4.0.9",
"@types/mdast": "^4.0.4",
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/picomatch": "^4.0.2",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
+1 -1
View File
@@ -61,7 +61,7 @@
"@types/estree": "^1.0.8",
"@types/js-yaml": "^4.0.9",
"@types/mdast": "^4.0.4",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-custom": "workspace:*",
+2 -2
View File
@@ -82,9 +82,9 @@
"xml-js": "^1.6.11"
},
"devDependencies": {
"@scalar/api-client-react": "^1.3.80",
"@scalar/api-client-react": "^1.3.82",
"@types/js-yaml": "^4.0.9",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/openapi-sampler": "^1.0.3",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
+1 -1
View File
@@ -57,7 +57,7 @@
},
"devDependencies": {
"@types/mdx": "^2.0.13",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-custom": "workspace:*",
+1 -1
View File
@@ -49,7 +49,7 @@
},
"devDependencies": {
"@types/js-yaml": "^4.0.9",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
"fumadocs-core": "workspace:*",
+1 -1
View File
@@ -123,7 +123,7 @@
"devDependencies": {
"@fumadocs/cli": "workspace:*",
"@tailwindcss/cli": "^4.1.18",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-custom": "workspace:*",
+1 -1
View File
@@ -26,7 +26,7 @@
"types:check": "tsc --noEmit"
},
"devDependencies": {
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
"tsconfig": "workspace:*",
+1 -1
View File
@@ -39,7 +39,7 @@
},
"devDependencies": {
"@fastify/deepmerge": "^3.2.0",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/ungap__structured-clone": "^1.2.0",
"@ungap/structured-clone": "^1.3.0",
+1 -1
View File
@@ -56,7 +56,7 @@
"devDependencies": {
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"eslint-config-custom": "workspace:*",
"fumadocs-ui": "workspace:*",
+1 -1
View File
@@ -53,7 +53,7 @@
"@types/estree": "^1.0.8",
"@types/hast": "^3.0.4",
"@types/mdast": "^4.0.4",
"@types/node": "25.0.10",
"@types/node": "25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"eslint-config-custom": "workspace:*",
+1 -1
View File
@@ -41,7 +41,7 @@
"@fumadocs/cli": "workspace:*",
"@types/bun": "^1.3.7",
"@types/lodash.merge": "^4.6.9",
"@types/node": "^25.0.10",
"@types/node": "^25.1.0",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"class-variance-authority": "^0.7.1",
+611 -526
View File
File diff suppressed because it is too large Load Diff