Просмотр исходного кода

refactor: simplify oxc eslint compatibility

xingyu4j 3 месяцев назад
Родитель
Сommit
913636ae44

+ 0 - 13
internal/lint-configs/eslint-config/src/configs/disableds.ts

@@ -1,13 +0,0 @@
-import type { Linter } from 'eslint';
-
-export async function disableds(): Promise<Linter.Config[]> {
-  return [
-    {
-      files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
-      name: 'disables/js',
-      rules: {
-        '@typescript-eslint/explicit-module-boundary-types': 'off',
-      },
-    },
-  ];
-}

+ 0 - 1
internal/lint-configs/eslint-config/src/configs/index.ts

@@ -1,6 +1,5 @@
 export * from './command';
 export * from './command';
 export * from './comments';
 export * from './comments';
-export * from './disableds';
 export * from './ignores';
 export * from './ignores';
 export * from './javascript';
 export * from './javascript';
 export * from './jsonc';
 export * from './jsonc';

+ 67 - 11
internal/lint-configs/eslint-config/src/configs/javascript.ts

@@ -4,7 +4,73 @@ import js from '@eslint/js';
 import pluginUnusedImports from 'eslint-plugin-unused-imports';
 import pluginUnusedImports from 'eslint-plugin-unused-imports';
 import globals from 'globals';
 import globals from 'globals';
 
 
+const rulesCoveredByOxlint = new Set([
+  'constructor-super',
+  'for-direction',
+  'getter-return',
+  'no-async-promise-executor',
+  'no-case-declarations',
+  'no-class-assign',
+  'no-compare-neg-zero',
+  'no-cond-assign',
+  'no-const-assign',
+  'no-constant-binary-expression',
+  'no-constant-condition',
+  'no-debugger',
+  'no-delete-var',
+  'no-dupe-args',
+  'no-dupe-class-members',
+  'no-dupe-else-if',
+  'no-dupe-keys',
+  'no-duplicate-case',
+  'no-empty',
+  'no-empty-character-class',
+  'no-empty-pattern',
+  'no-empty-static-block',
+  'no-ex-assign',
+  'no-extra-boolean-cast',
+  'no-fallthrough',
+  'no-func-assign',
+  'no-global-assign',
+  'no-import-assign',
+  'no-invalid-regexp',
+  'no-irregular-whitespace',
+  'no-loss-of-precision',
+  'no-misleading-character-class',
+  'no-new-native-nonconstructor',
+  'no-nonoctal-decimal-escape',
+  'no-obj-calls',
+  'no-prototype-builtins',
+  'no-redeclare',
+  'no-regex-spaces',
+  'no-self-assign',
+  'no-setter-return',
+  'no-shadow-restricted-names',
+  'no-sparse-arrays',
+  'no-this-before-super',
+  'no-unreachable',
+  'no-unsafe-finally',
+  'no-unsafe-negation',
+  'no-unsafe-optional-chaining',
+  'no-unused-labels',
+  'no-unused-private-class-members',
+  'no-unused-vars',
+  'no-useless-backreference',
+  'no-useless-catch',
+  'no-useless-escape',
+  'no-with',
+  'require-yield',
+  'use-isnan',
+  'valid-typeof',
+]);
+
 export async function javascript(): Promise<Linter.Config[]> {
 export async function javascript(): Promise<Linter.Config[]> {
+  const recommendedRules = Object.fromEntries(
+    Object.entries(js.configs.recommended.rules).filter(
+      ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+    ),
+  );
+
   return [
   return [
     {
     {
       languageOptions: {
       languageOptions: {
@@ -33,11 +99,10 @@ export async function javascript(): Promise<Linter.Config[]> {
         'unused-imports': pluginUnusedImports,
         'unused-imports': pluginUnusedImports,
       },
       },
       rules: {
       rules: {
-        ...js.configs.recommended.rules,
+        ...recommendedRules,
         'dot-notation': ['error', { allowKeywords: true }],
         'dot-notation': ['error', { allowKeywords: true }],
         'keyword-spacing': 'off',
         'keyword-spacing': 'off',
         'no-control-regex': 'error',
         'no-control-regex': 'error',
-        'no-dupe-args': 'error',
         'no-empty-function': 'off',
         'no-empty-function': 'off',
         'no-restricted-properties': [
         'no-restricted-properties': [
           'error',
           'error',
@@ -73,15 +138,6 @@ export async function javascript(): Promise<Linter.Config[]> {
         ],
         ],
         'no-undef': 'off',
         'no-undef': 'off',
         'no-unreachable-loop': 'error',
         'no-unreachable-loop': 'error',
-        'no-unused-vars': [
-          'error',
-          {
-            args: 'none',
-            caughtErrors: 'none',
-            ignoreRestSiblings: true,
-            vars: 'all',
-          },
-        ],
         'space-before-function-paren': 'off',
         'space-before-function-paren': 'off',
 
 
         'unused-imports/no-unused-imports': 'error',
         'unused-imports/no-unused-imports': 'error',

+ 14 - 1
internal/lint-configs/eslint-config/src/configs/typescript.ts

@@ -2,11 +2,24 @@ import type { Linter } from 'eslint';
 
 
 import { interopDefault } from '../util';
 import { interopDefault } from '../util';
 
 
+const rulesCoveredByOxlint = new Set([
+  '@typescript-eslint/ban-ts-comment',
+  '@typescript-eslint/no-non-null-assertion',
+  '@typescript-eslint/no-unused-expressions',
+  '@typescript-eslint/no-unused-vars',
+  '@typescript-eslint/triple-slash-reference',
+]);
+
 export async function typescript(): Promise<Linter.Config[]> {
 export async function typescript(): Promise<Linter.Config[]> {
   const [pluginTs, parserTs] = await Promise.all([
   const [pluginTs, parserTs] = await Promise.all([
     interopDefault(import('@typescript-eslint/eslint-plugin')),
     interopDefault(import('@typescript-eslint/eslint-plugin')),
     interopDefault(import('@typescript-eslint/parser')),
     interopDefault(import('@typescript-eslint/parser')),
   ] as const);
   ] as const);
+  const strictRules = Object.fromEntries(
+    Object.entries(pluginTs.configs.strict?.rules ?? {}).filter(
+      ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+    ),
+  );
 
 
   return [
   return [
     {
     {
@@ -30,7 +43,7 @@ export async function typescript(): Promise<Linter.Config[]> {
       },
       },
       rules: {
       rules: {
         ...pluginTs.configs['eslint-recommended']?.overrides?.[0]?.rules,
         ...pluginTs.configs['eslint-recommended']?.overrides?.[0]?.rules,
-        ...pluginTs.configs.strict?.rules,
+        ...strictRules,
         // '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
         // '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
         '@typescript-eslint/consistent-type-definitions': 'off',
         '@typescript-eslint/consistent-type-definitions': 'off',
         '@typescript-eslint/explicit-function-return-type': 'off',
         '@typescript-eslint/explicit-function-return-type': 'off',

+ 13 - 12
internal/lint-configs/eslint-config/src/configs/unicorn.ts

@@ -2,8 +2,20 @@ import type { Linter } from 'eslint';
 
 
 import { interopDefault } from '../util';
 import { interopDefault } from '../util';
 
 
+const rulesCoveredByOxlint = new Set([
+  'unicorn/consistent-function-scoping',
+  'unicorn/no-process-exit',
+  'unicorn/prefer-global-this',
+  'unicorn/prefer-module',
+]);
+
 export async function unicorn(): Promise<Linter.Config[]> {
 export async function unicorn(): Promise<Linter.Config[]> {
   const pluginUnicorn = await interopDefault(import('eslint-plugin-unicorn'));
   const pluginUnicorn = await interopDefault(import('eslint-plugin-unicorn'));
+  const recommendedRules = Object.fromEntries(
+    Object.entries(pluginUnicorn.configs.recommended.rules ?? {}).filter(
+      ([ruleName]) => !rulesCoveredByOxlint.has(ruleName),
+    ),
+  );
 
 
   return [
   return [
     {
     {
@@ -11,11 +23,10 @@ export async function unicorn(): Promise<Linter.Config[]> {
         unicorn: pluginUnicorn,
         unicorn: pluginUnicorn,
       },
       },
       rules: {
       rules: {
-        ...pluginUnicorn.configs.recommended.rules,
+        ...recommendedRules,
 
 
         'unicorn/better-regex': 'off',
         'unicorn/better-regex': 'off',
         'unicorn/consistent-destructuring': 'off',
         'unicorn/consistent-destructuring': 'off',
-        'unicorn/consistent-function-scoping': 'off',
         'unicorn/expiring-todo-comments': 'off',
         'unicorn/expiring-todo-comments': 'off',
         'unicorn/filename-case': 'off',
         'unicorn/filename-case': 'off',
         'unicorn/import-style': 'off',
         'unicorn/import-style': 'off',
@@ -25,19 +36,9 @@ export async function unicorn(): Promise<Linter.Config[]> {
         'unicorn/prefer-at': 'off',
         'unicorn/prefer-at': 'off',
         'unicorn/prefer-dom-node-text-content': 'off',
         'unicorn/prefer-dom-node-text-content': 'off',
         'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
         'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
-        'unicorn/prefer-global-this': 'off',
         'unicorn/prefer-top-level-await': 'off',
         'unicorn/prefer-top-level-await': 'off',
         'unicorn/prevent-abbreviations': 'off',
         'unicorn/prevent-abbreviations': 'off',
       },
       },
     },
     },
-    {
-      files: [
-        'scripts/**/*.?([cm])[jt]s?(x)',
-        'internal/**/*.?([cm])[jt]s?(x)',
-      ],
-      rules: {
-        'unicorn/no-process-exit': 'off',
-      },
-    },
   ];
   ];
 }
 }

+ 0 - 1
internal/lint-configs/eslint-config/src/configs/vue.ts

@@ -128,7 +128,6 @@ export async function vue(): Promise<Linter.Config[]> {
           },
           },
         ],
         ],
         'vue/one-component-per-file': 'error',
         'vue/one-component-per-file': 'error',
-        'vue/prefer-import-from-vue': 'error',
         'vue/prefer-separate-static-class': 'error',
         'vue/prefer-separate-static-class': 'error',
         'vue/prefer-template': 'error',
         'vue/prefer-template': 'error',
         'vue/prop-name-casing': ['error', 'camelCase'],
         'vue/prop-name-casing': ['error', 'camelCase'],

+ 0 - 11
internal/lint-configs/eslint-config/src/custom-config.ts

@@ -21,14 +21,6 @@ const customConfig: Linter.Config[] = [
     ignores: restrictedImportIgnores,
     ignores: restrictedImportIgnores,
     rules: {
     rules: {
       'perfectionist/sort-interfaces': 'off',
       'perfectionist/sort-interfaces': 'off',
-      'perfectionist/sort-objects': 'off',
-    },
-  },
-  {
-    files: ['**/**.vue'],
-    ignores: restrictedImportIgnores,
-    rules: {
-      'perfectionist/sort-objects': 'off',
     },
     },
   },
   },
   {
   {
@@ -63,7 +55,6 @@ const customConfig: Linter.Config[] = [
           ],
           ],
         },
         },
       ],
       ],
-      'perfectionist/sort-interfaces': 'off',
     },
     },
   },
   },
   {
   {
@@ -137,9 +128,7 @@ const customConfig: Linter.Config[] = [
   {
   {
     files: ['apps/backend-mock/**/**', 'docs/**/**'],
     files: ['apps/backend-mock/**/**', 'docs/**/**'],
     rules: {
     rules: {
-      '@typescript-eslint/no-extraneous-class': 'off',
       'no-console': 'off',
       'no-console': 'off',
-      'unicorn/prefer-module': 'off',
     },
     },
   },
   },
   {
   {

+ 0 - 2
internal/lint-configs/eslint-config/src/index.ts

@@ -3,7 +3,6 @@ import type { Linter } from 'eslint';
 import {
 import {
   command,
   command,
   comments,
   comments,
-  disableds,
   ignores,
   ignores,
   javascript,
   javascript,
   jsonc,
   jsonc,
@@ -34,7 +33,6 @@ async function defineConfig(config: FlatConfig[] = []) {
     ignores(),
     ignores(),
     typescript(),
     typescript(),
     jsonc(),
     jsonc(),
-    disableds(),
     node(),
     node(),
     perfectionist(),
     perfectionist(),
     comments(),
     comments(),

+ 10 - 9
packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue

@@ -35,12 +35,12 @@ const emit = defineEmits<{
 }>();
 }>();
 
 
 const PI: number = Math.PI;
 const PI: number = Math.PI;
-enum CanvasOpr {
-  // eslint-disable-next-line no-unused-vars
-  Clip = 'clip',
-  // eslint-disable-next-line no-unused-vars
-  Fill = 'fill',
-}
+const canvasOpr = {
+  clip: 'clip',
+  fill: 'fill',
+} as const;
+
+type CanvasOpr = (typeof canvasOpr)[keyof typeof canvasOpr];
 
 
 const modalValue = defineModel<boolean>({ default: false });
 const modalValue = defineModel<boolean>({ default: false });
 
 
@@ -189,8 +189,8 @@ function draw(ctx1: CanvasRenderingContext2D, ctx2: CanvasRenderingContext2D) {
     3 * circleRadius,
     3 * circleRadius,
     canvasHeight - (squareLength + 2 * circleRadius),
     canvasHeight - (squareLength + 2 * circleRadius),
   );
   );
-  drawPiece(ctx1, state.pieceX, state.pieceY, CanvasOpr.Fill);
-  drawPiece(ctx2, state.pieceX, state.pieceY, CanvasOpr.Clip);
+  drawPiece(ctx1, state.pieceX, state.pieceY, canvasOpr.fill);
+  drawPiece(ctx2, state.pieceX, state.pieceY, canvasOpr.clip);
 }
 }
 
 
 // 绘制拼图切块
 // 绘制拼图切块
@@ -233,7 +233,8 @@ function drawPiece(
   ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
   ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
   ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
   ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
   ctx.stroke();
   ctx.stroke();
-  opr === CanvasOpr.Clip ? ctx.clip() : ctx.fill();
+  // oxlint-disable-next-line no-unused-expressions
+  opr === canvasOpr.clip ? ctx.clip() : ctx.fill();
   ctx.globalCompositeOperation = 'destination-over';
   ctx.globalCompositeOperation = 'destination-over';
 }
 }
 
 

+ 4 - 4
packages/effects/common-ui/src/components/resize/resize.vue

@@ -997,16 +997,16 @@ const bodyDown = (ev: MouseEvent & TouchEvent) => {
     ev.preventDefault();
     ev.preventDefault();
   }
   }
 
 
-  if (isDraggable.value) {
-    bodyDrag.value = true;
-  }
-
   const pointerPosition = getPointerPosition(ev);
   const pointerPosition = getPointerPosition(ev);
 
 
   if (!pointerPosition) {
   if (!pointerPosition) {
     return;
     return;
   }
   }
 
 
+  if (isDraggable.value) {
+    bodyDrag.value = true;
+  }
+
   saveDimensionsBeforeMove(pointerPosition);
   saveDimensionsBeforeMove(pointerPosition);
 
 
   if (parentLimitation.value) {
   if (parentLimitation.value) {

+ 271 - 391
up-oxc.md

@@ -1,23 +1,25 @@
 # OXC 迁移计划
 # OXC 迁移计划
 
 
 > 本文档记录将项目中可替代的工具链逐步迁移到 [oxc](https://oxc.rs/) 生态的计划。
 > 本文档记录将项目中可替代的工具链逐步迁移到 [oxc](https://oxc.rs/) 生态的计划。
+>
+> 说明:本文档已按当前仓库状态校准。第一阶段已完成大部分工作,第二阶段的 formatter 迁移也已大部分落地。
 
 
 ## 当前现状
 ## 当前现状
 
 
-项目 ESLint 体系依赖约 20+ 个包,包括:
+当前仓库的 lint / format 体系已经从“纯 ESLint + Prettier”演进为 “oxlint + ESLint 共存,oxfmt 替换 Prettier”。
+
+当前与 lint / format 直接相关的核心依赖包括:
 
 
 - `eslint` ^10.0.3
 - `eslint` ^10.0.3
+- `oxlint` ^1.55.0
+- `oxfmt` ^0.40.0
+- `eslint-plugin-oxlint` ^1.55.0
 - `@typescript-eslint/parser` ^8.57.0
 - `@typescript-eslint/parser` ^8.57.0
 - `@typescript-eslint/eslint-plugin` ^8.57.0
 - `@typescript-eslint/eslint-plugin` ^8.57.0
 - `eslint-plugin-unicorn` ^63.0.0
 - `eslint-plugin-unicorn` ^63.0.0
-- `eslint-plugin-import-x` ^4.16.2
 - `eslint-plugin-unused-imports` ^4.4.1
 - `eslint-plugin-unused-imports` ^4.4.1
-- `eslint-plugin-regexp` ^3.1.0
-- `eslint-plugin-jsdoc` ^62.8.0
 - `eslint-plugin-n` ^17.24.0
 - `eslint-plugin-n` ^17.24.0
-- `eslint-plugin-no-only-tests` ^3.3.0
 - `eslint-plugin-perfectionist` ^5.6.0
 - `eslint-plugin-perfectionist` ^5.6.0
-- `eslint-plugin-prettier` ^5.5.5
 - `eslint-plugin-vue` ^10.8.0
 - `eslint-plugin-vue` ^10.8.0
 - `eslint-plugin-better-tailwindcss` ^4.3.2
 - `eslint-plugin-better-tailwindcss` ^4.3.2
 - `eslint-plugin-jsonc` ^3.1.2
 - `eslint-plugin-jsonc` ^3.1.2
@@ -25,19 +27,28 @@
 - `eslint-plugin-command` ^3.5.2
 - `eslint-plugin-command` ^3.5.2
 - `eslint-plugin-pnpm` ^1.6.0
 - `eslint-plugin-pnpm` ^1.6.0
 - `@eslint-community/eslint-plugin-eslint-comments` ^4.7.1
 - `@eslint-community/eslint-plugin-eslint-comments` ^4.7.1
-- `@vitest/eslint-plugin` ^1.6.11
 - `vue-eslint-parser` ^10.4.0
 - `vue-eslint-parser` ^10.4.0
 - `yaml-eslint-parser` ^2.0.0
 - `yaml-eslint-parser` ^2.0.0
 - `globals` ^17.4.0
 - `globals` ^17.4.0
-- `prettier` ^3.8.1
 - `esbuild` ^0.27.4
 - `esbuild` ^0.27.4
 - `html-minifier-terser` ^7.2.0
 - `html-minifier-terser` ^7.2.0
 
 
+以下依赖已不再存在于当前仓库的 lint / format 链路中:
+
+- `eslint-plugin-import-x`
+- `eslint-plugin-regexp`
+- `eslint-plugin-jsdoc`
+- `eslint-plugin-no-only-tests`
+- `@vitest/eslint-plugin`
+- `eslint-plugin-prettier`
+- `stylelint-prettier`
+- `prettier`
+
 ---
 ---
 
 
 ## 第一阶段:引入 oxlint,与 ESLint 共存
 ## 第一阶段:引入 oxlint,与 ESLint 共存
 
 
-**目标**:将通用 JS/TS lint 规则交给 oxlint,ESLint 仅保留 oxlint 无法覆盖的特殊规则,大幅减少依赖数量并提升 lint 速度。
+**目标**:将通用 JS/TS lint 规则交给 oxlint,ESLint 仅保留 oxlint 无法覆盖的特殊规则,减少依赖数量并提升 lint 速度。
 
 
 ### 1.1 安装 oxlint
 ### 1.1 安装 oxlint
 
 
@@ -45,42 +56,46 @@
 pnpm add -Dw oxlint
 pnpm add -Dw oxlint
 ```
 ```
 
 
-### 1.2 移除的 ESLint 插件
+### 1.2 已迁出或已移除的 ESLint 插件
 
 
-以下插件与规则在 oxlint 中已有对应能力,但“有能力承接”不等于“现在就能删依赖”。这里区分为“已移除 / 已迁出 ESLint”和“仍需保留”两类
+以下插件与规则已经完成迁移,或者已从当前仓库移除
 
 
 | 插件 | 当前状态 | 说明 |
 | 插件 | 当前状态 | 说明 |
 | --- | --- | --- |
 | --- | --- | --- |
 | `eslint-plugin-regexp` | 已移除 | 由 oxlint 内建能力承接 |
 | `eslint-plugin-regexp` | 已移除 | 由 oxlint 内建能力承接 |
 | `eslint-plugin-jsdoc` | 已移除 | 由 oxlint 内建能力承接 |
 | `eslint-plugin-jsdoc` | 已移除 | 由 oxlint 内建能力承接 |
-| `eslint-plugin-no-only-tests` | 已移除 | 测试规则已迁到 oxlint / vitest |
-| `eslint-plugin-better-tailwindcss` | 已迁出 ESLint | 仍然保留依赖,但已通过 oxlint `jsPlugins` 运行 |
+| `eslint-plugin-no-only-tests` | 已移除 | 测试规则已迁到 oxlint / vitest 分类 |
+| `eslint-plugin-import-x` | 已移除 | `import` 规则已集中迁入 `@vben/oxlint-config` |
+| `@vitest/eslint-plugin` | 已移除 | Vitest 规则已迁入 `@vben/oxlint-config` |
+| `eslint-plugin-prettier` | 已移除 | formatter 已切换到 oxfmt |
+| `eslint-plugin-better-tailwindcss` | 已迁出 ESLint | 仍保留依赖,但已通过 oxlint `jsPlugins` 运行 |
 | `@typescript-eslint/eslint-plugin` | 仍需保留 | 还有一批 TS 规则未迁移 |
 | `@typescript-eslint/eslint-plugin` | 仍需保留 | 还有一批 TS 规则未迁移 |
 | `@typescript-eslint/parser` | 仍需保留 | ESLint 侧 TS / Vue 规则仍依赖它 |
 | `@typescript-eslint/parser` | 仍需保留 | ESLint 侧 TS / Vue 规则仍依赖它 |
 | `eslint-plugin-unicorn` | 仍需保留 | ESLint 侧仍使用其 recommended 规则补充 |
 | `eslint-plugin-unicorn` | 仍需保留 | ESLint 侧仍使用其 recommended 规则补充 |
-| `eslint-plugin-import-x` | 仍需保留 | `import/newline-after-import`、`import/no-webpack-loader-syntax` 尚未迁移 |
 | `eslint-plugin-unused-imports` | 仍需保留 | `no-unused-imports` 仍由 ESLint 负责 |
 | `eslint-plugin-unused-imports` | 仍需保留 | `no-unused-imports` 仍由 ESLint 负责 |
 | `eslint-plugin-n` | 仍需保留 | 多条 Node 规则在 oxlint 中暂无等价承接 |
 | `eslint-plugin-n` | 仍需保留 | 多条 Node 规则在 oxlint 中暂无等价承接 |
 | `eslint-plugin-perfectionist` | 仍需保留 | 排序规则策略不同,不建议强迁 |
 | `eslint-plugin-perfectionist` | 仍需保留 | 排序规则策略不同,不建议强迁 |
 | `@eslint-community/eslint-plugin-eslint-comments` | 仍需保留 | 当前尚未迁移 |
 | `@eslint-community/eslint-plugin-eslint-comments` | 仍需保留 | 当前尚未迁移 |
 
 
-### 1.3 必须保留的 ESLint 插件
+### 1.3 当前仍需保留在 ESLint 侧的插件 / 能力
 
 
-以下插件 oxlint 目前不支持或不完全支持,需继续由 ESLint 处理:
+以下插件或能力当前仍需继续由 ESLint 处理:
 
 
-| 插件 | 原因 |
+| 插件 / 能力 | 原因 |
 | --- | --- |
 | --- | --- |
-| `eslint-plugin-vue` + `vue-eslint-parser` | Vue SFC 模板 lint,oxlint Vue 支持尚未完善 |
-| `eslint-plugin-jsonc` + `eslint-plugin-yml` | JSON/YAML 文件 lint,oxlint 不支持 |
+| `eslint-plugin-vue` + `vue-eslint-parser` | Vue SFC template lint,oxlint Vue 支持尚未完善 |
+| `@typescript-eslint/eslint-plugin` + `@typescript-eslint/parser` | 仍有一批 TS strict / type-aware 规则保留在 ESLint 侧 |
+| `eslint-plugin-unused-imports` | `no-unused-imports` 仍由 ESLint 负责 |
+| `eslint-plugin-n` | 多条 Node 规则尚无等价承接 |
+| `eslint-plugin-perfectionist` | 当前仍负责排序策略 |
+| `eslint-plugin-jsonc` + `eslint-plugin-yml` + `yaml-eslint-parser` | JSON / YAML 文件 lint 仍在 ESLint 侧 |
 | `eslint-plugin-pnpm` | pnpm workspace 规则,oxlint 无对应 |
 | `eslint-plugin-pnpm` | pnpm workspace 规则,oxlint 无对应 |
 | `eslint-plugin-command` | 魔法注释命令,oxlint 无对应 |
 | `eslint-plugin-command` | 魔法注释命令,oxlint 无对应 |
-| `@vitest/eslint-plugin` | Vitest 特定规则(oxlint vitest 分类可能部分覆盖,需验证) |
-| `yaml-eslint-parser` | YAML 解析,配合 eslint-plugin-yml 使用 |
-| `eslint-plugin-prettier` | Prettier 集成(第二阶段替换 Prettier 后可移除) |
+| `@eslint-community/eslint-plugin-eslint-comments` | 当前尚未迁移 |
 
 
 ### 1.4 配置 oxlint
 ### 1.4 配置 oxlint
 
 
-当前实现已调整为与 ESLint 一致的 workspace 包组织方式:
+当前实现已调整为与 ESLint 一致的 workspace 包组织方式:
 
 
 - 根目录使用 [oxlint.config.ts](./oxlint.config.ts) 作为薄入口
 - 根目录使用 [oxlint.config.ts](./oxlint.config.ts) 作为薄入口
 - 实际规则配置位于 `internal/lint-configs/oxlint-config`
 - 实际规则配置位于 `internal/lint-configs/oxlint-config`
@@ -112,30 +127,35 @@ export function defineConfig(config = {}) {
 
 
 ### 1.5 当前已完成项
 ### 1.5 当前已完成项
 
 
-截至目前,第一阶段已完成以下工作:
-
-1. 根 `lint` 已调整为先跑 `oxlint` 再跑 `vsh lint`
-2. `lefthook` 已接入 `oxlint --fix`
-3. 已新增 `@vben/oxlint-config`,并将 oxlint 规则集中到 `internal/lint-configs/oxlint-config`
-4. `eslint-plugin-oxlint` 已接入 `@vben/eslint-config`
-5. 已移除 `eslint-plugin-jsdoc`、`eslint-plugin-regexp`、`eslint-plugin-no-only-tests`
-6. `better-tailwindcss` 已迁移到 `@vben/oxlint-config` 的 `jsPlugins` 方案
-7. `unicorn` 插件已在 oxlint 侧显式启用,并补齐仓库内所需的 override
-8. 当前 `pnpm run lint:oxc`、`pnpm run lint:eslint`、`pnpm run lint` 均可通过
+截至当前仓库状态,第一阶段与其配套的 formatter 迁移已完成以下工作:
+
+1. 根 `lint` 已统一委托给 `vsh lint`
+2. 保留 `lint:oxc`、`lint:oxc:type-aware`、`lint:eslint`、`lint:style` 作为独立入口
+3. `lefthook` 已接入 `oxfmt`、`oxlint --fix`、`eslint --cache --fix`、`stylelint --fix`
+4. 已新增 `@vben/oxlint-config`,并将 oxlint 规则集中到 `internal/lint-configs/oxlint-config`
+5. 已新增 `@vben/oxfmt-config`,并使用根级 `oxfmt.config.ts` 作为格式化配置入口
+6. `eslint-plugin-oxlint` 已接入 `@vben/eslint-config`
+7. 已移除 `eslint-plugin-jsdoc`、`eslint-plugin-regexp`、`eslint-plugin-no-only-tests`
+8. `import` 与 `vitest` 规则已迁入 oxlint,相关 ESLint 插件已移除
+9. `better-tailwindcss` 已迁移到 `@vben/oxlint-config` 的 `jsPlugins` 方案
+10. `unicorn` 插件已在 oxlint 侧显式启用,并补齐仓库内所需的 override
+11. Prettier 相关根配置与 ESLint / Stylelint 集成已移除
+12. `internal/node-utils` 已改为调用 `oxfmt`
 
 
 ### 1.6 当前 oxlint 基线策略
 ### 1.6 当前 oxlint 基线策略
 
 
 当前 `@vben/oxlint-config` 采用“先收敛噪音,再逐步接管规则”的策略:
 当前 `@vben/oxlint-config` 采用“先收敛噪音,再逐步接管规则”的策略:
 
 
-- 启用 `correctness` 和 `suspicious`
-- 保留 `import`、`node`、`typescript`、`unicorn`、`vitest`、`vue` 插件
+- 启用 `correctness` 和 `suspicious`
+- 显式启用 `import`、`node`、`oxc`、`typescript`、`unicorn`、`vitest`、`vue` 插件
 - 通过 `jsPlugins` 在 oxlint 侧承接 `better-tailwindcss`
 - 通过 `jsPlugins` 在 oxlint 侧承接 `better-tailwindcss`
 - 对当前仓库内高噪音且不准备立即批量整改的规则先显式关闭
 - 对当前仓库内高噪音且不准备立即批量整改的规则先显式关闭
-- 通过 `overrides` 为 `.d.ts` 等特殊文件保留例外配置
+- 通过 `overrides` 为 `.d.ts`、测试文件、脚本目录等特殊场景保留例外配置
+- `overrides.files` 已避免继续使用 ESLint 风格的 extglob,改为显式文件后缀列表
 
 
-### 1.7 已确认可迁移到 oxlint 的规则
+### 1.7 当前已迁入 oxlint 的规则
 
 
-以下规则已确认可由当前版本 `oxlint` 接管,后续应从 `@vben/eslint-config` 逐步迁移到 `@vben/oxlint-config`
+以下规则已在当前仓库的 `@vben/oxlint-config` 中落地
 
 
 #### JavaScript / core
 #### JavaScript / core
 
 
@@ -144,17 +164,14 @@ export function defineConfig(config = {}) {
 - `no-array-constructor`
 - `no-array-constructor`
 - `no-caller`
 - `no-caller`
 - `no-case-declarations`
 - `no-case-declarations`
-- `no-control-regex`
 - `no-debugger`
 - `no-debugger`
-- `no-empty-function`
 - `no-eval`
 - `no-eval`
 - `no-iterator`
 - `no-iterator`
 - `no-new-wrappers`
 - `no-new-wrappers`
-- `no-shadow`
 - `no-shadow-restricted-names`
 - `no-shadow-restricted-names`
 - `no-unused-expressions`
 - `no-unused-expressions`
-- `no-unused-vars`
 - `prefer-const`
 - `prefer-const`
+- 以及一批额外的 core 规则,例如 `no-console`、`no-template-curly-in-string`、`prefer-template`、`object-shorthand`
 
 
 #### import
 #### import
 
 
@@ -164,43 +181,42 @@ export function defineConfig(config = {}) {
 - `import/no-mutable-exports`
 - `import/no-mutable-exports`
 - `import/no-named-default`
 - `import/no-named-default`
 - `import/no-self-import`
 - `import/no-self-import`
+- `import/no-webpack-loader-syntax`
 
 
 #### TypeScript
 #### TypeScript
 
 
-- `@typescript-eslint/no-non-null-assertion`
-- `@typescript-eslint/no-empty-function`
-- `@typescript-eslint/no-shadow`
-- `@typescript-eslint/no-unused-expressions`
-- `@typescript-eslint/no-unused-vars`
-- `@typescript-eslint/no-var-requires`
+- `typescript/ban-ts-comment`
+- `typescript/no-non-null-assertion`
+- `typescript/no-var-requires`
+- `typescript/triple-slash-reference`
 
 
-> `@typescript-eslint/ban-ts-comment` 虽然 oxlint 已支持,但当前仓库中存在多处 `@ts-ignore`,直接迁移会新增报错,暂不建议在这一阶段接管。
+> 当前仓库已开始为 type-aware 规则预留位置,但 `no-floating-promises`、`await-thenable` 等高噪音规则仍显式关闭,等待后续逐步接管。
 
 
 #### Vitest
 #### Vitest
 
 
+- `vitest/consistent-test-it`
 - `vitest/no-focused-tests`
 - `vitest/no-focused-tests`
 - `vitest/no-identical-title`
 - `vitest/no-identical-title`
+- `vitest/no-import-node-test`
 - `vitest/prefer-hooks-in-order`
 - `vitest/prefer-hooks-in-order`
 - `vitest/prefer-lowercase-title`
 - `vitest/prefer-lowercase-title`
 
 
 #### Node
 #### Node
 
 
-- `n/no-exports-assign`
-- `n/no-new-require`
-- `n/no-path-concat`
+- `node/no-exports-assign`
+- `node/no-new-require`
+- `node/no-path-concat`
 
 
 #### Unicorn
 #### Unicorn
 
 
-- `unicorn/consistent-function-scoping`
 - `unicorn/no-process-exit`
 - `unicorn/no-process-exit`
-- `unicorn/prefer-global-this`
 - `unicorn/prefer-module`
 - `unicorn/prefer-module`
 
 
 #### Tailwind CSS
 #### Tailwind CSS
 
 
 - `better-tailwindcss/enforce-consistent-class-order`
 - `better-tailwindcss/enforce-consistent-class-order`
-- `better-tailwindcss/enforce-consistent-line-wrapping`
-- `better-tailwindcss/no-unknown-classes`
+
+> `better-tailwindcss/enforce-consistent-line-wrapping` 与 `better-tailwindcss/no-unknown-classes` 当前仍因噪音 / 与 formatter 冲突而关闭。
 
 
 #### Vue
 #### Vue
 
 
@@ -210,14 +226,15 @@ export function defineConfig(config = {}) {
 
 
 以下内容当前不建议从 ESLint 侧移除:
 以下内容当前不建议从 ESLint 侧移除:
 
 
-1. Vue SFC/template 主体规则
+1. Vue SFC / template 主体规则
 2. `perfectionist`
 2. `perfectionist`
 3. `jsonc` / `yml`
 3. `jsonc` / `yml`
 4. `pnpm`
 4. `pnpm`
 5. `command`
 5. `command`
-6. `prettier`
-7. `eslint-comments`
-8. `unused-imports`
+6. `eslint-comments`
+7. `unused-imports`
+8. `node.ts` 中尚未被 oxlint 覆盖的规则
+9. `typescript.ts` 中暂不适合直接迁移的 strict / type-aware 规则
 
 
 其中 Vue 相关规则尤其需要保留,至少包括:
 其中 Vue 相关规则尤其需要保留,至少包括:
 
 
@@ -236,15 +253,14 @@ export function defineConfig(config = {}) {
 
 
 ### 1.9 推荐的下一步执行顺序
 ### 1.9 推荐的下一步执行顺序
 
 
-为降低回归风险,后续规则迁移建议按以下顺序推进:
+为降低回归风险,建议按当前真实代码结构推进:
 
 
-1. `import.ts`
-2. `javascript.ts` 中剩余的低风险 1:1 规则
-3. `typescript.ts`
-4. `node.ts`
-5. `test.ts`
-6. 最后再评估 `import.ts` 中剩余规则是否值得继续下沉
-7. 最后处理 `vue.ts` 中的个别确认项
+1. 验证 `oxcCompat()` 是否正确关闭 ESLint 重复规则
+2. 继续清理 `eslint-config/src/configs/javascript.ts` 中已被 oxlint 明确覆盖的低风险规则
+3. 继续从 `eslint-config/src/configs/typescript.ts` 向 `@vben/oxlint-config` 下沉规则,并结合 `lint:oxc:type-aware` 逐步启用 type-aware 规则
+4. 评估 `eslint-config/src/configs/unicorn.ts` 中剩余规则是否值得继续保留
+5. 保留并持续观察 `eslint-config/src/configs/node.ts`、`vue.ts`、`perfectionist.ts`、`jsonc.ts`、`yaml.ts`、`pnpm.ts`、`command.ts`
+6. 最后再评估是否要重新启用 tailwind 的 wrapping / unknown classes 规则
 
 
 每迁移一组后都执行:
 每迁移一组后都执行:
 
 
@@ -254,67 +270,75 @@ pnpm run lint:eslint
 pnpm run lint
 pnpm run lint
 ```
 ```
 
 
-### 1.10 更新 scripts
+### 1.10 当前 scripts
 
 
 ```jsonc
 ```jsonc
 // package.json
 // package.json
 {
 {
   "scripts": {
   "scripts": {
-    "lint": "pnpm run lint:oxc && pnpm run lint:eslint",
+    "format": "vsh lint --format",
+    "lint": "vsh lint",
     "lint:oxc": "oxlint .",
     "lint:oxc": "oxlint .",
-    "lint:eslint": "vsh lint",
+    "lint:oxc:type-aware": "oxlint . --type-aware",
+    "lint:eslint": "eslint . --cache",
+    "lint:style": "stylelint \"**/*.{vue,css,less,scss}\" --cache",
   },
   },
 }
 }
 ```
 ```
 
 
-### 1.11 更新 lefthook
+### 1.11 当前 lefthook
 
 
-在 pre-commit 中将 oxlint 加入暂存文件检查
+当前 `pre-commit` 已包含如下链路
 
 
 ```yaml
 ```yaml
 pre-commit:
 pre-commit:
+  parallel: true
   commands:
   commands:
+    code-workspace:
+      run: pnpm vsh code-workspace --auto-commit
+    lint-md:
+      run: pnpm oxfmt {staged_files}
+      glob: '*.md'
     lint-vue:
     lint-vue:
+      run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files}
       glob: '*.vue'
       glob: '*.vue'
-      run: pnpm prettier --write {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files}
     lint-js:
     lint-js:
+      run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files}
       glob: '*.{js,jsx,ts,tsx}'
       glob: '*.{js,jsx,ts,tsx}'
-      run: pnpm prettier --cache --ignore-unknown --write {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files}
+    lint-style:
+      run: pnpm oxfmt {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files}
+      glob: '*.{scss,less,styl,html,vue,css}'
+    lint-package:
+      run: pnpm oxfmt {staged_files}
+      glob: 'package.json'
+    lint-json:
+      run: pnpm oxfmt {staged_files}
+      glob: '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}'
 ```
 ```
 
 
 ### 1.12 验证步骤
 ### 1.12 验证步骤
 
 
-1. 安装 oxlint 后全量运行 `pnpm lint:oxc`,记录所有报告
+1. 全量运行 `pnpm run lint:oxc`,记录 oxlint 报告
 2. 对比当前 ESLint 规则覆盖情况,调整 oxlint 配置使两者对齐
 2. 对比当前 ESLint 规则覆盖情况,调整 oxlint 配置使两者对齐
-3. 逐个移除可替代的 ESLint 插件,每次移除后运行完整 lint 验证无遗漏
+3. 逐个移除可替代的 ESLint 插件或规则组,每次移除后运行完整 lint 验证
 4. CI 中同时运行 oxlint 和 ESLint,确保双重覆盖期间无回归
 4. CI 中同时运行 oxlint 和 ESLint,确保双重覆盖期间无回归
 
 
 ### 1.13 待修复问题与改进项
 ### 1.13 待修复问题与改进项
 
 
-> 以下问题通过代码审查发现,按优先级排列
+> 以下问题按当前仓库状态重新整理
 
 
 #### [高] `unicorn` 插件启用后要同时收敛默认规则与 override
 #### [高] `unicorn` 插件启用后要同时收敛默认规则与 override
 
 
-这个问题已经修复,但需要记录经验:
+这个问题已经修复,但需要保留经验:
 
 
 - `plugins` 一旦显式声明,必须手动包含 `unicorn`
 - `plugins` 一旦显式声明,必须手动包含 `unicorn`
 - 启用后不只会打开我们手写的 `unicorn/no-process-exit`、`unicorn/prefer-module`
 - 启用后不只会打开我们手写的 `unicorn/no-process-exit`、`unicorn/prefer-module`
 - 还会带出 oxlint 默认启用的一部分 `unicorn` 规则,需要按仓库现状显式关闭噪音项
 - 还会带出 oxlint 默认启用的一部分 `unicorn` 规则,需要按仓库现状显式关闭噪音项
-- OXC `overrides.files` 不要继续使用 `?([cm])[jt]s?(x)` 这类 ESLint 风格的 extglob,当前仓库已改为显式文件后缀列表
+- OXC `overrides.files` 不要继续使用 `?([cm])[jt]s?(x)` 这类 ESLint 风格的 extglob
 
 
 #### [高] 使用 `@oxlint/migrate` 仅做审计,不直接落地配置
 #### [高] 使用 `@oxlint/migrate` 仅做审计,不直接落地配置
 
 
-官方提供了 [`@oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate) 工具,可自动读取 ESLint flat config 生成对应 oxlint 配置:
-
-也可以参考 [`oxlint-migration-inspector`](https://github.com/joris-gallot/oxlint-migration-inspector) `npx oxlint-migration-inspector` 命令,查看哪些规则无法迁移。
-
-```bash
-# 查看哪些规则无法迁移
-npx @oxlint/migrate --details
-
-# 与已有配置合并(而非覆盖)
-npx @oxlint/migrate --merge
-```
+官方提供了 [`@oxlint/migrate`](https://github.com/oxc-project/oxlint-migrate) 工具,可自动读取 ESLint flat config 生成对应 oxlint 配置。
 
 
 对于当前仓库,`@oxlint/migrate` 更适合做“审计工具”,不适合直接生成或合并为最终配置,原因是:
 对于当前仓库,`@oxlint/migrate` 更适合做“审计工具”,不适合直接生成或合并为最终配置,原因是:
 
 
@@ -323,10 +347,9 @@ npx @oxlint/migrate --merge
 3. Tailwind 规则依赖手写 `jsPlugins` 和 `settings`
 3. Tailwind 规则依赖手写 `jsPlugins` 和 `settings`
 4. 现有迁移流程还包含 ESLint 兼容层 `eslint-plugin-oxlint`
 4. 现有迁移流程还包含 ESLint 兼容层 `eslint-plugin-oxlint`
 
 
-因此更合理的用法是:
+更合理的用法是:
 
 
 ```bash
 ```bash
-# 只做对账,不直接采纳输出
 npx @oxlint/migrate --details
 npx @oxlint/migrate --details
 ```
 ```
 
 
@@ -334,53 +357,43 @@ npx @oxlint/migrate --details
 
 
 #### [中] `mergeOxlintConfigs` 函数重复定义
 #### [中] `mergeOxlintConfigs` 函数重复定义
 
 
-`mergeOxlintConfigs` 在两处有几乎相同的实现:
-
-- `oxlint-config/src/configs/index.ts` — 包含 `jsPlugins` 合并逻辑
-- `eslint-config/src/configs/oxlint.ts` — 缺少 `jsPlugins` 合并逻辑
-
-这个问题已经修复。ESLint 侧的 `oxlint.ts` 已直接导入 `@vben/oxlint-config` 的 `mergeOxlintConfigs`,避免实现不一致:
+这个问题已经修复。ESLint 侧的 `oxlint.ts` 已直接导入 `@vben/oxlint-config` 的 `mergeOxlintConfigs`,并在传入 `buildFromOxlintConfig()` 前剥离 `extends`:
 
 
 ```ts
 ```ts
-// eslint-config/src/configs/oxlint.ts
 import { mergeOxlintConfigs, oxlintConfig } from '@vben/oxlint-config';
 import { mergeOxlintConfigs, oxlintConfig } from '@vben/oxlint-config';
 import oxlint from 'eslint-plugin-oxlint';
 import oxlint from 'eslint-plugin-oxlint';
 
 
 export async function oxcCompat(): Promise<Linter.Config[]> {
 export async function oxcCompat(): Promise<Linter.Config[]> {
-  return oxlint.buildFromOxlintConfig(mergeOxlintConfigs(oxlintConfig));
+  const { extends: _extends, ...config } = mergeOxlintConfigs(oxlintConfig);
+
+  return oxlint.buildFromOxlintConfig(
+    config as Parameters<typeof oxlint.buildFromOxlintConfig>[0],
+  );
 }
 }
 ```
 ```
 
 
 #### [中] 验证 `oxcCompat()` 是否正确关闭 ESLint 重复规则
 #### [中] 验证 `oxcCompat()` 是否正确关闭 ESLint 重复规则
 
 
-ESLint 侧 `javascript.ts` 约有 **70+ 条规则**,很多已被 oxlint 的 `correctness`/`suspicious` category 覆盖(如 `no-debugger`、`no-dupe-keys`、`no-unreachable` 等),但 ESLint 侧并未手动关闭
+ESLint 侧 `javascript.ts` 仍有较多规则,而其中很多已被 oxlint 的 `correctness` / `suspicious` category 覆盖
 
 
-`eslint-plugin-oxlint` 的 `buildFromOxlintConfig()` 理论上会自动关闭 ESLint 中被 oxlint 覆盖的规则。需要验证 `oxcCompat()` 确实生效——如果正常工作,则 ESLint 侧无需手动清理这些规则。
+`eslint-plugin-oxlint` 的 `buildFromOxlintConfig()` 理论上会自动关闭 ESLint 中被 oxlint 覆盖的规则。仍需验证 `oxcCompat()` 确实生效。如果正常工作,则 ESLint 侧无需手动清理这批重复规则。
 
 
-**验证方法**
+建议验证方法
 
 
 ```bash
 ```bash
-# 临时在 oxlint 中 warn 一个 ESLint 也有的规则(如 no-debugger)
-# 确认 ESLint 不再报告该规则
+# 临时在 oxlint 中启用一个 ESLint 也有的规则(如 no-debugger)
+# 确认 ESLint 不再重复报告该规则
 ```
 ```
 
 
-#### [中] `eslint-plugin-import-x` 迁移不完全
-
-ESLint 侧 `import.ts` 仍保留 3 条规则:
-
-| 规则                              | 状态                              |
-| --------------------------------- | --------------------------------- |
-| `import/newline-after-import`     | 未迁移到 oxlint,需检查是否已支持 |
-| `import/no-unresolved`            | 已 off,无需处理                  |
-| `import/no-webpack-loader-syntax` | 未迁移到 oxlint,需检查是否已支持 |
+#### [中] `eslint-plugin-import-x` 已从当前仓库移除
 
 
-如果这两条规则被 oxlint 支持,则 `eslint-plugin-import-x` 可从 ESLint 依赖中完全移除
+`eslint-plugin-import-x` 相关迁移已经落地,当前仓库不再保留该依赖,`import` 规则集中定义在 `internal/lint-configs/oxlint-config/src/configs/import.ts`。
 
 
-#### [中] `eslint-plugin-n` 实际不能完全移除
+当前未再单独保留 `import/newline-after-import`。如未来仍需这类纯风格规则,应单独评估是否值得重新引入。
 
 
-1.2 表格中标记 `eslint-plugin-n` 为"可移除",但 ESLint 侧 `node.ts` 仍有以下规则未被 oxlint 接管:
+#### [中] `eslint-plugin-n` 仍不能完全移除
 
 
-可参考 https://github.com/oxc-project/oxc/issues/481 查看 Tasks 列表,oxlint 正在逐步接管 ESLint 的规则。
+当前 ESLint 侧 `node.ts` 仍保留以下规则,尚未被 oxlint 接管:
 
 
 | 规则 | 备注 |
 | 规则 | 备注 |
 | --- | --- |
 | --- | --- |
@@ -392,17 +405,25 @@ ESLint 侧 `import.ts` 仍保留 3 条规则:
 | `n/prefer-global/process` | oxlint 未支持 |
 | `n/prefer-global/process` | oxlint 未支持 |
 | `n/process-exit-as-throw` | oxlint 未支持 |
 | `n/process-exit-as-throw` | oxlint 未支持 |
 
 
-**结论**:`eslint-plugin-n` 当前仍需保留在 ESLint 侧,1.2 表格需修正
+**结论**:`eslint-plugin-n` 当前仍需保留在 ESLint 侧。
 
 
-#### [低] 考虑启用 `--type-aware` 规则
+#### [低] 已增加 `lint:oxc:type-aware` 入口,后续逐步启用规则
 
 
-ESLint 侧 `typescript.ts` 已配置 `project: './tsconfig.*.json'`,即已使用 type-aware linting。oxlint 也支持 `--type-aware` 选项,启用后可迁移更多依赖类型信息的规则(如 `@typescript-eslint/no-floating-promises` 等),进一步减少对 ESLint TypeScript 插件的依赖。
+当前根 `package.json` 已提供:
 
 
 ```bash
 ```bash
-# 测试 type-aware 模式
-oxlint --type-aware --tsconfig tsconfig.json
+pnpm run lint:oxc:type-aware
 ```
 ```
 
 
+当前 `@vben/oxlint-config` 已显式保留一批关闭状态的 type-aware 规则,例如:
+
+- `typescript/no-floating-promises`
+- `typescript/await-thenable`
+- `typescript/no-base-to-string`
+- `typescript/no-unnecessary-type-assertion`
+
+后续建议基于实际报告量逐条开启,而不是一次性打开全部 type-aware 规则。
+
 #### [低] `--replace-eslint-comments` 批量转换注释
 #### [低] `--replace-eslint-comments` 批量转换注释
 
 
 代码中存在的 `// eslint-disable` 注释虽然 oxlint 兼容,但在第四阶段移除 ESLint 后会变得语义不清。官方迁移工具提供了批量转换选项:
 代码中存在的 `// eslint-disable` 注释虽然 oxlint 兼容,但在第四阶段移除 ESLint 后会变得语义不清。官方迁移工具提供了批量转换选项:
@@ -413,9 +434,9 @@ npx @oxlint/migrate --replace-eslint-comments
 
 
 建议在第一阶段完成后或第四阶段开始前执行。
 建议在第一阶段完成后或第四阶段开始前执行。
 
 
-#### [低] `jsPlugins` 特性可减少 ESLint 依赖
+#### [低] `jsPlugins` 已在仓库中使用,后续可继续减少 ESLint 依赖
 
 
-oxlint 支持通过 `jsPlugins` 字段加载外部 ESLint 插件。对于 `eslint-plugin-pnpm`、`eslint-plugin-command` 等 oxlint 不内置的插件,未来可评估通过 `jsPlugins` 在 oxlint 中直接加载,从而减少对 ESLint 的依赖:
+当前仓库已经通过 `jsPlugins` 在 oxlint 侧接入 `eslint-plugin-better-tailwindcss`。对于 `eslint-plugin-pnpm`、`eslint-plugin-command` 等 oxlint 不内置的插件,未来仍可评估采用同样方式进一步减少对 ESLint 的依赖:
 
 
 ```json
 ```json
 {
 {
@@ -428,141 +449,114 @@ oxlint 支持通过 `jsPlugins` 字段加载外部 ESLint 插件。对于 `eslin
 
 
 ---
 ---
 
 
-## 第二阶段:oxfmt 替换 Prettier
+## 第二阶段:oxfmt 替换 Prettier(大部分已完成)
 
 
-**前提**:oxfmt 已发布,支持 JS/TS/Vue SFC 格式化,CSS/HTML/YAML/Markdown 等通过内部委托 Prettier 处理
+**当前状态**:第二阶段的大部分工作已经落地,下面记录的是“当前仓库真实状态”和仍需继续验证的事项,而不是最初的待办清单
 
 
 > 参考文档:[oxfmt CLI](https://oxc.rs/docs/guide/usage/formatter/cli.html) | [Config Reference](https://oxc.rs/docs/guide/usage/formatter/config-file-reference.html)
 > 参考文档:[oxfmt CLI](https://oxc.rs/docs/guide/usage/formatter/cli.html) | [Config Reference](https://oxc.rs/docs/guide/usage/formatter/config-file-reference.html)
 
 
-### 2.1 当前 Prettier 引用全景
-
-迁移前需清楚 Prettier 在仓库中的所有触点:
+### 2.1 当前 formatter 触点全景
 
 
-| 位置 | 用途 | 迁移动作 |
+| 位置 | 当前状态 | 说明 |
 | --- | --- | --- |
 | --- | --- | --- |
-| `internal/lint-configs/prettier-config/` | `@vben/prettier-config` 包,导出共享配置 | **改写为 `@vben/oxfmt-config`** |
-| `.prettierrc.mjs` | 根配置入口,`export { default } from '@vben/prettier-config'` | **替换为 `.oxfmtrc.json`** |
-| `.prettierignore` | 格式化忽略文件 | **迁移到 `.oxfmtrc.json` 的 `ignorePatterns`** |
-| `eslint-config/src/configs/prettier.ts` | ESLint 中 `eslint-plugin-prettier` 集成 | **移除整个配置文件** |
-| `eslint-config/src/index.ts` | 引用 `prettier()` 配置 | **移除 `prettier()` 调用** |
-| `eslint-config/package.json` | 依赖 `eslint-plugin-prettier` | **移除该依赖** |
-| `stylelint-config/index.mjs` | 插件 `stylelint-prettier`,规则 `prettier/prettier: true` | **移除 `stylelint-prettier` 插件和规则** |
-| `stylelint-config/package.json` | 依赖 `prettier`、`stylelint-prettier` | **移除这两个依赖** |
-| `internal/node-utils/src/prettier.ts` | `prettierFormat()` 函数,供构建工具调用 | **改写为调用 oxfmt** |
-| `internal/node-utils/package.json` | 依赖 `prettier` | **替换为 `oxfmt`** |
-| `scripts/vsh/src/lint/index.ts` | `prettier . --write --cache` / `prettier . --check --cache` | **替换为 `oxfmt` / `oxfmt --check`** |
-| `lefthook.yml` | 多处 `pnpm prettier --write/--cache` | **替换为 `pnpm oxfmt`** |
-| `pnpm-workspace.yaml` catalog | `prettier: ^3.8.1`、`eslint-plugin-prettier`、`stylelint-prettier` | **移除这三项** |
-| `package.json` 根 | 依赖 `@vben/prettier-config` | **替换为 `@vben/oxfmt-config`** |
-| `vben-admin.code-workspace` | workspace 引用 `prettier-config` | **更新** |
-
-### 2.2 自动迁移配置
-
-oxfmt 内置了从 Prettier 迁移的能力:
-
-```bash
-npx oxfmt@latest --migrate prettier
-```
-
-该命令会:
+| `internal/lint-configs/oxfmt-config/` | 已完成 | 新增 `@vben/oxfmt-config` workspace 包 |
+| `oxfmt.config.ts` | 已完成 | 根级 formatter 配置入口,负责追加 `ignorePatterns` |
+| `.prettierrc.mjs` | 已移除 | 不再作为根入口 |
+| `.prettierignore` | 已移除 | 忽略模式已迁入 `oxfmt.config.ts` |
+| `eslint-config/src/configs/prettier.ts` | 已移除 | ESLint 不再集成 Prettier |
+| `eslint-config/src/index.ts` | 已完成 | 已无 `prettier()` 调用 |
+| `eslint-config/package.json` | 已完成 | 已移除 `eslint-plugin-prettier` 依赖 |
+| `stylelint-config/index.mjs` | 已完成 | 已移除 `stylelint-prettier` 插件和规则 |
+| `stylelint-config/package.json` | 已完成 | 已移除 `prettier` / `stylelint-prettier` 依赖 |
+| `internal/node-utils/src/formatter.ts` | 已完成 | 格式化工具已改为调用 `oxfmt` |
+| `scripts/vsh/src/lint/index.ts` | 已完成 | 已改为调用 `oxfmt` |
+| `lefthook.yml` | 已完成 | 已统一切换为 `pnpm oxfmt` |
+| `pnpm-workspace.yaml` catalog | 已完成 | 已移除 `prettier`、`eslint-plugin-prettier`、`stylelint-prettier`,并新增 `oxfmt` |
+| `package.json` 根 | 已完成 | 已依赖 `@vben/oxfmt-config` 与 `oxfmt` |
+| `vben-admin.code-workspace` | 已完成 | 已更新 workspace 引用 |
+
+### 2.2 当前实际配置
+
+当前仓库并未使用 `.oxfmtrc.json`,而是采用 “共享包 + 根入口” 的组织方式。
+
+共享配置位于 `internal/lint-configs/oxfmt-config/src/index.ts`:
 
 
-- 读取当前 `.prettierrc.mjs`(通过 `@vben/prettier-config` 解析)
-- 生成 `.oxfmtrc.json`
-- 将 `.prettierignore` 的模式迁移到 `ignorePatterns`
-- 如果检测到 `prettier-plugin-tailwindcss` 会自动启用 `sortTailwindcss`
-- 如果检测到 `prettier-plugin-packagejson` 会启用 `sortPackageJson`
-
-> **注意**:如果 `.oxfmtrc.json` 已存在会报错,需先删除再重新运行。
-
-### 2.3 配置对照与预期输出
-
-当前 Prettier 配置(`@vben/prettier-config`):
+```ts
+import { defineConfig as defineOxfmtConfig } from 'oxfmt';
 
 
-```js
-{
-  endOfLine: 'auto',
+const oxfmtConfig = defineOxfmtConfig({
   printWidth: 80,
   printWidth: 80,
   proseWrap: 'never',
   proseWrap: 'never',
   semi: true,
   semi: true,
   singleQuote: true,
   singleQuote: true,
+  sortPackageJson: false,
   trailingComma: 'all',
   trailingComma: 'all',
-  overrides: [
-    { files: ['*.json5'], options: { quoteProps: 'preserve', singleQuote: false } }
-  ]
-}
+});
 ```
 ```
 
 
-预期 oxfmt 配置(`.oxfmtrc.json`)
+根级入口位于 `oxfmt.config.ts`:
 
 
-```json
-{
-  "$schema": "./node_modules/oxfmt/configuration_schema.json",
-  "printWidth": 80,
-  "semi": true,
-  "singleQuote": true,
-  "trailingComma": "all",
-  "proseWrap": "never",
-  "endOfLine": "lf",
-  "ignorePatterns": [
-    "dist",
-    "dev-dist",
-    ".local",
-    ".claude",
-    ".agent",
-    ".agents",
-    ".codex",
-    ".output.js",
-    "node_modules",
-    ".nvmrc",
-    "coverage",
-    "CODEOWNERS",
-    ".nitro",
-    ".output",
-    "**/*.svg",
-    "**/*.sh",
-    "public",
-    ".npmrc",
-    "*-lock.yaml",
-    "skills-lock.json"
+```ts
+import { defineConfig } from '@vben/oxfmt-config';
+
+export default defineConfig({
+  ignorePatterns: [
+    'dist',
+    'dev-dist',
+    '.local',
+    '.claude',
+    '.agent',
+    '.agents',
+    '.codex',
+    '.output.js',
+    'node_modules',
+    '.nvmrc',
+    'coverage',
+    'CODEOWNERS',
+    '.nitro',
+    '.output',
+    '**/*.svg',
+    '**/*.sh',
+    'public',
+    '.npmrc',
+    '*-lock.yaml',
+    'skills-lock.json',
   ],
   ],
-  "overrides": [
-    {
-      "files": ["*.json5"],
-      "options": { "quoteProps": "preserve", "singleQuote": false }
-    }
-  ]
-}
+});
 ```
 ```
 
 
-关键差异说明
+需要注意两点:
 
 
-| Prettier 选项 | oxfmt 处理 |
-| --- | --- |
-| `endOfLine: 'auto'` | **不支持 `auto`**,需显式设为 `"lf"`(与 `.editorconfig` 的 `end_of_line=lf` 一致) |
-| `printWidth: 80` | 直接映射(oxfmt 默认 100,需显式设 80 保持一致) |
-| `overrides` | **自动迁移不支持 `overrides`**,需手动编写 |
+1. 当前 formatter 的 `printWidth` 明确设为 `80`
+2. `.editorconfig` 的 `max_line_length` 仍为 `100`
 
 
-### 2.4 `@vben/oxfmt-config` workspace 包
+也就是说,当前仓库实际上采用的是“oxfmt 显式配置优先于 `.editorconfig`”的策略,这一点需要在后续验证中保持一致。
 
 
-保持与 `@vben/prettier-config` 一致的 workspace 包组织模式:
+### 2.3 `@vben/oxfmt-config` workspace 包
+
+当前包结构与其他 lint-config 包保持一致:
 
 
 ```text
 ```text
 internal/lint-configs/oxfmt-config/
 internal/lint-configs/oxfmt-config/
   package.json
   package.json
-  index.mjs          # 导出 oxfmt 配置对象(供程序化调用)
+  src/index.ts
 ```
 ```
 
 
 ```json
 ```json
-// internal/lint-configs/oxfmt-config/package.json
 {
 {
   "name": "@vben/oxfmt-config",
   "name": "@vben/oxfmt-config",
   "version": "5.6.0",
   "version": "5.6.0",
   "private": true,
   "private": true,
   "type": "module",
   "type": "module",
-  "main": "./index.mjs",
-  "module": "./index.mjs",
+  "files": ["dist"],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
   "exports": {
   "exports": {
-    ".": { "default": "./index.mjs" }
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.mjs"
+    }
   },
   },
   "dependencies": {
   "dependencies": {
     "oxfmt": "catalog:"
     "oxfmt": "catalog:"
@@ -570,167 +564,54 @@ internal/lint-configs/oxfmt-config/
 }
 }
 ```
 ```
 
 
-> **注意**:oxfmt 的配置文件 `.oxfmtrc.json` 不像 Prettier 那样支持 JS 配置的 `export default`。 `@vben/oxfmt-config` 包的作用是:
->
-> 1. 集中管理 `oxfmt` 版本依赖
-> 2. 导出配置对象供 `internal/node-utils` 等程序化场景使用
-> 3. 根目录直接使用 `.oxfmtrc.json` 文件(oxfmt 会自动读取)
-
-### 2.5 替换范围详表
+这个包当前承担三件事:
 
 
-| 当前依赖 | 替代方案 |
-| --- | --- |
-| `prettier` ^3.8.1 | `oxfmt`(JS/TS 原生格式化,CSS/HTML/YAML/MD 内部委托 Prettier) |
-| `eslint-plugin-prettier` | 移除(不再需要 ESLint-Prettier 集成) |
-| `stylelint-prettier` | 移除(Stylelint 不再需要 Prettier 集成) |
-| `@vben/prettier-config` | 改写为 `@vben/oxfmt-config` |
+1. 集中管理 `oxfmt` 版本依赖
+2. 导出共享格式化配置对象
+3. 供根级 `oxfmt.config.ts` 和其他程序化场景复用
 
 
-### 2.6 操作步骤
+### 2.4 已完成的替换范围
 
 
-#### 第一步:生成 oxfmt 配置
+| 原方案                   | 当前状态                      |
+| ------------------------ | ----------------------------- |
+| `prettier`               | 已移除,当前统一使用 `oxfmt`  |
+| `eslint-plugin-prettier` | 已移除                        |
+| `stylelint-prettier`     | 已移除                        |
+| `@vben/prettier-config`  | 已替换为 `@vben/oxfmt-config` |
 
 
-```bash
-# 自动迁移(生成 .oxfmtrc.json)
-npx oxfmt@latest --migrate prettier
+### 2.5 已完成的操作
 
 
-# 手动补充 overrides(自动迁移不支持)
-# 手动将 endOfLine: 'auto' 改为 "lf"
-# 手动添加 ignorePatterns(从 .prettierignore 迁移)
-```
+以下动作已在当前仓库完成:
 
 
-#### 第二步:创建 `@vben/oxfmt-config` 包
+1. 创建 `@vben/oxfmt-config` workspace 包
+2. 新增根级 `oxfmt.config.ts`
+3. 将 `scripts/vsh/src/lint/index.ts` 切换到 `oxfmt`
+4. 将 `lefthook.yml` 切换到 `pnpm oxfmt`
+5. 删除 ESLint 中的 Prettier 集成
+6. 删除 Stylelint 中的 Prettier 集成
+7. 将 `internal/node-utils` 中的格式化能力切换到 `oxfmt`
+8. 删除 `.prettierrc.mjs`、`.prettierignore` 和旧的 `@vben/prettier-config`
+9. 更新根 `package.json`、`pnpm-workspace.yaml`、`vben-admin.code-workspace`
 
 
-```bash
-mkdir -p internal/lint-configs/oxfmt-config
-# 创建 package.json 和 index.mjs
-```
+### 2.6 下一步只保留验证项
 
 
-#### 第三步:全量格式化并对比
+第二阶段当前不再需要按“迁移步骤”执行,剩余工作主要是验证和收口:
 
 
-```bash
-# 先用 prettier 格式化一遍作为基线
-pnpm prettier . --write
-
-# 再用 oxfmt 格式化
-npx oxfmt@latest
-
-# 查看差异
-git diff --stat
-```
-
-检查差异是否可接受。已知的可能差异:
-
-- oxfmt 的 `sortPackageJson` 排序算法可能与 Prettier 不同
-- 嵌入语言格式化(CSS-in-JS)可能有细微差异
-
-#### 第四步:更新 `scripts/vsh/src/lint/index.ts`
-
-```ts
-// Before
-await execaCommand(`prettier . --write --cache --log-level warn`, {
-  stdio: 'inherit',
-});
-await execaCommand(`prettier . --ignore-unknown --check --cache`, {
-  stdio: 'inherit',
-});
-
-// After
-await execaCommand(`oxfmt`, { stdio: 'inherit' });
-await execaCommand(`oxfmt --check`, { stdio: 'inherit' });
-```
-
-#### 第五步:更新 `lefthook.yml`
-
-```yaml
-pre-commit:
-  parallel: true
-  commands:
-    lint-md:
-      run: pnpm oxfmt {staged_files}
-      glob: '*.md'
-    lint-vue:
-      run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files}
-      glob: '*.vue'
-    lint-js:
-      run: pnpm oxfmt {staged_files} && pnpm oxlint --fix {staged_files} && pnpm eslint --cache --fix {staged_files}
-      glob: '*.{js,jsx,ts,tsx}'
-    lint-style:
-      run: pnpm oxfmt {staged_files} && pnpm stylelint --fix --allow-empty-input {staged_files}
-      glob: '*.{scss,less,styl,html,vue,css}'
-    lint-package:
-      run: pnpm oxfmt {staged_files}
-      glob: 'package.json'
-    lint-json:
-      run: pnpm oxfmt {staged_files}
-      glob: '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}'
-```
-
-#### 第六步:清理 ESLint 中的 Prettier 集成
-
-1. 删除 `eslint-config/src/configs/prettier.ts`
-2. 从 `eslint-config/src/configs/index.ts` 移除 `export * from './prettier'`
-3. 从 `eslint-config/src/index.ts` 移除 `prettier()` 调用
-4. 从 `eslint-config/package.json` 移除 `eslint-plugin-prettier` 依赖
-
-#### 第七步:清理 Stylelint 中的 Prettier 集成
-
-1. 从 `stylelint-config/index.mjs` 的 `plugins` 数组移除 `'stylelint-prettier'`
-2. 从 `stylelint-config/index.mjs` 的 `rules` 移除 `'prettier/prettier': true`
-3. 从 `stylelint-config/package.json` 移除 `prettier` 和 `stylelint-prettier` 依赖
-
-#### 第八步:更新 `internal/node-utils/src/prettier.ts`
-
-```ts
-// 重命名为 formatter.ts 或保留文件名
-import { execaCommand } from 'execa';
-
-async function formatFile(filepath: string) {
-  await execaCommand(`oxfmt ${filepath}`, { stdio: 'inherit' });
-}
-
-export { formatFile };
-```
-
-或者如果 oxfmt 提供了 Node API,则使用程序化调用。
-
-#### 第九步:移除旧依赖
-
-```bash
-# 移除根目录文件
-rm .prettierrc.mjs
-rm .prettierignore
-
-# 从 pnpm-workspace.yaml catalog 移除
-# - prettier: ^3.8.1
-# - eslint-plugin-prettier: ^5.5.5
-# - stylelint-prettier: ^5.0.3
-
-# 移除 @vben/prettier-config 包
-rm -rf internal/lint-configs/prettier-config
-
-# 更新 package.json 根,移除 @vben/prettier-config 依赖
-# 更新 vben-admin.code-workspace,移除 prettier-config workspace 引用
-```
-
-#### 第十步:全量验证
-
-```bash
-pnpm install
-pnpm run lint
-pnpm run lint:oxc
-pnpm run lint:eslint
-```
+1. 重新全量运行 `pnpm run lint`,确认 `vsh lint` 当前默认行为与预期一致
+2. 明确 `oxfmt.config.ts` 是否作为 CLI 与编辑器共同入口;如团队工具链存在兼容性差异,再决定是否需要补 `.oxfmtrc.json`
+3. 决定 `printWidth: 80` 与 `.editorconfig` 的 `max_line_length = 100` 是否继续并存
+4. 评估是否启用 oxfmt 的额外能力,例如 `sortImports`、`sortTailwindcss`
 
 
 ### 2.7 oxfmt 额外能力评估
 ### 2.7 oxfmt 额外能力评估
 
 
 oxfmt 提供了 Prettier 没有的扩展特性,可选启用:
 oxfmt 提供了 Prettier 没有的扩展特性,可选启用:
 
 
-| 特性 | 说明 | 建议 |
+| 特性 | 说明 | 当前状态 / 建议 |
 | --- | --- | --- |
 | --- | --- | --- |
-| `sortImports` | import 语句排序,灵感来自 `eslint-plugin-perfectionist/sort-imports` | 评估是否可替代 ESLint 侧 perfectionist 的 import 排序 |
-| `sortTailwindcss` | 替代 `prettier-plugin-tailwindcss` | 当前项目已通过 oxlint `jsPlugins` 处理,需评估是否切换 |
-| `sortPackageJson` | 自动排序 `package.json` 字段 | 默认启用,排序算法与 prettier-plugin-packagejson 不同 |
-| `insertFinalNewline` | 文件末尾添加换行 | 默认启用,与 `.editorconfig` 的 `insert_final_newline=true` 一致 |
+| `sortImports` | import 语句排序,灵感来自 `eslint-plugin-perfectionist/sort-imports` | 可评估是否替代 ESLint 侧部分排序职责 |
+| `sortTailwindcss` | 替代 `prettier-plugin-tailwindcss` | 当前仓库仍优先使用 oxlint `jsPlugins` 方案 |
+| `sortPackageJson` | 自动排序 `package.json` 字段 | 当前共享配置显式设为 `false` |
+| `insertFinalNewline` | 文件末尾添加换行 | 与 `.editorconfig` 的 `insert_final_newline=true` 一致 |
 
 
 ### 2.8 文件类型覆盖说明
 ### 2.8 文件类型覆盖说明
 
 
@@ -745,15 +626,15 @@ oxfmt 对不同文件类型的处理方式:
 | HTML                      | 内部委托 Prettier                             |
 | HTML                      | 内部委托 Prettier                             |
 | YAML / Markdown / GraphQL | 内部委托 Prettier                             |
 | YAML / Markdown / GraphQL | 内部委托 Prettier                             |
 
 
-> **重要**:CSS 等非 JS/TS 文件仍然通过 oxfmt 内部委托 Prettier 处理,因此 `npx oxfmt` 一个命令即可覆盖所有文件类型。不需要单独安装 Prettier——oxfmt 自带内嵌版本
+> **重要**:CSS 等非 JS/TS 文件仍然通过 oxfmt 内部委托 Prettier 处理,因此 `oxfmt` 一个命令即可覆盖主要文件类型;仓库中不需要再单独安装 `prettier`
 
 
-### 2.9 迁移风险
+### 2.9 当前风险与注意事项
 
 
-1. **格式化差异**:oxfmt 与 Prettier 的输出可能存在细微差异,首次全量格式化会产生大量 diff,建议单独一个 commit
-2. **嵌套配置不支持**:oxfmt 不支持子目录级别的配置文件,如有需要需用 `overrides` 替代
-3. **`endOfLine: 'auto'` 不支持**:必须改为显式值,建议统一为 `"lf"`
-4. **`node-utils/prettier.ts`**:如果有其他包或脚本通过 `prettierFormat()` 调用格式化,需逐一排查
-5. **IDE 配置**:团队成员需安装 oxfmt VS Code 扩展,或配置 LSP(`oxfmt --lsp`)
+1. **配置入口一致性**:当前实际入口是 `oxfmt.config.ts`,需确认 CLI、编辑器、CI 是否都按这份配置执行
+2. **行宽来源不一致**:`oxfmt` 显式 `printWidth: 80`,`.editorconfig` 为 `100`,需要明确这是有意保留还是待统一
+3. **格式化差异**:首次重新全量格式化时,仍可能出现与历史 Prettier 输出不同的 diff
+4. **扩展能力取舍**:`sortImports`、`sortTailwindcss` 是否启用会直接影响 ESLint / oxlint 的职责边界
+5. **IDE 配置**:团队成员仍需统一使用 oxfmt 对应扩展或 LSP(`oxfmt --lsp`)
 
 
 ---
 ---
 
 
@@ -777,7 +658,7 @@ oxfmt 对不同文件类型的处理方式:
 
 
 ## 第四阶段:完全移除 ESLint(远期)
 ## 第四阶段:完全移除 ESLint(远期)
 
 
-**前提**:oxlint 完全支持 Vue SFC 模板 lint 及所有保留插件的功能。
+**前提**:oxlint 完全支持 Vue SFC 模板 lint 及所有当前保留插件的功能。
 
 
 ### 4.1 替换范围
 ### 4.1 替换范围
 
 
@@ -790,7 +671,6 @@ oxfmt 对不同文件类型的处理方式:
 | `eslint-config-turbo` | 移除 |
 | `eslint-config-turbo` | 移除 |
 | `eslint-plugin-pnpm` | oxlint 或独立检查 |
 | `eslint-plugin-pnpm` | oxlint 或独立检查 |
 | `eslint-plugin-command` | oxlint 或移除 |
 | `eslint-plugin-command` | oxlint 或移除 |
-| `@vitest/eslint-plugin` | oxlint vitest 分类 |
 | `@vben/eslint-config` | 改写为 `@vben/oxlint-config` 或移除 |
 | `@vben/eslint-config` | 改写为 `@vben/oxlint-config` 或移除 |
 
 
 ### 4.2 操作步骤
 ### 4.2 操作步骤
@@ -798,26 +678,26 @@ oxfmt 对不同文件类型的处理方式:
 1. 持续跟踪 oxlint 的 Vue / JSON / YAML 支持进展
 1. 持续跟踪 oxlint 的 Vue / JSON / YAML 支持进展
 2. 当 oxlint 规则覆盖度满足要求时,全面切换
 2. 当 oxlint 规则覆盖度满足要求时,全面切换
 3. 移除 `internal/lint-configs/eslint-config/` 及所有 ESLint 相关依赖
 3. 移除 `internal/lint-configs/eslint-config/` 及所有 ESLint 相关依赖
-4. 更新 CI 和 lefthook 配置
+4. 更新 CI 和 `lefthook` 配置
 
 
 ---
 ---
 
 
 ## 迁移风险与注意事项
 ## 迁移风险与注意事项
 
 
 1. **规则对齐**:oxlint 的规则命名和行为可能与 ESLint 插件不完全一致,需逐条验证
 1. **规则对齐**:oxlint 的规则命名和行为可能与 ESLint 插件不完全一致,需逐条验证
-2. **Vue SFC 支持**:oxlint 对 `<template>` 的 lint 能力是最大瓶颈,第一阶段务必保留 `eslint-plugin-vue`
+2. **Vue SFC 支持**:oxlint 对 `<template>` 的 lint 能力是最大瓶颈,第一阶段务必保留 `eslint-plugin-vue`
 3. **CI 稳定性**:共存期间两套工具可能对同一问题重复报告,需通过配置互相排除
 3. **CI 稳定性**:共存期间两套工具可能对同一问题重复报告,需通过配置互相排除
-4. **团队习惯**:IDE 插件(如 VS Code ESLint 扩展)需要同步配置 oxlint 扩展
+4. **团队习惯**:IDE 插件需要同步配置 oxlint / oxfmt 对应扩展
 5. **版本锁定**:oxc 生态仍在快速迭代,建议锁定 minor 版本,升级时做全量验证
 5. **版本锁定**:oxc 生态仍在快速迭代,建议锁定 minor 版本,升级时做全量验证
 
 
 ---
 ---
 
 
 ## 预期收益
 ## 预期收益
 
 
-| 指标      | 预期改善                                    |
-| --------- | ------------------------------------------- |
-| lint 速度 | 通用规则部分提升 50-100x                    |
-| 依赖数量  | 第一阶段减少约 11 个包,最终可减少 20+ 个包 |
-| 安装体积  | 显著减少(ESLint 插件依赖树庞大)           |
-| CI 时间   | lint 阶段耗时大幅缩短                       |
-| 维护成本  | 减少 ESLint 插件版本兼容性问题              |
+| 指标      | 预期改善                              |
+| --------- | ------------------------------------- |
+| lint 速度 | 通用规则部分显著提升                  |
+| 依赖数量  | 第一阶段已明显减少,最终可继续下降    |
+| 安装体积  | 显著减少(ESLint 插件依赖树庞大)     |
+| CI 时间   | lint 阶段耗时大幅缩短                 |
+| 维护成本  | 减少 ESLint / Prettier 插件兼容性问题 |