Repository: easyops-cn/next-advanced-bricks
Pull request #84: feat(): monaco editor copilot
Author: login: weareoutman
Labels: name: eve: release after merged
Created: 2025-03-31T03:30:18Z | Merged: 2025-03-31T04:15:37Z

## 依赖检查

组件之间的依赖声明，是微服务组件架构下的重要信息，请确保其正确性。

请勾选以下两组选项其中之一：

- [x] 本次 MR **没有使用**上游组件（例如框架、后台组件等）的较新版本提供的特性。

或者：

- [ ] 本次 MR **使用了**上游组件（例如框架、后台组件等）的较新版本提供的特性。
- [ ] 在对应的文件中更新了该上游组件的依赖版本（或确认了当前声明的依赖版本已包含本次 MR 使用的新特性）。

## 提交信息检查

Git 提交信息将决定包的版本发布及自动生成的 CHANGELOG，请检查工作内容与提交信息是否相符，并在以下每组选项中都依次确认。

> 破坏性变更是针对于下游使用者而言，可以通过本次改动对下游使用者的影响来识别变更类型：
>
> - 下游使用者不做任何改动，仍可以正常工作时，那么它属于普通变更。
> - 反之，下游使用者不做改动就无法正常工作时，那么它属于破坏性变更。
>
> 例如，构件修改了一个属性名，小产品 Storyboard 中需要使用新属性名才能工作，那么它就是破坏性变更。
> 又例如，构件还没有任何下游使用者，那么它的任何变更都是普通变更。

### 破坏性变更：

- [ ] ⚠️ 本次 MR 包含**破坏性变更**的提交，请继续确认以下所有选项：
- [ ] 没有更好的兼容方案，必须做破坏性变更。
- [ ] 使用了 `feat` 作为提交类型。
- [ ] 标注了 `BREAKING CHANGE: 你的变更说明`。
- [ ] 同时更新了本仓库中所有下游使用者的调用。
- [ ] 同时更新了本仓库中所有下游使用者对该子包的依赖为即将发布的 major 版本。
- [ ] 同时为其它仓库的 Migrating 做好了准备，例如文档或批量改动的方法。
- [ ] 手动验证过破坏性变更在 Migrate 后可以正常工作。
- [ ] 破坏性变更所在的提交没有意外携带其它子包的改动。

### 新特性：

- [x] 本次 MR 包含新特性的提交，且该提交不带有破坏性变更，并使用了 `feat` 作为提交类型。
- [x] 给新特性添加了单元测试。
- [x] 手动验证过新特性可以正常工作。

### 问题修复：

- [ ] 本次 MR 包含问题修复的提交，且该提交不带有新特性或破坏性变更，并使用了 `fix` 作为提交类型。
- [ ] 给问题修复添加了单元测试。
- [ ] 手动验证过问题修复得到解决。

### 杂项工作：

即所有对下游使用者无任何影响、且没有必要显示在 CHANGELOG 中的改动，例如修改注释、测试用例、开发文档等：

- [ ] 本次 MR 包含杂项工作的提交，且该提交不带有问题修复、新特性或破坏性变更，并使用了 `chore`, `docs`, `test` 等作为提交类型。

<!-- ## 简单描述

<!-- 我在这个 MR 里都做了哪些工作？!-->

<!-- ## Todo

<!-- 我还有哪些事情没做？!-->



Diff:
diff --git a/bricks/vs/build.config.js b/bricks/vs/build.config.js
index 21c8da69d..1e951155c 100644
--- a/bricks/vs/build.config.js
+++ b/bricks/vs/build.config.js
@@ -24,6 +24,10 @@ export default {
         rootMode: "upward",
       },
     },
+    {
+      test: /\.txt$/,
+      type: "asset/source",
+    },
   ],
   plugins: [
     new MonacoWebpackPlugin({
diff --git a/bricks/vs/docs/code-editor.md b/bricks/vs/docs/code-editor.md
index 0dc680cbe..0d73372ef 100644
--- a/bricks/vs/docs/code-editor.md
+++ b/bricks/vs/docs/code-editor.md
@@ -88,13 +88,55 @@ children:
 
 ```yaml preview
 - brick: vs.code-editor
+  context:
+    - name: commonMarkers
+      value:
+        - token: PATH
+          message: 这是 PATH
+          level: hit
+        - token: QUERY
+          message: 这是 QUERY
+          level: info
+        - token: ANCHOR
+          message: 这是 ANCHOR
+          level: warn
+        - token: STATE
+          message: 这里不能写 STATE
+          level: error
+          code:
+            value: 详情地址
+            target: https://brick-next.js.org/docs/concepts/context
+        - token: TPL
+          level: warn
+          message: 不允许写入TPL
+    - name: commonLibs
+      value:
+        - filePath: base.d.ts
+          content: |
+            declare namespace CTX {
+              const pageTitle: string;
+              const name: string;
+              const a;
+              const b;
+            };
+            declare namespace FN {
+              function getPageDetail();
+              function getInstance();
+            };
+            declare namespace PATH {
+              const instanceId: string;
+              const name: string;
+            };
+            declare namespace QUERY {
+              const activeId: string;
+            }
   events:
     token.click:
       - action: console.log
   properties:
     language: brick_next_yaml
     value: |
-      basicUsige:
+      basicUsage:
         keyword:
          Expression:
           expression1: <% CTX.work %>
@@ -176,7 +218,7 @@ children:
               %>
             test7: |
               <%  "track context",  CTX.name 
-          exporession16:
+          expression16:
             - <% CTX.a %>     
             - CTX.b
             -   <% CTX.c %>    
@@ -198,25 +240,6 @@ children:
     links:
       - CTX
       - FN
-    markers:
-      - token: PATH
-        message: “这是 PATH”
-        level: hit
-      - token: QUERY
-        message: “这是 QUERY”
-        level: info
-      - token: ANCHOR
-        message: “这是 ANCHOR“
-        level: warn
-      - token: STATE
-        message: "这里不能写 STATE"
-        level: error
-        code:
-          value: "详情地址"
-          target: https://brick-next.js.org/docs/concepts/context
-      - token: TPL
-        level: warn
-        message: 不允许写入TPL
     completers:
       - label: buttonName
         detail: string
@@ -230,26 +253,8 @@ children:
         completers:
           - label: a
           - label: b
-    extraLibs:
-      - filePath: base.d.ts
-        content: |
-          declare namespace CTX {
-            const pageTitle: string;
-            const name: string;
-            const a;
-            const b;
-          };
-          declare namespace FN {
-            function getPageDetail();
-            function getInstance();
-          };
-          declare namespace PATH {
-            const instanceId: string;
-            const name: string;
-          };
-          declare namespace QUERY {
-            const activeId: string;
-          }
+    markers: <% CTX.commonMarkers %>
+    extraLibs: <% CTX.commonLibs %>
 - brick: vs.code-editor
   events:
     highlight.click:
@@ -264,6 +269,8 @@ children:
     links:
       - CTX
       - FN
+    markers: <% CTX.commonMarkers %>
+    extraLibs: <% CTX.commonLibs %>
 - brick: vs.code-editor
   events:
     highlight.click:
@@ -276,6 +283,8 @@ children:
     links:
       - CTX
       - FN
+    markers: <% CTX.commonMarkers %>
+    extraLibs: <% CTX.commonLibs %>
 - brick: vs.code-editor
   events:
     highlight.click:
@@ -289,6 +298,8 @@ children:
     links:
       - CTX
       - FN
+    markers: <% CTX.commonMarkers %>
+    extraLibs: <% CTX.commonLibs %>
 ```
 
 ### Show CTX.DS
diff --git a/bricks/vs/package.json b/bricks/vs/package.json
index 79535dab2..cee85a3a7 100644
--- a/bricks/vs/package.json
+++ b/bricks/vs/package.json
@@ -58,14 +58,17 @@
   },
   "dependencies": {
     "@babel/types": "^7.22.5",
+    "@next-api-sdk/llm-sdk": "^1.1.3",
     "@next-core/cook": "^2.5.7",
     "@next-core/element": "^1.2.17",
     "@next-core/monaco-contributions": "^0.3.14",
     "@next-core/react-element": "^1.0.36",
     "@next-core/react-runtime": "^1.7.11",
+    "@next-core/runtime": "^1.59.4",
     "@next-core/theme": "^1.5.4",
     "@next-core/utils": "^1.7.32",
     "@next-shared/form": "^0.7.10",
+    "@next-shared/monaco-copilot": "^0.0.0",
     "@next-shared/spell-check": "^0.1.1",
     "comlink": "^4.4.2",
     "monaco-editor": "^0.50.0",
diff --git a/bricks/vs/src/code-editor/index.spec.tsx b/bricks/vs/src/code-editor/index.spec.tsx
index 17acf8b73..d8edd6d23 100644
--- a/bricks/vs/src/code-editor/index.spec.tsx
+++ b/bricks/vs/src/code-editor/index.spec.tsx
@@ -6,6 +6,14 @@ import { CodeEditor } from "./index.js";
 import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
 
 jest.mock("@next-core/theme", () => ({}));
+jest.mock("@next-core/runtime", () => ({
+  getRuntime() {
+    return null;
+  },
+  getV2RuntimeFromDll() {
+    return null;
+  },
+}));
 jest.mock("@next-core/react-runtime");
 jest.mock("./workers/yamlLinter.js", () => ({}));
 jest.mock("./workers/spellCheckRemoteWorker.js", () => ({}));
diff --git a/bricks/vs/src/code-editor/index.tsx b/bricks/vs/src/code-editor/index.tsx
index 04f8b1cd6..4c2931ad4 100644
--- a/bricks/vs/src/code-editor/index.tsx
+++ b/bricks/vs/src/code-editor/index.tsx
@@ -10,6 +10,8 @@ import { EventEmitter, createDecorators } from "@next-core/element";
 import { unwrapProvider } from "@next-core/utils/general";
 import { wrapBrick } from "@next-core/react-element";
 import { useCurrentTheme } from "@next-core/react-runtime";
+import { getRuntime } from "@next-core/runtime";
+import { HttpAbortError } from "@next-core/http";
 import { FormItemElementBase } from "@next-shared/form";
 import type { FormItem, FormItemProps } from "@next-bricks/form/form-item";
 import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
@@ -38,7 +40,6 @@ import {
   getEmbeddedJavascriptUri,
   getBrickYamlBuiltInDeclare,
 } from "./utils/jsSuggestInBrickYaml.js";
-import { addExtraLibs } from "./utils/addExtraLibs.js";
 import type { EoTooltip, ToolTipProps } from "@next-bricks/basic/tooltip";
 import type {
   GeneralIcon,
@@ -49,6 +50,11 @@ import { K, NS, locales } from "./i18n.js";
 import type { copyToClipboard as _copyToClipboard } from "@next-bricks/basic/data-providers/copy-to-clipboard";
 import type { showNotification as _showNotification } from "@next-bricks/basic/data-providers/show-notification/show-notification";
 import classNames from "classnames";
+import {
+  MonacoCopilotProvider,
+  SUPPORTED_LANGUAGES,
+} from "@next-shared/monaco-copilot";
+import { AiopsBaseApi_openaiChat } from "@next-api-sdk/llm-sdk";
 import "./index.css";
 import { EmbeddedModelContext } from "./utils/embeddedModelState.js";
 import { PlaceholderContentWidget } from "./widget/Placeholder.js";
@@ -62,6 +68,12 @@ import {
   celCommonCompletionProviderFactory,
   celSpecificCompletionProviderFactory,
 } from "./utils/celCompletionProvider.js";
+import {
+  disposeEditor,
+  isCurrentEditor,
+  switchEditor,
+} from "./utils/EditorService.js";
+import { setExtraLibs } from "./utils/setExtraLibs.js";
 
 initializeReactI18n(NS, locales);
 
@@ -89,6 +101,47 @@ for (const lang of CEL_FAMILY) {
   );
 }
 
+// istanbul ignore next
+const { enabled: copilotEnabled, ...copilotOptions } =
+  (getRuntime()?.getMiscSettings().globalMonacoEditorCopilotOptions ?? {}) as {
+    enabled?: boolean;
+    model?: string;
+    debounce?: number;
+    timeout?: number;
+  };
+
+// istanbul ignore next
+if (copilotEnabled) {
+  monaco.languages.registerInlineCompletionsProvider(
+    SUPPORTED_LANGUAGES,
+    new MonacoCopilotProvider({
+      ...copilotOptions,
+      async request({ model, temperature, system, prompt, signal }) {
+        const response = await AiopsBaseApi_openaiChat(
+          {
+            model,
+            temperature,
+            enableSensitiveWordsFilter: false,
+            stream: false,
+            messages: [
+              ...(system ? [{ role: "system", content: system }] : []),
+              { role: "user", content: prompt },
+            ],
+          },
+          {
+            signal,
+            interceptorParams: {
+              ignoreLoadingBar: true,
+            },
+          }
+        );
+        return response.choices?.[0]?.message?.content?.trim();
+      },
+      HttpAbortError,
+    })
+  );
+}
+
 const { defineElement, property, event } = createDecorators();
 
 const WrappedFormItem = wrapBrick<FormItem, FormItemProps>("eo-form-item");
@@ -712,19 +765,6 @@ export function CodeEditorComponent({
   const languageDefaults =
     language === "typescript" ? "typescriptDefaults" : "javascriptDefaults";
 
-  useEffect(() => {
-    const libs: ExtraLib[] = extraLibs ?? [];
-
-    const disposables = addExtraLibs(libs, {
-      languageDefaults,
-    });
-    return () => {
-      for (const item of disposables) {
-        item.dispose();
-      }
-    };
-  }, [extraLibs, language, languageDefaults]);
-
   useEffect(() => {
     if (
       language === "javascript" ||
@@ -741,6 +781,55 @@ export function CodeEditorComponent({
     }
   }, [language, domLibsEnabled, languageDefaults]);
 
+  useEffect(() => {
+    const editor = editorRef.current;
+    if (!editor) {
+      return;
+    }
+    return () => {
+      disposeEditor(editor);
+    };
+  }, []);
+
+  useEffect(() => {
+    const editor = editorRef.current;
+    if (!editor) {
+      return;
+    }
+
+    const setupLanguageService = () => {
+      setExtraLibs(extraLibs, { languageDefaults });
+
+      if (
+        language === "javascript" ||
+        language === "typescript" ||
+        language === "brick_next_yaml"
+      ) {
+        monaco.languages.typescript[languageDefaults].setCompilerOptions({
+          allowNonTsExtensions: true,
+          lib: domLibsEnabled ? undefined : ["esnext"],
+          target: monaco.languages.typescript.ScriptTarget.ESNext,
+          moduleResolution:
+            monaco.languages.typescript.ModuleResolutionKind.NodeJs,
+        });
+      }
+    };
+
+    if (isCurrentEditor(editor)) {
+      setupLanguageService();
+    }
+
+    const disposable = editor.onDidFocusEditorWidget(() => {
+      // Set language service for this particular editor instance
+      if (switchEditor(editor)) {
+        setupLanguageService();
+      }
+    });
+    return () => {
+      disposable.dispose();
+    };
+  }, [domLibsEnabled, extraLibs, language, languageDefaults]);
+
   useEffect(() => {
     const editor = editorRef.current;
     if (language === "brick_next_yaml" && editor) {
@@ -971,13 +1060,6 @@ export function CodeEditorComponent({
     }
   }, [expanded]);
 
-  useEffect(() => {
-    return () => {
-      editorRef.current?.getModel()?.dispose();
-      editorRef.current?.dispose();
-    };
-  }, []);
-
   useEffect(() => {
     if (!editorRef.current && !placeholder) return;
     const placeholderWidget = new PlaceholderContentWidget(
diff --git a/bricks/vs/src/code-editor/utils/EditorService.ts b/bricks/vs/src/code-editor/utils/EditorService.ts
new file mode 100644
index 000000000..01b313959
--- /dev/null
+++ b/bricks/vs/src/code-editor/utils/EditorService.ts
@@ -0,0 +1,29 @@
+import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
+
+export let currentEditor: monaco.editor.IStandaloneCodeEditor | null = null;
+
+export function switchEditor(
+  editor: monaco.editor.IStandaloneCodeEditor
+): boolean {
+  if (currentEditor === editor) {
+    return false;
+  }
+  currentEditor = editor;
+  return true;
+}
+
+export function disposeEditor(
+  editor: monaco.editor.IStandaloneCodeEditor
+): void {
+  if (currentEditor === editor) {
+    currentEditor = null;
+  }
+  editor.getModel()?.dispose();
+  editor.dispose();
+}
+
+export function isCurrentEditor(
+  editor: monaco.editor.IStandaloneCodeEditor
+): boolean {
+  return currentEditor === editor;
+}
diff --git a/bricks/vs/src/code-editor/utils/addExtraLibs.spec.ts b/bricks/vs/src/code-editor/utils/addExtraLibs.spec.ts
deleted file mode 100644
index 6a56c0245..000000000
--- a/bricks/vs/src/code-editor/utils/addExtraLibs.spec.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { describe, test, expect } from "@jest/globals";
-import { addExtraLibs } from "./addExtraLibs.js";
-import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
-jest.mock("monaco-editor/esm/vs/editor/editor.api.js");
-
-describe("addExtraLibs", () => {
-  test("should work", () => {
-    jest
-      .spyOn(monaco.Uri, "file")
-      .mockImplementation(
-        (args) => ({ toString: () => `${args}` }) as monaco.Uri
-      );
-
-    const mockDispose = jest.fn();
-    const mockAddExtraLib = jest
-      .spyOn(monaco.languages.typescript.javascriptDefaults, "addExtraLib")
-      .mockReturnValue({ dispose: mockDispose });
-
-    addExtraLibs(
-      [
-        {
-          filePath: "test.d.ts",
-          content: "declare const PATH:object;",
-        },
-      ],
-      { languageDefaults: "javascriptDefaults" }
-    );
-
-    expect(mockAddExtraLib.mock.calls[0][1]).toEqual("libs/test.d.ts");
-
-    addExtraLibs(
-      [
-        {
-          filePath: "test.d.ts",
-          content: "declare const QUERY:object;",
-        },
-      ],
-      { languageDefaults: "javascriptDefaults" }
-    );
-
-    expect(mockDispose).toHaveBeenCalled();
-  });
-});
diff --git a/bricks/vs/src/code-editor/utils/addExtraLibs.ts b/bricks/vs/src/code-editor/utils/addExtraLibs.ts
deleted file mode 100644
index 870e11220..000000000
--- a/bricks/vs/src/code-editor/utils/addExtraLibs.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
-import { ExtraLib } from "../interfaces.js";
-
-const extraLibsMap = new Map<string, monaco.IDisposable[]>();
-
-export function addExtraLibs(
-  libs: ExtraLib[],
-  options: {
-    languageDefaults: "javascriptDefaults" | "typescriptDefaults";
-  }
-): monaco.IDisposable[] {
-  return libs.flatMap((lib) => {
-    const uri = monaco.Uri.file(`libs/${lib.filePath}`);
-    const uriString = uri.toString();
-    const previousLibs = extraLibsMap.get(uriString);
-    if (previousLibs) {
-      previousLibs.forEach((lib) => lib.dispose());
-    }
-    // Add libs for both js and ts.
-    const disposables = [options.languageDefaults].map((key) =>
-      monaco.languages.typescript[key].addExtraLib(lib.content, uriString)
-    );
-
-    extraLibsMap.set(uriString, disposables);
-    return disposables;
-  });
-}
diff --git a/bricks/vs/src/code-editor/utils/setExtraLibs.spec.ts b/bricks/vs/src/code-editor/utils/setExtraLibs.spec.ts
new file mode 100644
index 000000000..1d2c3a107
--- /dev/null
+++ b/bricks/vs/src/code-editor/utils/setExtraLibs.spec.ts
@@ -0,0 +1,92 @@
+import { setExtraLibs } from "./setExtraLibs.js";
+import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
+
+// Mock monaco
+jest.mock("monaco-editor/esm/vs/editor/editor.api.js", () => {
+  const Uri = {
+    file: (path: string) => ({
+      toString: () => `file://${path}`,
+    }),
+  };
+
+  const addExtraLibMock = jest.fn().mockReturnValue({ dispose: jest.fn() });
+
+  const languages = {
+    typescript: {
+      javascriptDefaults: {
+        addExtraLib: addExtraLibMock,
+      },
+      typescriptDefaults: {
+        addExtraLib: addExtraLibMock,
+      },
+    },
+  };
+
+  return {
+    Uri,
+    languages,
+  };
+});
+
+describe("setExtraLibs", () => {
+  it("should dispose previous libs if they exist", () => {
+    // Call once to set previousDisposables
+    const libs = [
+      { filePath: "test.d.ts", content: "declare const test: string;" },
+    ];
+    setExtraLibs(libs, { languageDefaults: "typescriptDefaults" });
+
+    // Get the created disposable
+    const disposeMock = (
+      monaco.languages.typescript.typescriptDefaults.addExtraLib as any
+    ).mock.results[0].value.dispose;
+
+    // Call again to trigger dispose
+    setExtraLibs([], { languageDefaults: "typescriptDefaults" });
+
+    expect(disposeMock).toHaveBeenCalled();
+  });
+
+  it("should add extraLibs for typescript", () => {
+    const libs = [
+      { filePath: "test1.d.ts", content: "declare const test1: string;" },
+      { filePath: "test2.d.ts", content: "declare const test2: number;" },
+    ];
+
+    setExtraLibs(libs, { languageDefaults: "typescriptDefaults" });
+
+    expect(
+      monaco.languages.typescript.typescriptDefaults.addExtraLib
+    ).toHaveBeenCalledTimes(2);
+    expect(
+      monaco.languages.typescript.typescriptDefaults.addExtraLib
+    ).toHaveBeenCalledWith(
+      "declare const test1: string;",
+      "file://libs/test1.d.ts"
+    );
+    expect(
+      monaco.languages.typescript.typescriptDefaults.addExtraLib
+    ).toHaveBeenCalledWith(
+      "declare const test2: number;",
+      "file://libs/test2.d.ts"
+    );
+  });
+
+  it("should add extraLibs for javascript", () => {
+    const libs = [{ filePath: "test.js", content: "const test = 'hello';" }];
+
+    setExtraLibs(libs, { languageDefaults: "javascriptDefaults" });
+
+    expect(
+      monaco.languages.typescript.javascriptDefaults.addExtraLib
+    ).toHaveBeenCalledWith("const test = 'hello';", "file://libs/test.js");
+  });
+
+  it("should handle undefined libs", () => {
+    setExtraLibs(undefined, { languageDefaults: "typescriptDefaults" });
+
+    expect(
+      monaco.languages.typescript.typescriptDefaults.addExtraLib
+    ).not.toHaveBeenCalled();
+  });
+});
diff --git a/bricks/vs/src/code-editor/utils/setExtraLibs.ts b/bricks/vs/src/code-editor/utils/setExtraLibs.ts
new file mode 100644
index 000000000..bd410d7de
--- /dev/null
+++ b/bricks/vs/src/code-editor/utils/setExtraLibs.ts
@@ -0,0 +1,24 @@
+import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
+import type { ExtraLib } from "../interfaces.js";
+
+let previousDisposables: monaco.IDisposable[] | undefined;
+
+export function setExtraLibs(
+  libs: ExtraLib[] | undefined,
+  options: {
+    languageDefaults: "javascriptDefaults" | "typescriptDefaults";
+  }
+): void {
+  for (const disposable of previousDisposables ?? []) {
+    disposable.dispose();
+  }
+
+  previousDisposables = libs?.map((lib) => {
+    const uri = monaco.Uri.file(`libs/${lib.filePath}`);
+    const uriString = uri.toString();
+    return monaco.languages.typescript[options.languageDefaults].addExtraLib(
+      lib.content,
+      uriString
+    );
+  });
+}
diff --git a/jest/__mocks__/monaco-editor/esm/vs/editor/editor.api.js.js b/jest/__mocks__/monaco-editor/esm/vs/editor/editor.api.js.js
index a171f25bb..077a20537 100644
--- a/jest/__mocks__/monaco-editor/esm/vs/editor/editor.api.js.js
+++ b/jest/__mocks__/monaco-editor/esm/vs/editor/editor.api.js.js
@@ -77,6 +77,10 @@ class Editor {
     return { dispose: jest.fn() };
   }
 
+  onDidFocusEditorWidget() {
+    return { dispose: jest.fn() };
+  }
+
   layout = jest.fn();
 
   dispose = jest.fn();
diff --git a/package.json b/package.json
index 14156c504..4c98ce029 100644
--- a/package.json
+++ b/package.json
@@ -68,6 +68,7 @@
     "@types/d3-selection": "^3.0.10",
     "@types/d3-shape": "^3.1.6",
     "@types/d3-zoom": "^3.0.8",
+    "@types/diff": "^7.0.2",
     "@types/dompurify": "^3.0.5",
     "@types/file-saver": "^2.0.5",
     "@types/history": "^4.7.11",
diff --git a/shared/monaco-copilot/package.json b/shared/monaco-copilot/package.json
new file mode 100644
index 000000000..4c5edcaaf
--- /dev/null
+++ b/shared/monaco-copilot/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "@next-shared/monaco-copilot",
+  "version": "0.0.0",
+  "homepage": "https://github.com/easyops-cn/next-advanced-bricks/tree/master/shared/monaco-copilot",
+  "repository": {
+    "type": "git",
+    "url": "git@github.com:easyops-cn/next-advanced-bricks.git",
+    "directory": "shared/monaco-copilot"
+  },
+  "license": "GPL-3.0",
+  "sideEffects": false,
+  "type": "module",
+  "main": "./dist/esm/index.js",
+  "types": "./dist/types/MonacoCopilotProvider.d.ts",
+  "files": [
+    "dist"
+  ],
+  "exports": {
+    ".": {
+      "types": "./dist/types/index.d.ts",
+      "import": "./dist/esm/index.js",
+      "require": "./dist/cjs/index.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "scripts": {
+    "clean": "rimraf dist",
+    "prestart": "npm run clean",
+    "start": "concurrently -k -n types,main \"npm run start:types\" \"npm run start:main\"",
+    "start:main": "cross-env NODE_ENV=development build-next-libs --watch",
+    "start:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types --project tsconfig.build.json --watch",
+    "prebuild": "npm run clean",
+    "build": "npm run build:types && npm run build:main",
+    "build:main": "cross-env NODE_ENV=production build-next-libs",
+    "build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types --project tsconfig.build.json",
+    "test": "cross-env NODE_ENV='test' test-next",
+    "test:ci": "cross-env NODE_ENV='test' CI=true test-next"
+  },
+  "devDependencies": {
+    "monaco-editor": "^0.50.0",
+    "@next-core/build-next-libs": "^1.0.24",
+    "@next-core/test-next": "^1.1.9"
+  },
+  "dependencies": {
+    "diff": "^7.0.0"
+  },
+  "peerDependencies": {
+    "monaco-editor": "*"
+  }
+}
diff --git a/shared/monaco-copilot/src/MonacoCopilotProvider.ts b/shared/monaco-copilot/src/MonacoCopilotProvider.ts
new file mode 100644
index 000000000..85ae23c19
--- /dev/null
+++ b/shared/monaco-copilot/src/MonacoCopilotProvider.ts
@@ -0,0 +1,209 @@
+// istanbul ignore file: experimental
+import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
+import { DEFAULT_SYSTEM_PROMPT } from "./prompt.js";
+import { postProcessByDiff } from "./postProcessByDiff.js";
+
+export const SUPPORTED_LANGUAGES = Object.freeze([
+  "typescript",
+  "javascript",
+  "brick_next_yaml",
+]);
+
+export type IHttpAbortError = {
+  new (message: string): Error;
+};
+
+export type ChatRequest = (
+  options: ChatRequestOptions
+) => Promise<string | null | undefined>;
+
+export interface ChatRequestOptions {
+  model?: string;
+  temperature?: number;
+  system?: string;
+  prompt?: string;
+  signal?: AbortSignal;
+}
+
+export interface MonacoCopilotProviderOptions {
+  HttpAbortError: IHttpAbortError;
+  request: ChatRequest;
+  model?: string;
+  debounce?: number;
+  timeout?: number;
+}
+
+export class MonacoCopilotProvider
+  implements monaco.languages.InlineCompletionsProvider
+{
+  #timer: null | ReturnType<typeof setTimeout> = null;
+  #previousResolve:
+    | null
+    | ((value: monaco.languages.InlineCompletions | null) => void) = null;
+  #debounce: number;
+  #timeout: number;
+  #HttpAbortError: IHttpAbortError;
+  #request: ChatRequest;
+  #model: string;
+
+  constructor(options: MonacoCopilotProviderOptions) {
+    this.#debounce = options.debounce ?? 750;
+    this.#HttpAbortError = options.HttpAbortError;
+    this.#request = options.request;
+    this.#model = options.model ?? "qwen-coder-turbo";
+    this.#timeout = options.timeout ?? 1.2e4;
+  }
+
+  async provideInlineCompletions(
+    model: monaco.editor.IModel,
+    position: monaco.Position,
+    ctx: monaco.languages.InlineCompletionContext,
+    token: monaco.CancellationToken
+  ) {
+    const abortCtrl = new AbortController();
+
+    token.onCancellationRequested(() => {
+      abortCtrl.abort();
+    });
+
+    if (this.#timer) {
+      clearTimeout(this.#timer);
+      this.#previousResolve?.(null);
+      this.#timer = null;
+      this.#previousResolve = null;
+    }
+
+    const promise = new Promise<monaco.languages.InlineCompletions | null>(
+      (resolve) => {
+        this.#previousResolve = resolve;
+
+        this.#timer = setTimeout(async () => {
+          this.#timer = null;
+          this.#previousResolve = null;
+
+          if (token.isCancellationRequested) {
+            resolve(null);
+          }
+
+          const language = model.getLanguageId();
+          const source = model.getValue();
+          const lineContent = model.getLineContent(position.lineNumber);
+          if (
+            // Ignore empty source code.
+            source.trim().length === 0 ||
+            // For these use cases (generally end of a statement/declaration line),
+            // the AI model would not respond in time currently.
+            (position.column === model.getLineLength(position.lineNumber) + 1 &&
+              (language === "brick_next_yaml"
+                ? /\s+%>\s*$/.test(lineContent)
+                : /[;,}\]]\s*$/.test(lineContent)))
+          ) {
+            resolve(null);
+            return;
+          }
+
+          const requestTimeout = setTimeout(() => {
+            abortCtrl.abort();
+          }, this.#timeout);
+
+          try {
+            const edit = await getInlineEdit({
+              request: this.#request,
+              model: this.#model,
+              source,
+              offset: model.getOffsetAt(position),
+              language,
+              signal: abortCtrl.signal,
+            });
+
+            if (!edit) {
+              return null;
+            }
+
+            resolve({
+              enableForwardStability: true,
+              items: [
+                {
+                  insertText: edit,
+                  range: new monaco.Range(
+                    position.lineNumber,
+                    position.column,
+                    position.lineNumber,
+                    position.column
+                  ),
+                },
+              ],
+            });
+          } catch (error) {
+            if (!(error instanceof this.#HttpAbortError)) {
+              // eslint-disable-next-line no-console
+              console.error("Error fetching inline completion:", error);
+            }
+            resolve(null);
+          } finally {
+            clearTimeout(requestTimeout);
+          }
+        }, this.#debounce);
+      }
+    );
+
+    return promise;
+  }
+
+  freeInlineCompletions() {
+    // Do nothing
+  }
+}
+
+async function getInlineEdit({
+  request,
+  model,
+  source,
+  language,
+  offset,
+  signal,
+}: {
+  request: ChatRequest;
+  model: string;
+  source: string;
+  language: string;
+  offset: number;
+  signal: AbortSignal;
+}): Promise<string | null> {
+  const prefix = source.slice(0, offset);
+  const suffix = source.slice(offset);
+  const context =
+    language === "brick_next_yaml"
+      ? "# File: config.yaml\n"
+      : `// File utils.${language === "javascript" ? "js" : "ts"}\n`;
+  const content = await request({
+    model,
+    system: DEFAULT_SYSTEM_PROMPT[language],
+    prompt: `
${context}${prefix}
${suffix}
`,
+    temperature: 0.2,
+    signal,
+  });
+
+  const matches = content?.match(
+    /(?:^|\n)```(?:\w*)\n([\s\S]*?)(?:\n```(?:\n|$)|$)/
+  );
+  if (!matches) {
+    // eslint-disable-next-line no-console
+    console.error("No code block found in response.", content);
+    return null;
+  }
+
+  const response = matches[1].startsWith(context)
+    ? matches[1].slice(context.length)
+    : matches[1];
+
+  const insertText = postProcessByDiff(response, prefix, suffix);
+
+  if (insertText && /\S/.test(insertText)) {
+    return insertText;
+  }
+
+  // eslint-disable-next-line no-console
+  console.warn("Response is invalid:", content);
+  return null;
+}
diff --git a/shared/monaco-copilot/src/index.ts b/shared/monaco-copilot/src/index.ts
new file mode 100644
index 000000000..ebf023348
--- /dev/null
+++ b/shared/monaco-copilot/src/index.ts
@@ -0,0 +1 @@
+export * from "./MonacoCopilotProvider.js";
diff --git a/shared/monaco-copilot/src/postProcessByDiff.spec.ts b/shared/monaco-copilot/src/postProcessByDiff.spec.ts
new file mode 100644
index 000000000..6d44ff907
--- /dev/null
+++ b/shared/monaco-copilot/src/postProcessByDiff.spec.ts
@@ -0,0 +1,253 @@
+import { postProcessByDiff } from "./postProcessByDiff";
+
+describe("postProcessByDiff", () => {
+  test.each(
+    [
+      ["empty start", "map()", "", "", "map()"],
+      ["add new line", "abc:\n  map()", "abc:", "", "\n  map()"],
+      ["add new line with a blank line", "map()", "", "", "map()"],
+      [
+        "change inline with whitespaces",
+        "map( a => 1 )",
+        "map( ",
+        " )",
+        "a => 1",
+      ],
+      [
+        "change inline with whitespaces surrounding",
+        "map( a => 1 )",
+        " map( ",
+        " )\n",
+        "a => 1",
+      ],
+      [
+        "change inline with whitespaces surrounding 2",
+        "  map( a => 1 )",
+        " map( ",
+        " )\n",
+        "a => 1",
+      ],
+      ["multi-line addition", "map(\n  a => 1\n)", "map(", ")", "\n  a => 1\n"],
+      [
+        "multi-line original source code",
+        "map(\n  a => 1\n)",
+        "# before omitted\nabc:\n  map(",
+        ")\n# after omitted",
+        "\n    a => 1\n  ",
+      ],
+      [
+        "multi-line partial original source code",
+        `map(
+  a => 1 +
+  2 +
+  3 +
+  4 +
+  5 +
+  6 +
+  7
+)
+# after omitted`,
+        "# before omitted\n# another before omitted\nabc:\n  map(",
+        ")\n# after omitted\n# another after omitted",
+        `
+    a => 1 +
+    2 +
+    3 +
+    4 +
+    5 +
+    6 +
+    7
+  `,
+      ],
+      [
+        "multi-line original source code with insertion only",
+        `
+    a => 1 +
+    2 +
+    3 +
+    4 +
+    5 +
+    6 +
+    7
+  `,
+        "# before omitted\n# another before omitted\nabc:\n  map(",
+        ")\n# after omitted\n# another after omitted",
+        `a => 1 +
+      2 +
+      3 +
+      4 +
+      5 +
+      6 +
+      7
+    `,
+      ],
+      [
+        "multi-line original source code with lots of prefix and suffix",
+        "map(\n  a => 1\n)",
+        "# 1 omitted\n# 2 omitted\n# 3 omitted\nabc:\n  map(",
+        ")\n# after 1 omitted\n# after 2 omitted\n# after 3 omitted",
+        "\n    a => 1\n  ",
+      ],
+      [
+        "multi-line original source code with unchanged",
+        "# 3 omitted\nmap(\n  a => 1\n)\n# after 1 omitted",
+        "# 1 omitted\n# 2 omitted\n# 3 omitted\nabc:\n  map(",
+        ")\n# after 1 omitted\n# after 2 omitted\n# after 3 omitted",
+        "\n    a => 1\n  ",
+      ],
+      [
+        "added unrelated lines",
+        "# before comment\n# unrelated\nabc: 123",
+        "# before comment\nabc: ",
+        "\n# after comment",
+        "123",
+      ],
+      [
+        "indentation",
+        "name: tom\nage: 18\ngender: male",
+        "  \tname: ",
+        "\n  end",
+        "tom\n  \tage: 18\n  \tgender: male",
+      ],
+      [
+        "indentation started with blank line",
+        `function refineMetricGroups(
+  groups: Group[] | undefined,
+  metrics: Metric[]
+): Group[] | undefined {
+  // 忽略指标数量不大于 1 的分组
+  if (!groups || groups.length === 0) return [];
+
+  const metricSet = new Set(metrics.map(metric => metric.name));
+
+  return groups.filter(group => {
+    const validMetricsCount = group.metrics.filter(metric => metricSet.has(metric)).length;
+    return validMetricsCount >= 2;
+  });
+}`,
+        `function refineMetricGroups(
+  groups: Group[] | undefined,
+  metrics: Metric[]
+): Group[] | undefined {
+  // 忽略指标数量不大于 1 的分组
+  const metricSet = new Set(metrics.map(metric => metric.name));
+  `,
+        `
+}
+
+interface Group {
+  group: string;
+  metrics: string[];
+}
+
+interface Metric {
+  name: string;
+}`,
+        `\n  return groups.filter(group => {
+    const validMetricsCount = group.metrics.filter(metric => metricSet.has(metric)).length;
+    return validMetricsCount >= 2;
+  });`,
+      ],
+      [
+        "insertion only",
+        `{
+  title: "路由",
+  sort: 1,
+},
+_category_functions: {
+  title: "函数",
+  sort: 2,
+},
+_category_templates: {
+  title: "模板",
+  sort: 3,
+},
+_category_i18n: {
+  title: "国际化",
+  sort: 4,
+},
+_category_images: {
+  title: "图片",
+  sort: 5,
+}`,
+        `  let discussionsMap: Map<string, boolean> = new Map<string, boolean>();
+
+  discussions?.forEach((d) => {
+    discussionsMap[d.relatedInstanceId] =
+      !!discussionsMap[d.relatedInstanceId] || d.resolved !== true;
+  });
+  const sortTreeNode = (i, j: any): number => {
+    return (i.sort ?? 9999) - (j.sort ?? 9999);
+  };
+
+  const categoryMap: Record<string, any> = {
+    _category_basic_info: {
+      title: "基本信息",
+      sort: 0,
+    },
+    _category_routes: {`,
+        `
+  };
+
+  const iconsMap: Record<string, any> = {
+    menus: {
+      lib: "antd",
+      icon: "unordered-list",
+      theme: "outlined",
+      color: "var(--theme-cyan-color)",
+    },
+    routes: {
+      lib: "antd",
+      icon: "copy",
+      theme: "outlined",
+      color: "var(--theme-cyan-color)",
+    },
+    functions: {
+      lib: "antd",
+      icon: "function",
+      theme: "outlined",
+      color: "var(--theme-cyan-color)",
+    },
+    templates: {
+      lib: "easyops",
+      category: "default",
+      icon: "event-type",
+      color: "var(--theme-cyan-color)",
+    },
+  };`,
+        `{
+      title: "路由",
+      sort: 1,
+    },
+    _category_functions: {
+      title: "函数",
+      sort: 2,
+    },
+    _category_templates: {
+      title: "模板",
+      sort: 3,
+    },
+    _category_i18n: {
+      title: "国际化",
+      sort: 4,
+    },
+    _category_images: {
+      title: "图片",
+      sort: 5,
+    }`,
+      ],
+      [
+        "no indentation with insertion only",
+        "123,\ndef: 456,",
+        "x: 7,\ny: 8,\nz:,\nabc:",
+        "\nr: 9,\ns: 0,\nt: 1",
+        "123,\ndef: 456,",
+      ],
+    ]
+    // .filter(([desc]) => desc.includes("(only)"))
+  )("%s", (_desc, response, prefix, suffix, expected) => {
+    // console.log(_desc);
+    const result = postProcessByDiff(response, prefix, suffix);
+    expect(result).toBe(expected);
+  });
+});
diff --git a/shared/monaco-copilot/src/postProcessByDiff.ts b/shared/monaco-copilot/src/postProcessByDiff.ts
new file mode 100644
index 000000000..5e33b8286
--- /dev/null
+++ b/shared/monaco-copilot/src/postProcessByDiff.ts
@@ -0,0 +1,214 @@
+import { diffLines, type Change } from "diff";
+
+type ChangeAction = "added" | "removed" | "unchanged";
+
+/**
+ * Post process the response from AI to get the insertion text around the cursor.
+ *
+ * The AI response may:
+ * 1) contains full original source code combined with the insertions (as well as insertions outside the cursor).
+ * 2) contains the insertions with several lines of source code as context before and after the cursor.
+ * 3) contains only the insertions.
+ *
+ * @param response The AI response text to be post-processed.
+ * @param originalPrefix The original source code before the cursor.
+ * @param originalSuffix The original source code after the cursor.
+ * @returns The processed insertion text or null if no valid insertion is found.
+ */
+export function postProcessByDiff(
+  response: string,
+  originalPrefix: string,
+  originalSuffix: string
+): string | null {
+  const trimmedResponse = response.replace(/^\n+|\n+$/g, "");
+  const trimmedOriginalPrefix = originalPrefix.replace(/^\n+/g, "");
+  const trimmedOriginalSuffix = originalSuffix.replace(/\n+$/g, "");
+  const responseLines = trimmedResponse.split("\n");
+  const trimmedPrefixLines = trimmedOriginalPrefix.split("\n");
+  const trimmedSuffixLines = trimmedOriginalSuffix.split("\n");
+  const cursorLineNumber = trimmedPrefixLines.length;
+
+  const diffLinesOffset = Math.max(
+    0,
+    trimmedPrefixLines.length - responseLines.length
+  );
+  const truncatedPrefix =
+    diffLinesOffset > 0
+      ? trimmedPrefixLines.slice(diffLinesOffset).join("\n")
+      : trimmedOriginalPrefix;
+  const truncatedSuffix =
+    trimmedSuffixLines.length > responseLines.length
+      ? trimmedSuffixLines.slice(0, responseLines.length).join("\n")
+      : trimmedOriginalSuffix;
+  const truncatedSource = `${truncatedPrefix}${truncatedSuffix}`;
+
+  // First, find out the insertion by comparing the diff, this resolves situation 1) and 2).
+  const changes = diffLines(truncatedSource, trimmedResponse, {
+    ignoreWhitespace: true,
+  }) as Required<Change>[];
+
+  let oldLineIndex = diffLinesOffset;
+  let afterCursor = false;
+  let lastAction: ChangeAction = "unchanged";
+  for (let i = 0; i < changes.length; i++) {
+    const change = changes[i];
+    lastAction = change.removed
+      ? "removed"
+      : change.added
+        ? "added"
+        : "unchanged";
+    const nextChange = changes[i + 1];
+    const nextAction = nextChange?.removed
+      ? "removed"
+      : nextChange?.added
+        ? "added"
+        : "unchanged";
+    if (lastAction !== "added") {
+      oldLineIndex += change.count;
+    } else if (i === 0 && changes.length === 1) {
+      oldLineIndex++;
+    }
+    if (!afterCursor) {
+      afterCursor = oldLineIndex >= cursorLineNumber;
+      if (afterCursor) {
+        const offset = oldLineIndex - cursorLineNumber;
+        if (
+          (lastAction === "unchanged" &&
+            offset === 0 &&
+            nextAction === "added") ||
+          (lastAction === "added" && offset === 0) ||
+          (lastAction === "removed" && nextAction === "added")
+        ) {
+          const update = lastAction === "added" ? change : nextChange;
+          const fullFixedUpdateValue = `${
+            lastAction === "unchanged"
+              ? `${change.value.replace(/\n$/, "").split("\n").pop()!}\n`
+              : ""
+          }${update.value.replace(/\n$/, "")}`;
+          const updatedLines = fullFixedUpdateValue.split("\n");
+          const lastUpdatedLine = updatedLines[updatedLines.length - 1];
+          // Original
+          const originalLinePrefix = trimmedPrefixLines[cursorLineNumber - 1];
+          const originalLineSuffix = trimmedSuffixLines[0];
+
+          const {
+            trimmed: lastUpdatedLineTrimmed,
+            trailing: lastUpdatedLineTrailing,
+          } = trimWithInfo(lastUpdatedLine);
+          const {
+            trimmed: originalLinePrefixTrimmed,
+            leading: originalLinePrefixLeading,
+            trailing: originalLinePrefixTrailing,
+          } = trimWithInfo(originalLinePrefix);
+          const {
+            trimmed: originalLineSuffixTrimmed,
+            leading: originalLineSuffixLeading,
+          } = trimWithInfo(originalLineSuffix);
+
+          for (let j = 0; j < updatedLines.length; j++) {
+            const firstUpdatedLine = updatedLines[j];
+            const {
+              trimmed: firstUpdatedLineTrimmed,
+              leading: firstUpdatedLineLeading,
+            } = trimWithInfo(firstUpdatedLine);
+            if (
+              firstUpdatedLineTrimmed.startsWith(originalLinePrefixTrimmed) &&
+              lastUpdatedLineTrimmed.endsWith(originalLineSuffixTrimmed)
+            ) {
+              const fixedUpdateValue = updatedLines.slice(j).join("\n");
+              const start =
+                firstUpdatedLineLeading.length +
+                originalLinePrefixTrimmed.length;
+              const end =
+                fixedUpdateValue.length -
+                (lastUpdatedLineTrailing.length +
+                  originalLineSuffixTrimmed.length);
+              const restUpdate = fixedUpdateValue.slice(start, end);
+              const {
+                leading: restUpdateLeading,
+                trailing: restUpdateTrailing,
+              } = trimWithInfo(restUpdate);
+
+              const insertText = restUpdate.slice(
+                Math.min(
+                  restUpdateLeading.length,
+                  originalLinePrefixTrailing.length
+                ),
+                restUpdate.length -
+                  Math.min(
+                    restUpdateTrailing.length,
+                    originalLineSuffixLeading.length
+                  )
+              );
+
+              if (
+                originalLinePrefixLeading.length >
+                  firstUpdatedLineLeading.length &&
+                firstUpdatedLineTrimmed.length > 0 &&
+                originalLinePrefixTrimmed.length > 0 &&
+                originalLinePrefixLeading.startsWith(firstUpdatedLineLeading)
+              ) {
+                const leadingSpaces = originalLinePrefixLeading.slice(
+                  firstUpdatedLineLeading.length
+                );
+                return insertText
+                  .split("\n")
+                  .map((line, index) =>
+                    index === 0 ? line : `${leadingSpaces}${line}`
+                  )
+                  .join("\n");
+              }
+
+              return insertText;
+            }
+          }
+        }
+        break;
+      }
+    }
+  }
+
+  // Maybe the response is insertion only, that's the situation 3).
+  // TODO: check whether it's syntax correct after the insertion?
+  const unchangedCount = changes
+    .filter((change) => !(change.added || change.removed))
+    .reduce((acc, change) => acc + change.count, 0);
+  const truncatedLines = truncatedSource.split("\n");
+  if (unchangedCount / truncatedLines.length < 0.2) {
+    const insertText = trimmedResponse.trimStart();
+    // Keep the original indentation.
+    const leadingSpaces =
+      trimmedPrefixLines[trimmedPrefixLines.length - 1].match(/^\s+/)?.[0] ??
+      "";
+    return leadingSpaces
+      ? insertText
+          .split("\n")
+          .map((line, index) =>
+            index === 0 ? line : `${leadingSpaces}${line}`
+          )
+          .join("\n")
+      : insertText;
+  }
+
+  return null;
+}
+
+function trimWithInfo(content: string): {
+  trimmed: string;
+  leading: string;
+  trailing: string;
+} {
+  let leading = "";
+  let trailing = "";
+  const trimmed = content
+    .replace(/^\s+/, (match) => {
+      leading = match;
+      return "";
+    })
+    .replace(/\s+$/, (match) => {
+      trailing = match;
+      return "";
+    });
+
+  return { trimmed, leading, trailing };
+}
diff --git a/shared/monaco-copilot/src/prompt.ts b/shared/monaco-copilot/src/prompt.ts
new file mode 100644
index 000000000..8388d16cf
--- /dev/null
+++ b/shared/monaco-copilot/src/prompt.ts
@@ -0,0 +1,22 @@
+// istanbul ignore file
+export const DEFAULT_SYSTEM_PROMPT: Record<string, string> = {
+  brick_next_yaml: `你是一个编程助手，主要用于 Visual Builder 中的 YAML 配置的代码补全。
+
+YAML 中可以使用 \`<% %>\` 嵌入 JS 表达式，例如：
+
+${"```yaml"}yaml
+groups: <% _.groupBy(CTX.hosts, "idc") %>
+${"```"}
+
+JS 表达式中可以使用 lodash (\`_\`) 和 moment。
+
+提供简洁易读的代码补全，语法和逻辑准确，与现有上下文无缝集成，格式优雅。如果要添加注释，不要放在行尾部，应该单独成行。`,
+  javascript: getDefaultSystemPrompt("JavaScript"),
+  typescript: getDefaultSystemPrompt("TypeScript"),
+};
+
+function getDefaultSystemPrompt(language: "JavaScript" | "TypeScript"): string {
+  return `你是一个编程助手，主要用于 Visual Builder 中的 ${language} 函数的代码补全。
+
+提供简洁易读的代码补全，语法和逻辑准确，与现有上下文无缝集成，格式优雅。如果要添加注释，不要放在行尾部，应该单独成行。`;
+}
diff --git a/shared/monaco-copilot/tsconfig.build.json b/shared/monaco-copilot/tsconfig.build.json
new file mode 100644
index 000000000..1f6ff8774
--- /dev/null
+++ b/shared/monaco-copilot/tsconfig.build.json
@@ -0,0 +1,4 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": ["**/*.spec.*", "**/__mocks__/", "**/__fixtures__/"]
+}
diff --git a/shared/monaco-copilot/tsconfig.json b/shared/monaco-copilot/tsconfig.json
new file mode 100644
index 000000000..473e9688a
--- /dev/null
+++ b/shared/monaco-copilot/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "extends": "../../tsconfig.module.json",
+  "compilerOptions": {
+    "outDir": "./dist"
+  },
+  "include": ["./src/"]
+}
diff --git a/yarn.lock b/yarn.lock
index 076447321..bea573ba2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2904,6 +2904,13 @@
   dependencies:
     "@next-core/http" "^1.0.6"
 
+"@next-api-sdk/llm-sdk@^1.1.3":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@next-api-sdk/llm-sdk/-/llm-sdk-1.1.3.tgz#6a30c9717ad5a3b89969b4e9dc87013a4c5885bd"
+  integrity sha512-xQQJhuymgb2FTQLy10qQuRoJb2lvuEcRHh7bmktAIFvoe9a7uC5JeBi2oCktaTBSEdFCySoUT+jEQKoehC79WA==
+  dependencies:
+    "@next-core/http" "^1.2.12"
+
 "@next-api-sdk/micro-app-sdk@^1.2.1":
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/@next-api-sdk/micro-app-sdk/-/micro-app-sdk-1.2.1.tgz#b3879de5e3b06e698c003d7eb4919392b3d710c6"
@@ -4405,6 +4412,11 @@
   dependencies:
     "@types/ms" "*"
 
+"@types/diff@^7.0.2":
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/@types/diff/-/diff-7.0.2.tgz#d638edebf3c97aa4962b6f1164a7921ab3de9f83"
+  integrity sha512-JSWRMozjFKsGlEjiiKajUjIJVKuKdE3oVy2DNtK+fUo8q82nhFZ2CPQwicAIkXrofahDXrWJ7mjelvZphMS98Q==
+
 "@types/dompurify@^3.0.5":
   version "3.0.5"
   resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.5.tgz#02069a2fcb89a163bacf1a788f73cb415dd75cb7"
@@ -7728,6 +7740,11 @@ diff@^5.0.0:
   resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40"
   integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==
 
+diff@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a"
+  integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==
+
 diffie-hellman@^5.0.0:
   version "5.0.3"
   resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR introduces a new Monaco Editor Copilot feature that provides inline code completions using an LLM interface. It adds new modules for prompt generation, diff postprocessing, and a copilot provider implementation; integrates these components into the editor environment; and updates documentation and build configurations accordingly.

### Reviewed Changes

Copilot reviewed 13 out of 18 changed files in this pull request and generated 2 comments.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| shared/monaco-copilot/src/prompt.ts | Adds default system prompts for various languages |
| shared/monaco-copilot/src/postProcessByDiff.ts | Implements logic to extract inline edits via diff analysis |
| shared/monaco-copilot/src/postProcessByDiff.spec.ts | Introduces unit tests ensuring post-processing accuracy |
| shared/monaco-copilot/src/MonacoCopilotProvider.ts | Provides an inline completions provider using the new copilot |
| bricks/vs/src/code-editor/utils/setExtraLibs.ts | Sets extra libraries for the editor based on configuration |
| bricks/vs/src/code-editor/utils/getInlineEdit.ts | Implements inline edit retrieval from the LLM response |
| bricks/vs/src/code-editor/utils/EditorService.ts | Manages editor instance state and disposal |
| bricks/vs/src/code-editor/utils/CopilotProvider.ts | Offers an alternative inline completions provider implementation |
| bricks/vs/src/code-editor/index.tsx | Integrates the copilot in the main code-editor component |
| bricks/vs/docs/code-editor.md | Updates documentation with new marker and extraLibs configurations |
| bricks/vs/build.config.js | Adds a rule to load .txt files as source assets |
</details>


<details>
<summary>Files not reviewed (5)</summary>

* **bricks/vs/package.json**: Language not supported
* **package.json**: Language not supported
* **shared/monaco-copilot/package.json**: Language not supported
* **shared/monaco-copilot/tsconfig.build.json**: Language not supported
* **shared/monaco-copilot/tsconfig.json**: Language not supported
</details>



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T03:31:21Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request introduces a new inline completion provider ("monaco editor copilot") for the Monaco Editor, enabling improved code completion with context-aware hints based on AI responses. Key changes include:
- Adding default system prompts and a helper function for YAML, JavaScript, and TypeScript via the new prompt.ts module.
- Implementing diff-based post processing of AI responses along with comprehensive unit tests.
- Introducing MonacoCopilotProvider and integrating it into the existing code editor along with supporting utilities and updated documentation.

### Reviewed Changes

Copilot reviewed 16 out of 21 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| shared/monaco-copilot/src/prompt.ts | Defines default system prompts for various languages. |
| shared/monaco-copilot/src/postProcessByDiff.ts | Implements diff parsing to extract the inserted text from AI responses. |
| shared/monaco-copilot/src/postProcessByDiff.spec.ts | Adds unit tests for diff post processing behavior. |
| shared/monaco-copilot/src/MonacoCopilotProvider.ts | Provides an inline completions provider integrating with the AI. |
| jest/__mocks__/monaco-editor/esm/vs/editor/editor.api.js.js | Extends editor API mocks with additional focus event support. |
| bricks/vs/src/code-editor/utils/setExtraLibs.ts (+spec) | Introduces and tests a new utility to manage extra libraries. |
| bricks/vs/src/code-editor/(addExtraLibs.ts, addExtraLibs.spec.ts) | Removes the outdated extra lib addition functions. |
| bricks/vs/src/code-editor/utils/EditorService.ts | Adds helper functions for managing the current editor instance. |
| bricks/vs/src/code-editor/index.tsx | Integrates the new MonacoCopilotProvider and extra libs functionality. |
| bricks/vs/docs/code-editor.md | Updates documentation to reflect new markers and extra libs usage. |
| bricks/vs/build.config.js | Updates webpack configuration for txt asset support. |
</details>


<details>
<summary>Files not reviewed (5)</summary>

* **bricks/vs/package.json**: Language not supported
* **package.json**: Language not supported
* **shared/monaco-copilot/package.json**: Language not supported
* **shared/monaco-copilot/tsconfig.build.json**: Language not supported
* **shared/monaco-copilot/tsconfig.json**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**bricks/vs/docs/code-editor.md:139**
* Correct the typo 'basicUsige' to 'basicUsage' to ensure consistency in the documentation.
```
basicUsige:
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T03:59:23Z

Review comments:
diff_hunk: @@ -88,13 +88,55 @@ children:
 
 ```yaml preview
 - brick: vs.code-editor
+  context:
+    - name: commonMarkers
+      value:
+        - token: PATH
+          message: “这是 PATH”
+          level: hit
+        - token: QUERY
+          message: “这是 QUERY”
+          level: info
+        - token: ANCHOR
+          message: “这是 ANCHOR“
path: bricks/vs/docs/code-editor.md
user: login: Copilot
body: The marker message for token 'ANCHOR' uses mismatched quotes. Please use matching quotation marks (e.g., “这是 ANCHOR”) to ensure consistency.
```suggestion
          message: “这是 ANCHOR”
```
created_at: 2025-03-31T03:31:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,172 @@
+import { AiopsBaseApi_openaiChat } from "@next-api-sdk/llm-sdk";
+
+export interface InlineEditResult {
+  insertText: string;
+  prefixOffset: number;
+  suffixOffset: number;
+}
+
+export async function getInlineEdit({
+  source,
+  language,
+  offset,
+  signal,
+}: {
+  source: string;
+  language: string;
+  offset: number;
+  signal: AbortSignal;
+}): Promise<InlineEditResult | null> {
+  const prefix = source.slice(0, offset);
+  const suffix = source.slice(offset);
+  const context =
+    language === "brick_next_yaml"
+      ? "# File: props.yaml\n"
+      : `// File utils.${language === "javascript" ? "js" : "ts"}\n`;
+  const response = await AiopsBaseApi_openaiChat(
+    {
+      // model: "qwen-turbo",
+      // model: "qwen-plus",
+      model: "qwen-coder-turbo",
+      // model: "claude-3-5-sonnet-latest",
+      enableSensitiveWordsFilter: false,
+      stream: false,
+      temperature: 0.2,
+      messages: [
+        {
+          role: "system",
+          content:
+            language === "brick_next_yaml"
+              ? `你是一个编程助手，主要用于 Visual Builder 中的 YAML 配置的代码补全。
+
+YAML 中可以使用 \`<% %>\` 嵌入 JS 表达式，例如：
+
+${"```yaml"}yaml
+groups: <% _.groupBy(CTX.hosts, "idc") %>
+${"```"}
+
+JS 表达式中可以使用 lodash (\`_\`) 和 moment。
+
+提供简洁易读的代码补全，语法和逻辑准确，与现有上下文无缝集成，格式优雅。如果要添加注释，不要放在行尾部，应该单独成行。`
+              : `你是一个编程助手，主要用于 Visual Builder 中的 ${language === "typescript" ? "TypeScript" : "JavaScript"} 函数的代码补全。
+
+提供简洁易读的代码补全，语法和逻辑准确，与现有上下文无缝集成，格式优雅。如果要添加注释，不要放在行尾部，应该单独成行。`,
+        },
+        {
+          role: "user",
+          content: `
${context}${prefix}
${suffix}
`,
+        },
+      ],
+    },
+    {
+      signal,
+      interceptorParams: {
+        ignoreLoadingBar: true,
+      },
+    }
+  );
+
+  const content = response.choices?.[0]?.message?.content?.trim();
+  if (content) {
+    const matches = content.match(
+      /(?:^|\n)```(?:\w*)\n([\s\S]*?)(?:\n```(?:\n|$)|$)/
+    );
+    if (matches) {
+      const full = matches[1].startsWith(context)
+        ? matches[1].slice(context.length)
+        : matches[1];
+      const trimmedFull = full.trim();
+      const trimmedPrefix = prefix.trimStart();
+      const trimmedSuffix = suffix.trimEnd();
+      // Case 1: responded with full source code.
+      if (
+        trimmedFull.startsWith(trimmedPrefix) &&
+        trimmedFull.endsWith(trimmedSuffix)
+      ) {
+        const insertText = trimmedFull.slice(
+          trimmedPrefix.length,
+          trimmedFull.length - trimmedSuffix.length
+        );
+        if (/\S/.test(insertText)) {
+          return {
+            insertText,
+            prefixOffset: 0,
+            suffixOffset: 0,
+          };
+        }
+        // eslint-disable-next-line no-console
+        console.log("Empty insertText");
+        return null;
+      }
+
+      // Case 2: responded with prefix source code only.
+      const allTrimmedPrefix = trimmedPrefix.trimEnd();
+      if (
+        trimmedFull.length === allTrimmedPrefix.length &&
+        trimmedFull === allTrimmedPrefix
+      ) {
+        // eslint-disable-next-line no-console
+        console.log("Empty insertText");
+        return null;
+      }
+
+      const prefixLastLine = prefix.slice(prefix.lastIndexOf("\n") + 1);
+      const trimmedPrefixLastLine = prefixLastLine.trimStart();
+      const insertLeadingSpaces = full.match(/^\s+/)?.[0] ?? "";
+      const prefixLeadingSpaces = prefixLastLine.match(/^\s+/)?.[0] ?? "";
+      const leadingSpaces =
+        insertLeadingSpaces.length >= prefixLeadingSpaces.length
+          ? ""
+          : prefixLeadingSpaces.startsWith(insertLeadingSpaces)
+            ? prefixLeadingSpaces.slice(insertLeadingSpaces.length)
+            : prefixLeadingSpaces;
+
+      // Case 3: responded with partial source code.
+      if (trimmedFull.startsWith(trimmedPrefixLastLine)) {
+        // Case 3.1: with original content for the current line.
+        const insertText = trimmedFull
+          .split("\n")
+          .map((line, index) =>
+            index === 0 ? line : `${leadingSpaces}${line}`
+          )
+          .join("\n");
+
+        if (/\S/.test(insertText)) {
+          return {
+            insertText,
+            prefixOffset: trimmedPrefixLastLine.length,
+            suffixOffset: 0,
+          };
+        }
+      } else if (trimmedFull.length < source.length / 2) {
+        // Spacial detection: returned code is way more less than the original code.
path: bricks/vs/src/code-editor/utils/getInlineEdit.ts
user: login: Copilot
body: Typo in comment: 'Spacial detection' should be corrected to 'Special detection'.
```suggestion
        // Special detection: returned code is way more less than the original code.
```
created_at: 2025-03-31T03:31:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-31T04:09:58Z
body: ## [Codecov](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) Report
Attention: Patch coverage is `81.51261%` with `22 lines` in your changes missing coverage. Please review.
> Project coverage is 85.07%. Comparing base [(`0fc95e1`)](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/commit/0fc95e18615967f82b188041c30fbe3d8d79e0df?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) to head [(`d4bc041`)](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/commit/d4bc04159bfd25badbb490132d61e84f7a0ad133?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn).
> Report is 5 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) | Patch % | Lines |
|---|---|---|
| [bricks/vs/src/code-editor/index.tsx](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=bricks%2Fvs%2Fsrc%2Fcode-editor%2Findex.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-YnJpY2tzL3ZzL3NyYy9jb2RlLWVkaXRvci9pbmRleC50c3g=) | 47.61% | [8 Missing and 3 partials :warning: ](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) |
| [bricks/vs/src/code-editor/utils/EditorService.ts](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=bricks%2Fvs%2Fsrc%2Fcode-editor%2Futils%2FEditorService.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-YnJpY2tzL3ZzL3NyYy9jb2RlLWVkaXRvci91dGlscy9FZGl0b3JTZXJ2aWNlLnRz) | 46.15% | [6 Missing and 1 partial :warning: ](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) |
| [shared/monaco-copilot/src/postProcessByDiff.ts](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=shared%2Fmonaco-copilot%2Fsrc%2FpostProcessByDiff.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-c2hhcmVkL21vbmFjby1jb3BpbG90L3NyYy9wb3N0UHJvY2Vzc0J5RGlmZi50cw==) | 94.87% | [1 Missing and 3 partials :warning: ](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) |

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84/graphs/tree.svg?width=650&height=150&src=pr&token=clagOcXtXR&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn)](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn)

```diff
@@            Coverage Diff             @@
##           master      #84      +/-   ##
==========================================
+ Coverage   85.05%   85.07%   +0.01%     
==========================================
  Files         410      416       +6     
  Lines       13486    13657     +171     
  Branches     2119     2159      +40     
==========================================
+ Hits        11471    11619     +148     
- Misses       1641     1656      +15     
- Partials      374      382       +8     
```

| [Files with missing lines](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn) | Coverage Δ | |
|---|---|---|
| [bricks/vs/src/code-editor/utils/setExtraLibs.ts](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=bricks%2Fvs%2Fsrc%2Fcode-editor%2Futils%2FsetExtraLibs.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-YnJpY2tzL3ZzL3NyYy9jb2RlLWVkaXRvci91dGlscy9zZXRFeHRyYUxpYnMudHM=) | `100.00% <100.00%> (ø)` | |
| [shared/monaco-copilot/src/postProcessByDiff.ts](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=shared%2Fmonaco-copilot%2Fsrc%2FpostProcessByDiff.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-c2hhcmVkL21vbmFjby1jb3BpbG90L3NyYy9wb3N0UHJvY2Vzc0J5RGlmZi50cw==) | `94.87% <94.87%> (ø)` | |
| [bricks/vs/src/code-editor/utils/EditorService.ts](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=bricks%2Fvs%2Fsrc%2Fcode-editor%2Futils%2FEditorService.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-YnJpY2tzL3ZzL3NyYy9jb2RlLWVkaXRvci91dGlscy9FZGl0b3JTZXJ2aWNlLnRz) | `46.15% <46.15%> (ø)` | |
| [bricks/vs/src/code-editor/index.tsx](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84?src=pr&el=tree&filepath=bricks%2Fvs%2Fsrc%2Fcode-editor%2Findex.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn#diff-YnJpY2tzL3ZzL3NyYy9jb2RlLWVkaXRvci9pbmRleC50c3g=) | `58.63% <47.61%> (-2.29%)` | :arrow_down: |

... and [16 files with indirect coverage changes](https://app.codecov.io/gh/easyops-cn/next-advanced-bricks/pull/84/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=easyops-cn)

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-31T04:11:36Z
body: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY - APP ID SHA256: 3076a3b1c583bf5b64521d8d9db1dbd879b28184b5854b3b4190ea51d4dd61e3 -->
🚀 Deployed on https://docs-preview-84--next-advanced-bricks.netlify.app
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-31T04:15:28Z
body: 📐🤏 Size check result (b68fefad20cf51a484751dfce6179151405a3794...abc521afe0b90e599188dd323c322be5eaa39f69):

[See full diff](https://size-checker.shenwei.xyz/api/compare/easyops-cn--next-advanced-bricks/b68fefad20cf51a484751dfce6179151405a3794/abc521afe0b90e599188dd323c322be5eaa39f69.diff)

## Load all bricks together

| Name | Prev | Now | Diff |
| - | - | - | - |
| All bricks | 4,418.41 KB | 4,423.76 KB | 🔺 +5.35 KB |

Critical changes:

| Name | Prev | Now | Diff |
| - | - | - | - |
| vs | 843.6 KB | 848.84 KB | 🔺 +5.24 KB |

<details>

<summary>See full changes</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| &lt;core&gt; | 316.86 KB | 316.85 KB | ≈ |
| &lt;react&gt; | 55.06 KB | 55.06 KB | 🟰 |
| advanced | 521.17 KB | 521.18 KB | ≈ |
| ai | 288.23 KB | 288.28 KB | ≈ |
| api-market | 10.59 KB | 10.59 KB | 🟰 |
| basic | 101.22 KB | 101.22 KB | 🟰 |
| containers | 95.6 KB | 95.6 KB | 🟰 |
| data-view | 642.94 KB | 642.98 KB | ≈ |
| diagram | 179.84 KB | 179.81 KB | ≈ |
| form | 324.91 KB | 324.94 KB | ≈ |
| form-platform | 12.7 KB | 12.7 KB | 🟰 |
| icons | 66.16 KB | 66.16 KB | 🟰 |
| illustrations | 17.45 KB | 17.45 KB | 🟰 |
| inject | 56.26 KB | 56.26 KB | 🟰 |
| markdown | 249.37 KB | 249.33 KB | ≈ |
| mini-chart | 16.05 KB | 16.05 KB | 🟰 |
| nav | 121.66 KB | 121.65 KB | ≈ |
| presentational | 135.66 KB | 135.65 KB | ≈ |
| recent-history | 33.18 KB | 33.18 KB | 🟰 |
| shoelace | 196.07 KB | 196.07 KB | 🟰 |
| visual-builder | 450.7 KB | 450.78 KB | ≈ |
| vs | 843.6 KB | 848.84 KB | 🔺 +5.24 KB |

</details>

## Load bricks by each package

Critical changes:

| Name | Prev | Now | Diff |
| - | - | - | - |
| advanced | 842.52 KB | 896 KB | 🔺 +53.48 KB |
| api-market | 333.18 KB | 385.78 KB | 🔺 +52.6 KB |
| visual-builder | 1,641.95 KB | 1,647.04 KB | 🔺 +5.09 KB |
| vs | 1,140.72 KB | 1,145.93 KB | 🔺 +5.21 KB |

<details>

<summary>See full changes</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| advanced | 842.52 KB | 896 KB | 🔺 +53.48 KB |
| ai | 598.11 KB | 598.19 KB | ≈ |
| api-market | 333.18 KB | 385.78 KB | 🔺 +52.6 KB |
| basic | 422.59 KB | 422.59 KB | 🟰 |
| containers | 252.52 KB | 252.52 KB | 🟰 |
| data-view | 800.12 KB | 800.21 KB | ≈ |
| diagram | 263.19 KB | 263.19 KB | 🟰 |
| form | 678.35 KB | 678.37 KB | ≈ |
| form-platform | 367.82 KB | 367.85 KB | ≈ |
| icons | 123.76 KB | 123.76 KB | 🟰 |
| illustrations | 143.73 KB | 143.73 KB | 🟰 |
| inject | 56.26 KB | 56.26 KB | 🟰 |
| markdown | 446.07 KB | 446.14 KB | ≈ |
| mini-chart | 81.64 KB | 81.64 KB | 🟰 |
| nav | 477.43 KB | 477.43 KB | 🟰 |
| presentational | 445.25 KB | 445.28 KB | ≈ |
| recent-history | 312.28 KB | 312.28 KB | 🟰 |
| shoelace | 196.11 KB | 196.07 KB | ≈ |
| visual-builder | 1,641.95 KB | 1,647.04 KB | 🔺 +5.09 KB |
| vs | 1,140.72 KB | 1,145.93 KB | 🔺 +5.21 KB |
| widget-editors | 0 KB | 0 KB | 🟰 |

</details>

<details>

<summary>Critical details for package advanced</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| &lt;react&gt; | 55.06 KB | 110.11 KB | 🔺 +55.05 KB |
| &lt;self&gt; | 521.18 KB | 518.63 KB | 🟢 -2.55 KB |
| basic | 49.57 KB | 42.49 KB | 🟢 -7.08 KB |
| form | 33.54 KB | 41.59 KB | 🔺 +8.05 KB |

</details>

<details>

<summary>Critical details for package api-market</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| &lt;react&gt; | 55.06 KB | 110.11 KB | 🔺 +55.05 KB |
| nav | 17.75 KB | 15.25 KB | 🟢 -2.5 KB |
| shoelace | 117.01 KB | 117.05 KB | ≈ |

</details>

<details>

<summary>Critical details for package visual-builder</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| &lt;self&gt; | 461.35 KB | 461.33 KB | ≈ |
| shoelace | 118.04 KB | 118.03 KB | ≈ |
| vs | 843.62 KB | 848.74 KB | 🔺 +5.12 KB |

</details>

<details>

<summary>Critical details for package vs</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| &lt;self&gt; | 854.21 KB | 859.38 KB | 🔺 +5.17 KB |
| form | 17.89 KB | 17.9 KB | ≈ |
| shoelace | 115.03 KB | 115.07 KB | ≈ |

</details>

## Load by each brick

Critical changes:

| Name | Prev | Now | Diff |
| - | - | - | - |
| eo-date-picker | 284.49 KB | 338.76 KB | 🔺 +54.27 KB |
| eo-directory-tree | 169.14 KB | 167.45 KB | 🟢 -1.69 KB |
| eo-input | 196.71 KB | 142.47 KB | 🟢 -54.24 KB |
| eo-switch | 147.97 KB | 202.22 KB | 🔺 +54.25 KB |
| form.general-checkbox | 212.36 KB | 158.11 KB | 🟢 -54.25 KB |
| form.general-switch | 147.97 KB | 202.22 KB | 🔺 +54.25 KB |
| visual-builder.property-editor | 1,432.6 KB | 1,437.92 KB | 🔺 +5.32 KB |
| vs.code-editor | 1,140.64 KB | 1,145.91 KB | 🔺 +5.27 KB |

<details>

<summary>See full changes</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| advanced.capture-snapshot | 52.36 KB | 52.36 KB | 🟰 |
| advanced.general-cascader | 269.67 KB | 269.67 KB | 🟰 |
| advanced.general-table | 381.19 KB | 381.29 KB | 🔼 +0.1 KB |
| advanced.pdf-viewer | 200.99 KB | 200.99 KB | 🟰 |
| ai.chat-agent | 67.69 KB | 67.69 KB | 🟰 |
| ai.chat-view | 593.31 KB | 593.29 KB | ≈ |
| api-market.apis-directory-tree | 333.21 KB | 333.22 KB | ≈ |
| basic.active-element-blur | 8.57 KB | 8.57 KB | 🟰 |
| basic.change-language | 8.56 KB | 8.56 KB | 🟰 |
| basic.copy-to-clipboard | 8.72 KB | 8.72 KB | 🟰 |
| basic.dropdown-button | 280.72 KB | 280.76 KB | ≈ |
| basic.general-button | 152.86 KB | 152.86 KB | 🟰 |
| basic.general-image | 148.41 KB | 148.41 KB | 🟰 |
| basic.general-link | 267.91 KB | 267.89 KB | ≈ |
| basic.general-menu | 78.34 KB | 78.34 KB | 🟰 |
| basic.general-menu-item | 144.77 KB | 144.77 KB | 🟰 |
| basic.general-popover | 195.22 KB | 195.22 KB | 🟰 |
| basic.general-tag | 146.72 KB | 146.72 KB | 🟰 |
| basic.general-tag-list | 148.81 KB | 148.81 KB | 🟰 |
| basic.general-text | 352.3 KB | 352.31 KB | ≈ |
| basic.get-language | 8.55 KB | 8.55 KB | 🟰 |
| basic.home-redirect | 23.59 KB | 23.59 KB | 🟰 |
| basic.http-proxy-request | 8.63 KB | 8.63 KB | 🟰 |
| basic.http-request | 8.55 KB | 8.55 KB | 🟰 |
| basic.lock-body-scroll | 23.28 KB | 23.28 KB | 🟰 |
| basic.set-theme-by-apps | 8.57 KB | 8.57 KB | 🟰 |
| basic.set-timeout | 8.56 KB | 8.56 KB | 🟰 |
| basic.show-dialog | 340.84 KB | 340.84 KB | 🟰 |
| basic.show-notification | 267.89 KB | 267.89 KB | 🟰 |
| basic.show-watermark | 10.3 KB | 10.3 KB | 🟰 |
| basic.v3-widget-mate | 8.54 KB | 8.54 KB | 🟰 |
| containers.easy-view | 67.04 KB | 67.04 KB | 🟰 |
| containers.flex-layout | 66.78 KB | 66.78 KB | 🟰 |
| containers.general-card | 164.53 KB | 164.53 KB | 🟰 |
| containers.general-category | 67.4 KB | 67.4 KB | 🟰 |
| containers.general-drawer | 158.34 KB | 158.37 KB | ≈ |
| containers.general-modal | 165.18 KB | 165.18 KB | 🟰 |
| containers.grid-layout | 67.88 KB | 67.88 KB | 🟰 |
| containers.micro-view | 87.94 KB | 87.94 KB | 🟰 |
| containers.search-bar | 66.9 KB | 66.9 KB | 🟰 |
| containers.tab-group | 72.1 KB | 72.1 KB | 🟰 |
| containers.tab-item | 159.93 KB | 159.93 KB | 🟰 |
| containers.tab-list | 159.93 KB | 159.93 KB | 🟰 |
| data-view.app-wall-card-item | 70.04 KB | 70.04 KB | 🟰 |
| data-view.app-wall-relation-line | 69.71 KB | 69.71 KB | 🟰 |
| data-view.app-wall-system-card | 136.31 KB | 136.23 KB | ≈ |
| data-view.basic-index-group | 69.32 KB | 69.33 KB | ≈ |
| data-view.battery-chart | 70.04 KB | 70.05 KB | ≈ |
| data-view.brick-notification | 135.51 KB | 135.43 KB | ≈ |
| data-view.bubbles-indicator | 169.21 KB | 169.21 KB | 🟰 |
| data-view.cabinet-app-layer | 69.71 KB | 69.71 KB | 🟰 |
| data-view.cabinet-button | 69.3 KB | 69.3 KB | 🟰 |
| data-view.cabinet-container | 79.54 KB | 79.55 KB | ≈ |
| data-view.cabinet-graph | 93.67 KB | 93.68 KB | ≈ |
| data-view.cabinet-node | 70.12 KB | 70.12 KB | 🟰 |
| data-view.cabinet-thumbnail | 83.39 KB | 83.4 KB | ≈ |
| data-view.china-map | 147.66 KB | 147.66 KB | 🟰 |
| data-view.china-map-chart | 379.08 KB | 379.05 KB | ≈ |
| data-view.complex-search | 147.92 KB | 147.92 KB | 🟰 |
| data-view.crystal-ball-indicator | 163.61 KB | 163.61 KB | 🟰 |
| data-view.data-display-flipper | 69.23 KB | 69.23 KB | 🟰 |
| data-view.data-display-flipper-fifth | 69.12 KB | 69.12 KB | 🟰 |
| data-view.data-display-flipper-sixth | 68.97 KB | 68.98 KB | ≈ |
| data-view.dropdown-menu | 137.52 KB | 137.53 KB | ≈ |
| data-view.gauge-chart | 70.15 KB | 70.16 KB | ≈ |
| data-view.gear-background | 115.41 KB | 115.41 KB | 🟰 |
| data-view.globe-with-gear-indicator | 214.62 KB | 214.62 KB | 🟰 |
| data-view.globe-with-halo-indicator | 164.62 KB | 164.62 KB | 🟰 |
| data-view.globe-with-orbit-indicator | 164.47 KB | 164.48 KB | ≈ |
| data-view.graph-layout-grid | 86.48 KB | 86.49 KB | ≈ |
| data-view.graph-node | 69.15 KB | 69.16 KB | ≈ |
| data-view.graph-text | 77.65 KB | 77.66 KB | ≈ |
| data-view.grid-background | 104.49 KB | 104.49 KB | 🟰 |
| data-view.hi-tech-button | 69.95 KB | 69.95 KB | 🟰 |
| data-view.indicator-card | 69.42 KB | 69.42 KB | 🟰 |
| data-view.lights-component-title | 68.84 KB | 68.85 KB | ≈ |
| data-view.loading-panel | 73.2 KB | 73.2 KB | 🟰 |
| data-view.modern-style-component-title | 69.92 KB | 69.93 KB | ≈ |
| data-view.modern-style-page-title | 69.99 KB | 69.99 KB | 🟰 |
| data-view.modern-style-treemap | 80.45 KB | 80.46 KB | ≈ |
| data-view.particle-animation | 69.84 KB | 69.85 KB | ≈ |
| data-view.progress-bar-list | 71.98 KB | 71.99 KB | ≈ |
| data-view.radar-chart | 70.89 KB | 70.9 KB | ≈ |
| data-view.simple-card-item | 69.53 KB | 69.53 KB | 🟰 |
| data-view.tabs-drawer | 137.45 KB | 137.46 KB | ≈ |
| data-view.tabs-page-title | 72.05 KB | 72.06 KB | ≈ |
| data-view.tech-mesh-base-view | 68.4 KB | 68.41 KB | ≈ |
| data-view.title-text | 69.61 KB | 69.62 KB | ≈ |
| data-view.top-title-bar | 80.76 KB | 80.77 KB | ≈ |
| diagram.editable-label | 67.64 KB | 67.64 KB | 🟰 |
| diagram.experimental-node | 67.09 KB | 67.09 KB | 🟰 |
| eo-actions | 277.63 KB | 277.63 KB | 🟰 |
| eo-alert | 139.69 KB | 139.78 KB | ≈ |
| eo-antd-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-app-bar-wrapper | 68.01 KB | 68 KB | ≈ |
| eo-auto-complete | 202.88 KB | 202.88 KB | 🟰 |
| eo-avatar | 259.84 KB | 259.86 KB | ≈ |
| eo-avatar-group | 258.76 KB | 258.76 KB | 🟰 |
| eo-banner | 95.96 KB | 95.96 KB | 🟰 |
| eo-breadcrumb | 270 KB | 270.04 KB | ≈ |
| eo-breadcrumb-item | 269.56 KB | 269.59 KB | ≈ |
| eo-broadcast-channel | 78.73 KB | 78.73 KB | 🟰 |
| eo-button | 152.86 KB | 152.86 KB | 🟰 |
| eo-card | 164.53 KB | 164.53 KB | 🟰 |
| eo-card-item | 300.45 KB | 300.4 KB | ≈ |
| eo-carousel-text | 75.31 KB | 75.31 KB | 🟰 |
| eo-cascader | 269.67 KB | 269.67 KB | 🟰 |
| eo-category | 67.4 KB | 67.4 KB | 🟰 |
| eo-checkbox | 158.11 KB | 158.11 KB | 🟰 |
| eo-code-display | 352.66 KB | 352.65 KB | ≈ |
| eo-color-picker | 240.22 KB | 240.22 KB | 🟰 |
| eo-content-layout | 66.33 KB | 66.33 KB | 🟰 |
| eo-context-menu | 280.66 KB | 280.65 KB | ≈ |
| eo-counter-badge | 145.46 KB | 145.46 KB | 🟰 |
| eo-current-time | 138.45 KB | 138.35 KB | ↓ -0.1 KB |
| eo-date-picker | 284.49 KB | 338.76 KB | 🔺 +54.27 KB |
| eo-descriptions | 188.23 KB | 188.22 KB | ≈ |
| eo-diagram | 122.43 KB | 122.43 KB | 🟰 |
| eo-directory | 281.69 KB | 281.71 KB | ≈ |
| eo-directory-tree | 169.14 KB | 167.45 KB | 🟢 -1.69 KB |
| eo-directory-tree-internal-node | 134.94 KB | 134.94 KB | 🟰 |
| eo-directory-tree-leaf | 134.25 KB | 134.24 KB | ≈ |
| eo-display-canvas | 218.64 KB | 218.64 KB | 🟰 |
| eo-divider | 73.12 KB | 73.12 KB | 🟰 |
| eo-draw-canvas | 238.75 KB | 238.78 KB | ≈ |
| eo-drawer | 158.34 KB | 158.34 KB | 🟰 |
| eo-dropdown-actions | 279.2 KB | 279.2 KB | 🟰 |
| eo-dropdown-button | 280.72 KB | 280.72 KB | 🟰 |
| eo-dropdown-select | 274.7 KB | 274.72 KB | ≈ |
| eo-dynamic-form-item | 245.87 KB | 245.88 KB | ≈ |
| eo-easy-view | 67.04 KB | 67.04 KB | 🟰 |
| eo-easyops-avatar | 261.76 KB | 261.76 KB | 🟰 |
| eo-easyops-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-event-agent | 23.18 KB | 23.18 KB | 🟰 |
| eo-fa-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-flex-layout | 66.78 KB | 66.78 KB | 🟰 |
| eo-form | 69.83 KB | 69.84 KB | ≈ |
| eo-form-item | 76.3 KB | 76.31 KB | ≈ |
| eo-formatter-number | 78.8 KB | 78.8 KB | 🟰 |
| eo-frame-breadcrumb | 284.35 KB | 284.31 KB | ≈ |
| eo-grid-layout | 67.88 KB | 67.88 KB | 🟰 |
| eo-humanize-time | 284.18 KB | 284.17 KB | ≈ |
| eo-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-icon-select | 265.88 KB | 265.89 KB | ≈ |
| eo-iframe | 78.78 KB | 78.78 KB | 🟰 |
| eo-illustration-message | 139.53 KB | 139.53 KB | 🟰 |
| eo-image | 148.41 KB | 148.41 KB | 🟰 |
| eo-img-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-info-card-item | 286.87 KB | 286.83 KB | ≈ |
| eo-input | 196.71 KB | 142.47 KB | 🟢 -54.24 KB |
| eo-launchpad-button | 306 KB | 306 KB | 🟰 |
| eo-launchpad-button-v2 | 315.92 KB | 315.92 KB | 🟰 |
| eo-launchpad-quick-access | 303.85 KB | 303.88 KB | ≈ |
| eo-launchpad-recent-visits | 302.67 KB | 302.65 KB | ≈ |
| eo-link | 267.89 KB | 267.9 KB | ≈ |
| eo-loading-container | 144.94 KB | 144.94 KB | 🟰 |
| eo-loading-step | 165.59 KB | 165.68 KB | ≈ |
| eo-main-view | 95.96 KB | 95.96 KB | 🟰 |
| eo-markdown-display | 140.58 KB | 140.58 KB | 🟰 |
| eo-markdown-editor | 408.23 KB | 408.21 KB | ≈ |
| eo-menu | 78.34 KB | 78.34 KB | 🟰 |
| eo-menu-group | 78.27 KB | 78.27 KB | 🟰 |
| eo-menu-item | 144.77 KB | 144.77 KB | 🟰 |
| eo-menu-item-sub-menu | 145.22 KB | 145.22 KB | 🟰 |
| eo-message-listener | 78.5 KB | 78.5 KB | 🟰 |
| eo-micro-view | 87.94 KB | 87.94 KB | 🟰 |
| eo-mini-actions | 279.7 KB | 279.7 KB | 🟰 |
| eo-mini-line-chart | 81.64 KB | 81.64 KB | 🟰 |
| eo-modal | 165.18 KB | 165.18 KB | 🟰 |
| eo-narrow-view | 75.11 KB | 75.11 KB | 🟰 |
| eo-nav-menu | 328.55 KB | 328.55 KB | 🟰 |
| eo-next-table | 524.18 KB | 524.13 KB | ≈ |
| eo-page-title | 78.48 KB | 78.48 KB | 🟰 |
| eo-page-view | 75.11 KB | 75.11 KB | 🟰 |
| eo-pagination | 305.74 KB | 305.76 KB | ≈ |
| eo-popover | 195.25 KB | 195.22 KB | ≈ |
| eo-popup | 148.03 KB | 148.06 KB | ≈ |
| eo-radio | 205.26 KB | 205.26 KB | 🟰 |
| eo-resizable-box | 68.75 KB | 68.75 KB | 🟰 |
| eo-search | 200.76 KB | 200.76 KB | 🟰 |
| eo-search-bar | 66.9 KB | 66.9 KB | 🟰 |
| eo-search-launchpad | 306.52 KB | 306.52 KB | 🟰 |
| eo-select | 345.78 KB | 345.78 KB | 🟰 |
| eo-sidebar | 312.58 KB | 312.57 KB | ≈ |
| eo-sidebar-menu | 293.63 KB | 293.6 KB | ≈ |
| eo-sidebar-menu-group | 293.61 KB | 293.6 KB | ≈ |
| eo-sidebar-menu-item | 278.49 KB | 278.44 KB | ≈ |
| eo-sidebar-menu-submenu | 293.63 KB | 293.6 KB | ≈ |
| eo-sidebar-sub-menu | 284.44 KB | 284.46 KB | ≈ |
| eo-spin | 67.22 KB | 67.22 KB | 🟰 |
| eo-statistics-card | 139.55 KB | 139.54 KB | ≈ |
| eo-submit-buttons | 230.35 KB | 230.35 KB | 🟰 |
| eo-svg-icon | 123.76 KB | 123.76 KB | 🟰 |
| eo-switch | 147.97 KB | 202.22 KB | 🔺 +54.25 KB |
| eo-tab-group | 72.1 KB | 72.1 KB | 🟰 |
| eo-tab-item | 159.93 KB | 159.93 KB | 🟰 |
| eo-tab-list | 159.93 KB | 159.93 KB | 🟰 |
| eo-table | 381.29 KB | 381.19 KB | ↓ -0.1 KB |
| eo-tag | 146.72 KB | 146.72 KB | 🟰 |
| eo-tag-list | 148.81 KB | 148.81 KB | 🟰 |
| eo-text | 352.34 KB | 352.31 KB | ≈ |
| eo-text-tooltip | 139.31 KB | 139.31 KB | 🟰 |
| eo-textarea | 85.51 KB | 85.51 KB | 🟰 |
| eo-time-picker | 214.46 KB | 214.47 KB | ≈ |
| eo-time-range-picker | 283.69 KB | 283.69 KB | 🟰 |
| eo-tooltip | 267.89 KB | 267.89 KB | 🟰 |
| eo-tree | 138.42 KB | 138.42 KB | 🟰 |
| eo-tree-select | 282.47 KB | 282.48 KB | ≈ |
| eo-upload-file | 357.45 KB | 357.45 KB | 🟰 |
| eo-upload-image | 247.05 KB | 247.05 KB | 🟰 |
| eo-user-or-user-group-select | 367.82 KB | 367.83 KB | ≈ |
| eo-workbench-layout | 352.48 KB | 352.49 KB | ≈ |
| eo-workbench-layout-v2 | 353.99 KB | 353.99 KB | 🟰 |
| form.dynamic-form-item | 245.87 KB | 245.88 KB | ≈ |
| form.general-checkbox | 212.36 KB | 158.11 KB | 🟢 -54.25 KB |
| form.general-form | 69.83 KB | 69.84 KB | ≈ |
| form.general-form-item | 76.3 KB | 76.31 KB | ≈ |
| form.general-input | 142.47 KB | 142.47 KB | 🟰 |
| form.general-radio | 205.26 KB | 205.26 KB | 🟰 |
| form.general-search | 146.51 KB | 146.51 KB | 🟰 |
| form.general-select | 345.78 KB | 345.82 KB | ≈ |
| form.general-switch | 147.97 KB | 202.22 KB | 🔺 +54.25 KB |
| form.general-textarea | 85.51 KB | 85.51 KB | 🟰 |
| form.icon-select | 265.88 KB | 265.89 KB | ≈ |
| form.submit-buttons | 230.35 KB | 230.35 KB | 🟰 |
| form.upload-image | 247.05 KB | 247.05 KB | 🟰 |
| icons.antd-icon | 123.76 KB | 123.76 KB | 🟰 |
| icons.easyops-icon | 123.76 KB | 123.76 KB | 🟰 |
| icons.fa-icon | 123.76 KB | 123.76 KB | 🟰 |
| icons.general-icon | 123.76 KB | 123.76 KB | 🟰 |
| icons.get-antd-icons | 123.76 KB | 123.76 KB | 🟰 |
| icons.get-easyops-icons | 123.76 KB | 123.76 KB | 🟰 |
| icons.get-fa-icons | 123.76 KB | 123.76 KB | 🟰 |
| icons.get-libs | 123.76 KB | 123.76 KB | 🟰 |
| icons.search-icons | 123.76 KB | 123.76 KB | 🟰 |
| illustrations.error-message | 139.53 KB | 139.53 KB | 🟰 |
| illustrations.get-illustration | 9.24 KB | 9.24 KB | 🟰 |
| illustrations.get-illustrations-by-category | 6.03 KB | 6.03 KB | 🟰 |
| illustrations.loading-transition | 66.55 KB | 66.55 KB | 🟰 |
| illustrations.translate-illustration-config | 9.24 KB | 9.24 KB | 🟰 |
| inject.visual-builder-preview-agent | 56.26 KB | 56.26 KB | 🟰 |
| markdown.markdown-editor | 408.19 KB | 408.23 KB | ≈ |
| nav.app-bar-wrapper | 68.01 KB | 68 KB | ≈ |
| nav.easyops-navbar-alerts | 280.94 KB | 280.9 KB | ≈ |
| nav.get-menu-config-options | 7.86 KB | 7.85 KB | ≈ |
| nav.get-menu-config-tree | 8.35 KB | 8.35 KB | 🟰 |
| nav.launchpad-config | 312.59 KB | 312.58 KB | ≈ |
| nav.nav-logo | 277.47 KB | 277.48 KB | ≈ |
| nav.poll-announce | 288.02 KB | 288.02 KB | 🟰 |
| presentational.code-display | 352.66 KB | 352.65 KB | ≈ |
| presentational.general-alert | 139.69 KB | 139.68 KB | ≈ |
| presentational.general-descriptions | 188.23 KB | 188.22 KB | ≈ |
| presentational.humanize-time | 284.18 KB | 284.17 KB | ≈ |
| recent-history.clear-history | 28.99 KB | 28.99 KB | 🟰 |
| recent-history.get-all-history | 28.99 KB | 28.99 KB | 🟰 |
| recent-history.push-history | 28.99 KB | 28.99 KB | 🟰 |
| recent-history.recent-visit | 311.21 KB | 311.19 KB | ≈ |
| sl-alert | 115.03 KB | 115.03 KB | 🟰 |
| sl-animated-image | 114.05 KB | 114.05 KB | 🟰 |
| sl-animation | 117.4 KB | 117.4 KB | 🟰 |
| sl-avatar | 114.04 KB | 114.04 KB | 🟰 |
| sl-badge | 114.04 KB | 114.04 KB | 🟰 |
| sl-breadcrumb | 114.83 KB | 114.83 KB | 🟰 |
| sl-breadcrumb-item | 114.83 KB | 114.83 KB | 🟰 |
| sl-button | 114.82 KB | 114.83 KB | ≈ |
| sl-button-group | 114.05 KB | 114.05 KB | 🟰 |
| sl-card | 114.04 KB | 114.04 KB | 🟰 |
| sl-carousel | 114.83 KB | 114.83 KB | 🟰 |
| sl-carousel-item | 114.83 KB | 114.83 KB | 🟰 |
| sl-checkbox | 114.04 KB | 114.04 KB | 🟰 |
| sl-color-picker | 120.09 KB | 120.09 KB | 🟰 |
| sl-details | 114.82 KB | 114.82 KB | 🟰 |
| sl-dialog | 115.03 KB | 115.03 KB | 🟰 |
| sl-divider | 114.04 KB | 114.04 KB | 🟰 |
| sl-drawer | 114.83 KB | 114.83 KB | 🟰 |
| sl-dropdown | 115.03 KB | 115.03 KB | 🟰 |
| sl-format-bytes | 114.83 KB | 114.83 KB | 🟰 |
| sl-format-date | 114.82 KB | 114.82 KB | 🟰 |
| sl-format-number | 114.82 KB | 114.82 KB | 🟰 |
| sl-icon | 114.04 KB | 114.04 KB | 🟰 |
| sl-icon-button | 114.05 KB | 114.05 KB | 🟰 |
| sl-image-comparer | 114.83 KB | 114.83 KB | 🟰 |
| sl-input | 114.82 KB | 114.82 KB | 🟰 |
| sl-menu | 115.03 KB | 115.03 KB | 🟰 |
| sl-menu-item | 115.03 KB | 115.03 KB | 🟰 |
| sl-menu-label | 114.05 KB | 114.05 KB | 🟰 |
| sl-mutation-observer | 114.05 KB | 114.05 KB | 🟰 |
| sl-option | 114.83 KB | 114.83 KB | 🟰 |
| sl-popup | 115.03 KB | 115.03 KB | 🟰 |
| sl-progress-bar | 114.83 KB | 114.83 KB | 🟰 |
| sl-progress-ring | 114.83 KB | 114.83 KB | 🟰 |
| sl-qr-code | 118.72 KB | 118.72 KB | 🟰 |
| sl-radio | 114.04 KB | 114.04 KB | 🟰 |
| sl-radio-button | 114.05 KB | 114.08 KB | ≈ |
| sl-radio-group | 114.05 KB | 114.05 KB | 🟰 |
| sl-range | 114.83 KB | 114.83 KB | 🟰 |
| sl-rating | 114.83 KB | 114.83 KB | 🟰 |
| sl-relative-time | 114.83 KB | 114.83 KB | 🟰 |
| sl-resize-observer | 114.05 KB | 114.05 KB | 🟰 |
| sl-select | 115.03 KB | 115.03 KB | 🟰 |
| sl-skeleton | 114.05 KB | 114.05 KB | 🟰 |
| sl-spinner | 114.83 KB | 114.83 KB | 🟰 |
| sl-split-panel | 114.83 KB | 114.83 KB | 🟰 |
| sl-switch | 114.04 KB | 114.04 KB | 🟰 |
| sl-tab | 114.83 KB | 114.83 KB | 🟰 |
| sl-tab-group | 114.83 KB | 114.83 KB | 🟰 |
| sl-tab-panel | 114.83 KB | 114.83 KB | 🟰 |
| sl-tag | 114.82 KB | 114.82 KB | 🟰 |
| sl-textarea | 114.04 KB | 114.04 KB | 🟰 |
| sl-tooltip | 115.03 KB | 115.03 KB | 🟰 |
| sl-tree | 114.83 KB | 114.83 KB | 🟰 |
| sl-tree-item | 114.83 KB | 114.83 KB | 🟰 |
| sl-visually-hidden | 114.05 KB | 114.05 KB | 🟰 |
| visual-builder.batch-update-raw-data-generated-view | 7.59 KB | 7.59 KB | 🟰 |
| visual-builder.chat-conversation | 337.53 KB | 337.56 KB | ≈ |
| visual-builder.chat-preview | 69.55 KB | 69.55 KB | 🟰 |
| visual-builder.check-editor-by-name | 7.2 KB | 7.2 KB | 🟰 |
| visual-builder.contract-select | 169.19 KB | 169.19 KB | 🟰 |
| visual-builder.generate-snippets-context-menu | 290.42 KB | 290.39 KB | ≈ |
| visual-builder.get-config-by-data-for-ai | 8.97 KB | 8.96 KB | ≈ |
| visual-builder.get-data-deps | 7.21 KB | 7.21 KB | 🟰 |
| visual-builder.get-dependency-tree | 7.58 KB | 7.58 KB | 🟰 |
| visual-builder.get-raw-data-system-prompts | 11.81 KB | 11.81 KB | 🟰 |
| visual-builder.inject-chat-preview-agent | 8.16 KB | 8.15 KB | ≈ |
| visual-builder.page-arch-node | 280.79 KB | 280.74 KB | ≈ |
| visual-builder.parse-path | 8.84 KB | 8.83 KB | ≈ |
| visual-builder.pre-generated-config | 79.94 KB | 79.93 KB | ≈ |
| visual-builder.pre-generated-config-preview | 75.29 KB | 75.29 KB | 🟰 |
| visual-builder.pre-generated-container | 69.49 KB | 69.48 KB | ≈ |
| visual-builder.pre-generated-preview | 69.53 KB | 69.53 KB | 🟰 |
| visual-builder.pre-generated-table-view | 67.13 KB | 67.12 KB | ≈ |
| visual-builder.property-editor | 1,432.6 KB | 1,437.92 KB | 🔺 +5.32 KB |
| visual-builder.raw-data-preview | 78.61 KB | 78.61 KB | 🟰 |
| visual-builder.raw-metric-preview | 71.43 KB | 71.42 KB | ≈ |
| visual-builder.workbench-action | 279.55 KB | 279.53 KB | ≈ |
| visual-builder.workbench-action-list | 284.93 KB | 284.95 KB | ≈ |
| visual-builder.workbench-history-action | 300.25 KB | 300.24 KB | ≈ |
| visual-builder.workbench-pane | 135.31 KB | 135.31 KB | 🟰 |
| visual-builder.workbench-sidebar | 68.02 KB | 68.01 KB | ≈ |
| visual-builder.workbench-tree | 285.02 KB | 285 KB | ≈ |
| vs.code-editor | 1,140.64 KB | 1,145.91 KB | 🔺 +5.27 KB |

</details>

<details>

<summary>Critical details for brick eo-date-picker</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js | 2.52 KB |  | <del>Del</del> |
| form/dist/chunks/845.f6378665.js | 82.97 KB | 83 KB | ≈ |
| form/dist/chunks/8548.3d64fb28.js | 0.83 KB |  | <del>Del</del> |
| form/dist/chunks/react.4372d06b.js | 55.06 KB |  | <del>Del</del> |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| icons/dist/chunks/114.6546c4b7.js |  | 1.59 KB | New |
| icons/dist/chunks/144.ed687799.js |  | 49.96 KB | New |
| icons/dist/chunks/41.48c2e71e.js |  | 3.53 KB | New |
| icons/dist/chunks/45.e9943c86.js |  | 2.52 KB | New |

</details>

<details>

<summary>Critical details for brick eo-directory-tree</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js |  | 2.52 KB | New |
| form/dist/chunks/8548.3d64fb28.js |  | 0.83 KB | New |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| nav/dist/chunks/1045.6f2ef8ee.js | 2.52 KB |  | <del>Del</del> |
| nav/dist/chunks/114.de520122.js | 1.59 KB |  | <del>Del</del> |
| nav/dist/chunks/3144.702dfbe9.js | 49.96 KB |  | <del>Del</del> |
| nav/dist/chunks/4041.457ae2a2.js | 3.53 KB |  | <del>Del</del> |
| nav/dist/chunks/4837.4c653276.js | 2.5 KB |  | <del>Del</del> |
| nav/dist/index.5f2f18b5.js |  | 6.41 KB | New |
| nav/dist/index.bba767fb.js | 6.42 KB |  | <del>Del</del> |

</details>

<details>

<summary>Critical details for brick eo-input</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js |  | 2.52 KB | New |
| form/dist/chunks/8548.3d64fb28.js |  | 0.83 KB | New |
| form/dist/chunks/react.4372d06b.js | 55.06 KB |  | <del>Del</del> |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| icons/dist/chunks/114.6546c4b7.js | 1.59 KB |  | <del>Del</del> |
| icons/dist/chunks/144.ed687799.js | 49.96 KB |  | <del>Del</del> |
| icons/dist/chunks/41.48c2e71e.js | 3.53 KB |  | <del>Del</del> |
| icons/dist/chunks/45.e9943c86.js | 2.52 KB |  | <del>Del</del> |

</details>

<details>

<summary>Critical details for brick eo-switch</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js | 2.52 KB |  | <del>Del</del> |
| form/dist/chunks/8548.3d64fb28.js | 0.83 KB |  | <del>Del</del> |
| form/dist/chunks/react.4372d06b.js | 55.06 KB |  | <del>Del</del> |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| icons/dist/chunks/114.6546c4b7.js |  | 1.59 KB | New |
| icons/dist/chunks/144.ed687799.js |  | 49.96 KB | New |
| icons/dist/chunks/41.48c2e71e.js |  | 3.53 KB | New |
| icons/dist/chunks/45.e9943c86.js |  | 2.52 KB | New |

</details>

<details>

<summary>Critical details for brick form.general-checkbox</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js |  | 2.52 KB | New |
| form/dist/chunks/8548.3d64fb28.js |  | 0.83 KB | New |
| form/dist/chunks/react.4372d06b.js | 55.06 KB |  | <del>Del</del> |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| icons/dist/chunks/114.6546c4b7.js | 1.59 KB |  | <del>Del</del> |
| icons/dist/chunks/144.ed687799.js | 49.96 KB |  | <del>Del</del> |
| icons/dist/chunks/41.48c2e71e.js | 3.53 KB |  | <del>Del</del> |
| icons/dist/chunks/45.e9943c86.js | 2.52 KB |  | <del>Del</del> |

</details>

<details>

<summary>Critical details for brick form.general-switch</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/chunks/1045.7ad43dc1.js | 2.52 KB |  | <del>Del</del> |
| form/dist/chunks/8548.3d64fb28.js | 0.83 KB |  | <del>Del</del> |
| form/dist/chunks/react.4372d06b.js | 55.06 KB |  | <del>Del</del> |
| form/dist/chunks/react.5c1c229c.js |  | 55.05 KB | New |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| icons/dist/chunks/114.6546c4b7.js |  | 1.59 KB | New |
| icons/dist/chunks/144.ed687799.js |  | 49.96 KB | New |
| icons/dist/chunks/41.48c2e71e.js |  | 3.53 KB | New |
| icons/dist/chunks/45.e9943c86.js |  | 2.52 KB | New |

</details>

<details>

<summary>Critical details for brick visual-builder.property-editor</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| shoelace/dist/chunks/vendors.b87b1ad4.js | 109.39 KB | 109.36 KB | ≈ |
| visual-builder/dist/chunks/4837.bbbe8edf.js |  | 2.5 KB | New |
| visual-builder/dist/chunks/7434.c8f35cb5.js |  | 7.5 KB | New |
| visual-builder/dist/chunks/8097.beaba572.js |  | 0.56 KB | New |
| visual-builder/dist/index.228ff2a1.js | 6.58 KB |  | <del>Del</del> |
| visual-builder/dist/index.ed4c1ca1.js |  | 6.57 KB | New |
| vs/dist/chunks/4837.0a1b818d.js | 2.5 KB |  | <del>Del</del> |
| vs/dist/chunks/5152.a1c0a265.js | 822.52 KB |  | <del>Del</del> |
| vs/dist/chunks/5584.da8ae321.js |  | 11.2 KB | New |
| vs/dist/chunks/7627.091da003.js | 9.1 KB |  | <del>Del</del> |
| vs/dist/chunks/8097.b7e88868.js | 0.56 KB |  | <del>Del</del> |
| vs/dist/chunks/8251.2e04a653.js |  | 825.33 KB | New |
| vs/dist/chunks/9780.6386fa71.js | 7.44 KB |  | <del>Del</del> |
| vs/dist/chunks/code-editor.02e84745.js |  | 6.85 KB | New |
| vs/dist/chunks/code-editor.d02ed558.js | 6.49 KB |  | <del>Del</del> |
| vs/dist/index.5c99b89f.js |  | 5.53 KB | New |
| vs/dist/index.ba602344.js | 5.52 KB |  | <del>Del</del> |

</details>

<details>

<summary>Critical details for brick vs.code-editor</summary>

| Name | Prev | Now | Diff |
| - | - | - | - |
| form/dist/index.0709d264.js | 6.1 KB |  | <del>Del</del> |
| form/dist/index.e72607bb.js |  | 6.11 KB | New |
| vs/dist/chunks/4837.0a1b818d.js | 2.5 KB |  | <del>Del</del> |
| vs/dist/chunks/4837.3c931400.js |  | 2.5 KB | New |
| vs/dist/chunks/5152.a1c0a265.js | 822.53 KB |  | <del>Del</del> |
| vs/dist/chunks/5584.da8ae321.js |  | 11.2 KB | New |
| vs/dist/chunks/7627.091da003.js | 9.1 KB |  | <del>Del</del> |
| vs/dist/chunks/8251.2e04a653.js |  | 825.33 KB | New |
| vs/dist/chunks/code-editor.02e84745.js |  | 6.85 KB | New |
| vs/dist/chunks/code-editor.d02ed558.js | 6.49 KB |  | <del>Del</del> |
| vs/dist/index.5c99b89f.js |  | 5.53 KB | New |
| vs/dist/index.ba602344.js | 5.52 KB |  | <del>Del</del> |

</details>
author_association: NONE