Kaynağa Gözat

feat: 添加编辑器

jiaxing.liao 3 hafta önce
ebeveyn
işleme
819d0eb3f8

+ 18 - 5
.vscode/settings.json

@@ -1,7 +1,20 @@
 {
-  "eslint.workingDirectories": [
-    {
-      "mode": "auto"
-    }
-  ]
+  "editor.formatOnSave": true,
+  "[typescript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[javascript]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "[json]": {
+    "editor.defaultFormatter": "esbenp.prettier-vscode"
+  },
+  "i18n-ally.localesPaths": [
+    "src/renderer/src/locales"
+  ],
+  "i18n-ally.enabledParsers": ["json"],
+  "i18n-ally.displayLanguage": "zh_CN",
+  "i18n-ally.sourceLanguage": "zh",
+  "i18n-ally.keystyle": "nested",
+  "i18n-ally.enabledFrameworks": ["vue"],
 }

+ 3 - 0
apps/web/package.json

@@ -10,15 +10,18 @@
   },
   "dependencies": {
     "element-plus": "^2.13.1",
+    "normalize.css": "^8.0.1",
     "vue": "^3.5.24",
     "vue-router": "4"
   },
   "devDependencies": {
+    "@repo/workflow": "workspace:*",
     "@types/node": "^24.10.1",
     "@vitejs/plugin-vue": "^6.0.1",
     "@vue/tsconfig": "^0.8.1",
     "less": "^4.5.1",
     "typescript": "~5.9.3",
+    "unocss": "^66.6.0",
     "vite": "npm:rolldown-vite@7.2.5",
     "vue-tsc": "^3.1.4"
   },

+ 3 - 0
apps/web/src/main.ts

@@ -5,4 +5,7 @@ import router from './router'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
 
+import 'normalize.css'
+import 'virtual:uno.css'
+
 createApp(App).use(router).use(ElementPlus).mount('#app')

+ 4 - 1
apps/web/src/router/index.ts

@@ -6,6 +6,8 @@ const About = () => import('@/views/About.vue')
 const Templates = () => import('@/views/Templates.vue')
 const Executions = () => import('@/views/Executions.vue')
 
+const Editor = () => import('@/views/Editor.vue')
+
 const routes = [
 	{
 		path: '/',
@@ -14,7 +16,8 @@ const routes = [
 			{ path: '', name: 'Dashboard', component: Dashboard },
 			{ path: 'about', name: 'About', component: About },
 			{ path: 'templates', name: 'Templates', component: Templates },
-			{ path: 'executions', name: 'Executions', component: Executions }
+			{ path: 'executions', name: 'Executions', component: Executions },
+			{ path: 'workflow/:id', name: 'Editor', component: Editor }
 		]
 	}
 ]

+ 51 - 0
apps/web/src/views/Editor.vue

@@ -0,0 +1,51 @@
+<template>
+	<div class="w-full h-full">
+		<Workflow :workflow="workflow" @click:node="handleNodeClick" @drop="handleDrop" />
+	</div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { Workflow, type IWorkflow, type XYPosition } from '@repo/workflow'
+
+const workflow = ref<IWorkflow>({
+	id: '1',
+	nodes: [
+		{
+			id: 'node-1',
+			type: 'canvas-node',
+			position: { x: 100, y: 100 },
+			width: 100,
+			height: 100,
+			data: { label: 'Node 1', inputs: [], outputs: [] }
+		},
+		{
+			id: 'node-2',
+			type: 'canvas-node',
+			width: 100,
+			height: 100,
+			position: { x: 400, y: 100 },
+			data: { label: 'Node 1', inputs: [], outputs: [] }
+		}
+	],
+	edges: [
+		{
+			id: 'edge-1-2',
+			source: 'node-1',
+			target: 'node-2',
+			type: 'canvas-edge',
+			data: {
+				label: 'Edge 1-2'
+			}
+		}
+	]
+})
+
+const handleNodeClick = (id: string, position: XYPosition) => {
+	console.log('click node', id, position)
+}
+
+const handleDrop = (position: XYPosition, event: DragEvent) => {
+	console.log('drag and drop at', position, event)
+}
+</script>

+ 7 - 0
apps/web/uno.config.ts

@@ -0,0 +1,7 @@
+import { defineConfig, presetWind3 } from 'unocss'
+
+export default defineConfig({
+  presets: [presetWind3()],
+  shortcuts: {},
+  rules: []
+})

+ 5 - 1
apps/web/vite.config.ts

@@ -1,10 +1,14 @@
 import { defineConfig } from 'vite'
 import vue from '@vitejs/plugin-vue'
 import path from 'path'
+import UnoCss from 'unocss/vite'
 
 // https://vite.dev/config/
 export default defineConfig({
-  plugins: [vue()],
+  plugins: [
+    vue(),
+    UnoCss()
+  ],
   resolve: {
     alias: {
       '@': path.resolve(__dirname, 'src')

+ 52 - 0
packages/workflow/biome.jsonc

@@ -0,0 +1,52 @@
+{
+	"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
+	"vcs": {
+		"clientKind": "git",
+		"enabled": true,
+		"useIgnoreFile": true
+	},
+	"files": {
+		"ignore": [
+			"**/.turbo",
+			"**/components.d.ts",
+			"**/coverage",
+			"**/dist",
+			"**/package.json",
+			"**/pnpm-lock.yaml",
+			"**/CHANGELOG.md"
+		]
+	},
+	"formatter": {
+		"enabled": true,
+		"formatWithErrors": false,
+		"indentStyle": "tab",
+		"indentWidth": 2,
+		"lineEnding": "lf",
+		"lineWidth": 100,
+		"attributePosition": "auto",
+		"ignore": [
+			// Handled by prettier
+			"**/*.vue"
+		]
+	},
+	"organizeImports": { "enabled": false },
+	"linter": {
+		"enabled": false
+	},
+	"javascript": {
+		"parser": {
+			"unsafeParameterDecoratorsEnabled": true
+		},
+		"formatter": {
+			"jsxQuoteStyle": "double",
+			"quoteProperties": "asNeeded",
+			"trailingCommas": "all",
+			"semicolons": "always",
+			"arrowParentheses": "always",
+			"bracketSpacing": true,
+			"bracketSameLine": false,
+			"quoteStyle": "single",
+			"attributePosition": "auto"
+		}
+	}
+}

+ 4 - 2
packages/workflow/index.ts

@@ -1,2 +1,4 @@
-export * as Workflow from './src/Workflow.vue'
-export * from './src/Interface'
+import Workflow from './src/Workflow.vue'
+
+export { Workflow }
+export * from './src/Interface'

+ 4 - 0
packages/workflow/package.json

@@ -13,7 +13,11 @@
   },
   "dependencies": {
     "@antv/x6": "^3.1.4",
+    "@vue-flow/background": "^1.3.2",
+    "@vue-flow/controls": "^1.1.3",
     "@vue-flow/core": "^1.48.1",
+    "@vue-flow/minimap": "^1.5.4",
+    "@vue-flow/node-toolbar": "^1.1.1",
     "less": "^4.5.1",
     "less-loader": "^12.3.0",
     "normalize.css": "^8.0.1",

+ 20 - 17
packages/workflow/src/Interface.ts

@@ -1,33 +1,36 @@
-import type { Node, Edge } from '@vue-flow/core'
+import type { Node, DefaultEdge } from '@vue-flow/core'
 
 export type CanvasConnectionPort = {
-	node?: string;
-	type: string;
-	index: number;
-	required?: boolean;
-	maxConnections?: number;
-	label?: string;
-};
+	node?: string
+	type: string
+	index: number
+	required?: boolean
+	maxConnections?: number
+	label?: string
+}
 
 export interface IWorkflowNode extends Node {
 	data: {
-    inputs: CanvasConnectionPort[];
-    outputs: CanvasConnectionPort[];
+		inputs: CanvasConnectionPort[]
+		outputs: CanvasConnectionPort[]
 		// 定义节点数据
 		[key: string]: any
 	}
 }
 
-export interface IWorkflowEdge {
-	data: {
-		// 定义边数据
-		[key: string]: any
-	}
-}
+export type IWorkflowEdge = DefaultEdge<{
+	// 定义边数据
+	[key: string]: any
+}>
 
 export interface IWorkflow {
 	id: string
 	nodes: IWorkflowNode[]
-	edges: IWorkflow & Edge[]
+	edges: IWorkflowEdge[]
 	[key: string]: any
 }
+
+export interface XYPosition {
+	x: number
+	y: number
+}

+ 27 - 7
packages/workflow/src/Workflow.vue

@@ -1,13 +1,33 @@
 <template>
-  <div class="w-full h-full">
-    <Canvas />
-  </div>
+	<div class="w-full h-full">
+		<Canvas :id="id" :nodes="nodes" :edges="edges" v-bind="$attrs" />
+		<slot />
+	</div>
 </template>
 
 <script setup lang="ts">
-import Canvas from './components/Canvas.vue';
+import { computed } from 'vue'
+import Canvas from './components/Canvas.vue'
+import type { IWorkflow } from './Interface'
 
 defineOptions({
-  name: 'Workflow',
-});
-</script>
+	inheritAttrs: false
+})
+
+const props = withDefaults(
+	defineProps<{
+		id?: string
+		workflow?: IWorkflow
+		readOnly?: boolean
+	}>(),
+	{
+		id: 'canvas',
+		readOnly: false
+	}
+)
+
+// nodes
+const nodes = computed(() => props.workflow?.nodes || [])
+// edges
+const edges = computed(() => props.workflow?.edges || [])
+</script>

+ 93 - 12
packages/workflow/src/components/Canvas.vue

@@ -1,28 +1,103 @@
 <script lang="ts" setup>
-import { computed } from 'vue'
-import { VueFlow } from '@vue-flow/core'
-import type { IWorkflow } from '../Interface'
+import { VueFlow, useVueFlow, type NodeMouseEvent } from '@vue-flow/core'
+import type { IWorkflow, XYPosition } from '../Interface'
 
 import CanvasNode from './elements/CanvasNode.vue'
 import CanvasEdge from './elements/CanvasEdge.vue'
+import CanvasBackground from './elements/background/CanvasBackground.vue'
 
 defineOptions({
 	name: 'workflow-canvas'
 })
 
-const props = withDefaults(defineProps<{
-  workflow?: IWorkflow
-}>(), {
-})
-// nodes
-const nodes = computed(() => props.workflow?.nodes ?? [])
+const emit = defineEmits<{
+	'update:node:position': [id: string, position: XYPosition]
+	'update:node:activated': [id: string, event?: MouseEvent]
+	'update:node:deactivated': [id: string]
+	'update:node:enabled': [id: string]
+	'update:node:selected': [id?: string]
+	'update:node:name': [id: string]
+	'update:node:parameters': [id: string, parameters: Record<string, unknown>]
+	'update:node:inputs': [id: string]
+	'update:node:outputs': [id: string]
+	'update:logs-open': [open?: boolean]
+	'update:logs:input-open': [open?: boolean]
+	'update:logs:output-open': [open?: boolean]
+	'update:has-range-selection': [isActive: boolean]
+	'click:node': [id: string, position: XYPosition]
+	'click:node:add': [id: string, handle: string]
+	'run:node': [id: string]
+	'copy:production:url': [id: string]
+	'copy:test:url': [id: string]
+	'delete:node': [id: string]
+	'replace:node': [id: string]
+	'create:node': [source: any]
+	'create:sticky': []
+	'delete:nodes': [ids: string[]]
+	'update:nodes:enabled': [ids: string[]]
+	'copy:nodes': [ids: string[]]
+	'duplicate:nodes': [ids: string[]]
+	'cut:nodes': [ids: string[]]
+	'drag-and-drop': [position: XYPosition, event: DragEvent]
+}>()
+
+const props = withDefaults(
+	defineProps<{
+		id?: string
+		nodes: IWorkflow['nodes']
+		edges: IWorkflow['edges']
+		readOnly?: boolean
+	}>(),
+	{
+		id: 'canvas',
+		readOnly: false,
+		nodes: () => [],
+		edges: () => []
+	}
+)
+
+const { viewport, viewportRef, project } = useVueFlow()
+
+/**
+ * Returns the position of a mouse or touch event
+ */
+const getMousePosition = (event: MouseEvent | TouchEvent): XYPosition => {
+	const x = (event && 'clientX' in event ? event.clientX : event?.touches?.[0]?.clientX) ?? 0
+	const y = (event && 'clientY' in event ? event.clientY : event?.touches?.[0]?.clientY) ?? 0
+
+	return { x, y }
+}
+
+function getProjectedPosition(event?: MouseEvent | TouchEvent) {
+	const bounds = viewportRef.value?.getBoundingClientRect() ?? { left: 0, top: 0 }
+	const { x, y } = event ? getMousePosition(event) : { x: 0, y: 0 }
 
-// edges
-const edges = computed(() => props.workflow?.edges ?? [])
+	return project({
+		x: x - bounds.left,
+		y: y - bounds.top
+	})
+}
+
+const onNodeClick = ({ node, event }: NodeMouseEvent) => {
+	emit('click:node', node.id, getProjectedPosition(event))
+}
+
+function onDrop(event: DragEvent) {
+	const position = getProjectedPosition(event)
+
+	emit('drag-and-drop', position, event)
+}
 </script>
 
 <template>
-	<VueFlow :nodes="nodes" :edges="edges">
+	<VueFlow
+		:id="id"
+		:nodes="nodes"
+		:edges="edges"
+		@node-click="onNodeClick"
+		@drop="onDrop"
+		v-bind="$attrs"
+	>
 		<template #node-canvas-node="nodeProps">
 			<CanvasNode v-bind="nodeProps" />
 		</template>
@@ -30,6 +105,12 @@ const edges = computed(() => props.workflow?.edges ?? [])
 		<template #edge-canvas-edge="edgeProps">
 			<CanvasEdge v-bind="edgeProps" />
 		</template>
+
+		<template #background>
+			<rect width="100%" height="100%" fill="#f0f0f0" />
+		</template>
+
+		<CanvasBackground :viewport="viewport" :striped="readOnly" />
 	</VueFlow>
 </template>
 

+ 17 - 19
packages/workflow/src/components/elements/CanvasEdge.vue

@@ -1,31 +1,29 @@
 <template>
-  <BaseEdge :path="path[0]" />
-  <EdgeLabelRenderer>
-    <div
-      :style="{
-        pointerEvents: 'all',
-        position: 'absolute',
-        transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,
-      }"
-      class="nodrag nopan"
-    >
-      {{ data.hello }}
-    </div>
-  </EdgeLabelRenderer>
+	<BaseEdge :path="path[0]" />
+	<EdgeLabelRenderer>
+		<div
+			:style="{
+				pointerEvents: 'all',
+				position: 'absolute',
+				transform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`
+			}"
+			class="nodrag nopan"
+		>
+			{{ data.label }}
+		</div>
+	</EdgeLabelRenderer>
 </template>
 
 <script setup lang="ts">
-import { computed } from 'vue';
-import { BaseEdge, EdgeLabelRenderer, getBezierPath, type EdgeProps } from '@vue-flow/core';
+import { computed } from 'vue'
+import { BaseEdge, EdgeLabelRenderer, getBezierPath, type EdgeProps } from '@vue-flow/core'
 
 defineOptions({
-  inheritAttrs: false,
+	inheritAttrs: false
 })
 
 const props = defineProps<EdgeProps>()
 const path = computed(() => getBezierPath(props))
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>

+ 10 - 9
packages/workflow/src/components/elements/CanvasNode.vue

@@ -1,16 +1,17 @@
 <script setup lang="ts">
-import { computed } from 'vue'
-import { Position, Handle } from '@vue-flow/core'
+import { Position } from '@vue-flow/core'
 import type { NodeProps } from '@vue-flow/core'
-  
+
+import CanvasHandle from './handles/CanvasHandle.vue'
+
 const props = defineProps<NodeProps>()
-console.log(props)
 </script>
 
 <template>
-  <div class="vue-flow__node-default">
-    <div>{{ data.label }}</div>
+	<div class="w-full h-full box-border border-2 border-solid border-black rounded-4px">
+		<div>{{ data.label }}</div>
 
-    <Handle type="source" :position="Position.Bottom" />
-  </div>
-</template>
+		<CanvasHandle handle-id="1" handle-type="source" :position="Position.Right" />
+		<CanvasHandle handle-id="2" handle-type="target" :position="Position.Left" />
+	</div>
+</template>

+ 0 - 0
packages/workflow/src/components/elements/CanvasPort.vue


+ 23 - 0
packages/workflow/src/components/elements/background/CanvasBackground.vue

@@ -0,0 +1,23 @@
+<script setup lang="ts">
+import CanvasBackgroundStripedPattern from './CanvasBackgroundStripedPattern.vue'
+import { Background } from '@vue-flow/background'
+import type { ViewportTransform } from '@vue-flow/core'
+
+defineProps<{
+	striped: boolean
+	viewport: ViewportTransform
+}>()
+</script>
+<template>
+	<Background data-test-id="canvas-background" pattern-color="var(--canvas--dot--color)" :gap="16">
+		<template v-if="striped" #pattern-container="patternProps">
+			<CanvasBackgroundStripedPattern
+				:id="patternProps.id"
+				data-test-id="canvas-background-striped-pattern"
+				:x="viewport.x"
+				:y="viewport.y"
+				:zoom="viewport.zoom"
+			/>
+		</template>
+	</Background>
+</template>

+ 35 - 0
packages/workflow/src/components/elements/background/CanvasBackgroundStripedPattern.vue

@@ -0,0 +1,35 @@
+<script setup lang="ts">
+/**
+ * @see https://github.com/bcakmakoglu/vue-flow/blob/master/packages/background/src/Background.vue
+ */
+import { computed } from 'vue';
+const props = defineProps<{
+	id: string;
+	x: number;
+	y: number;
+	zoom: number;
+}>();
+
+const scaledGap = computed(() => 20 * props.zoom || 1);
+const patternOffset = computed(() => scaledGap.value / 2);
+</script>
+
+<template>
+	<pattern
+		:id="id"
+		patternUnits="userSpaceOnUse"
+		:x="x % scaledGap"
+		:y="y % scaledGap"
+		:width="scaledGap"
+		:height="scaledGap"
+		:patternTransform="`rotate(135) translate(-${patternOffset},-${patternOffset})`"
+	>
+		<path :d="`M0 ${scaledGap / 2} H${scaledGap}`" :stroke-width="scaledGap / 2" />
+	</pattern>
+</template>
+
+<style scoped>
+path {
+	stroke: var(--canvas--read-only-line--color);
+}
+</style>

+ 30 - 0
packages/workflow/src/components/elements/handles/CanvasHandle.vue

@@ -0,0 +1,30 @@
+<script lang="ts" setup>
+import { Handle, type Position, type ValidConnectionFunc } from '@vue-flow/core'
+
+defineProps<{
+	handleId: string
+	handleClasses?: string | string[]
+	handleType: 'source' | 'target'
+	position: Position
+	offset?: Record<string, string>
+	isConnectableStart?: boolean
+	isConnectableEnd?: boolean
+	isValidConnection?: ValidConnectionFunc
+}>()
+</script>
+
+<template>
+	<Handle
+		v-bind="$attrs"
+		:id="handleId"
+		:class="handleClasses"
+		:type="handleType"
+		:position="position"
+		:style="offset"
+		:connectable-start="isConnectableStart"
+		:connectable-end="isConnectableEnd"
+		:is-valid-connection="isValidConnection"
+	>
+		<div class="w-6px h-6px rounded box-border border-2 border-solid border-black"></div>
+	</Handle>
+</template>

packages/workflow/src/uno.config.ts → packages/workflow/uno.config.ts


+ 133 - 85
pnpm-lock.yaml

@@ -136,6 +136,9 @@ importers:
       element-plus:
         specifier: ^2.13.1
         version: 2.13.1(vue@3.5.27(typescript@5.9.3))
+      normalize.css:
+        specifier: ^8.0.1
+        version: 8.0.1
       vue:
         specifier: ^3.5.24
         version: 3.5.27(typescript@5.9.3)
@@ -143,12 +146,15 @@ importers:
         specifier: '4'
         version: 4.6.4(vue@3.5.27(typescript@5.9.3))
     devDependencies:
+      '@repo/workflow':
+        specifier: workspace:*
+        version: link:../../packages/workflow
       '@types/node':
         specifier: ^24.10.1
         version: 24.10.9
       '@vitejs/plugin-vue':
         specifier: ^6.0.1
-        version: 6.0.3(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))(vue@3.5.27(typescript@5.9.3))
+        version: 6.0.3(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))(vue@3.5.27(typescript@5.9.3))
       '@vue/tsconfig':
         specifier: ^0.8.1
         version: 0.8.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))
@@ -158,52 +164,12 @@ importers:
       typescript:
         specifier: ~5.9.3
         version: 5.9.3
-      vite:
-        specifier: npm:rolldown-vite@7.2.5
-        version: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
-      vue-tsc:
-        specifier: ^3.1.4
-        version: 3.2.2(typescript@5.9.3)
-
-  apps/workflow:
-    dependencies:
-      '@antv/x6':
-        specifier: ^3.1.4
-        version: 3.1.4
-      less:
-        specifier: ^4.5.1
-        version: 4.5.1
-      less-loader:
-        specifier: ^12.3.0
-        version: 12.3.0(@rspack/core@1.7.3)(less@4.5.1)
-      normalize.css:
-        specifier: ^8.0.1
-        version: 8.0.1
       unocss:
         specifier: ^66.6.0
-        version: 66.6.0(postcss@8.5.6)(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))
-      vue:
-        specifier: ^3.5.24
-        version: 3.5.27(typescript@5.9.3)
-    devDependencies:
-      '@repo/typescript-config':
-        specifier: workspace:*
-        version: link:../../packages/typescript-config
-      '@types/node':
-        specifier: ^24.10.1
-        version: 24.10.9
-      '@vitejs/plugin-vue':
-        specifier: ^6.0.1
-        version: 6.0.3(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))(vue@3.5.27(typescript@5.9.3))
-      '@vue/tsconfig':
-        specifier: ^0.8.1
-        version: 0.8.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3))
-      typescript:
-        specifier: ~5.9.3
-        version: 5.9.3
+        version: 66.6.0(postcss@8.5.6)(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))
       vite:
         specifier: npm:rolldown-vite@7.2.5
-        version: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
+        version: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)
       vue-tsc:
         specifier: ^3.1.4
         version: 3.2.2(typescript@5.9.3)
@@ -219,7 +185,7 @@ importers:
         version: link:../typescript-config
       '@umijs/openapi':
         specifier: ^1.14.1
-        version: 1.14.1(typescript@5.9.3)
+        version: 1.14.1(chokidar@5.0.0)(typescript@5.9.3)
 
   packages/api-service:
     devDependencies:
@@ -231,7 +197,7 @@ importers:
         version: link:../typescript-config
       '@umijs/openapi':
         specifier: ^1.14.1
-        version: 1.14.1(typescript@5.9.3)
+        version: 1.14.1(chokidar@5.0.0)(typescript@5.9.3)
 
   packages/eslint-config:
     devDependencies:
@@ -269,20 +235,30 @@ importers:
         specifier: ^8.50.0
         version: 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.2)
 
-  packages/typescript-config:
-    devDependencies:
-      '@repo/typescript-config':
-        specifier: workspace:*
-        version: 'link:'
+  packages/nodes: {}
+
+  packages/typescript-config: {}
 
   packages/workflow:
     dependencies:
       '@antv/x6':
         specifier: ^3.1.4
         version: 3.1.4
+      '@vue-flow/background':
+        specifier: ^1.3.2
+        version: 1.3.2(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
+      '@vue-flow/controls':
+        specifier: ^1.1.3
+        version: 1.1.3(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
       '@vue-flow/core':
         specifier: ^1.48.1
         version: 1.48.1(vue@3.5.27(typescript@5.9.3))
+      '@vue-flow/minimap':
+        specifier: ^1.5.4
+        version: 1.5.4(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
+      '@vue-flow/node-toolbar':
+        specifier: ^1.1.1
+        version: 1.1.1(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
       less:
         specifier: ^4.5.1
         version: 4.5.1
@@ -943,24 +919,28 @@ packages:
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@biomejs/cli-linux-arm64@2.3.11':
     resolution: {integrity: sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g==}
     engines: {node: '>=14.21.3'}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@biomejs/cli-linux-x64-musl@2.3.11':
     resolution: {integrity: sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@biomejs/cli-linux-x64@2.3.11':
     resolution: {integrity: sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg==}
     engines: {node: '>=14.21.3'}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@biomejs/cli-win32-arm64@2.3.11':
     resolution: {integrity: sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw==}
@@ -1895,24 +1875,28 @@ packages:
     engines: {node: ^20.19.0 || >=22.12.0}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@rolldown/binding-linux-arm64-musl@1.0.0-beta.50':
     resolution: {integrity: sha512-L0zRdH2oDPkmB+wvuTl+dJbXCsx62SkqcEqdM+79LOcB+PxbAxxjzHU14BuZIQdXcAVDzfpMfaHWzZuwhhBTcw==}
     engines: {node: ^20.19.0 || >=22.12.0}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@rolldown/binding-linux-x64-gnu@1.0.0-beta.50':
     resolution: {integrity: sha512-gyoI8o/TGpQd3OzkJnh1M2kxy1Bisg8qJ5Gci0sXm9yLFzEXIFdtc4EAzepxGvrT2ri99ar5rdsmNG0zP0SbIg==}
     engines: {node: ^20.19.0 || >=22.12.0}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@rolldown/binding-linux-x64-musl@1.0.0-beta.50':
     resolution: {integrity: sha512-zti8A7M+xFDpKlghpcCAzyOi+e5nfUl3QhU023ce5NCgUxRG5zGP2GR9LTydQ1rnIPwZUVBWd4o7NjZDaQxaXA==}
     engines: {node: ^20.19.0 || >=22.12.0}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@rolldown/binding-openharmony-arm64@1.0.0-beta.50':
     resolution: {integrity: sha512-eZUssog7qljrrRU9Mi0eqYEPm3Ch0UwB+qlWPMKSUXHNqhm3TvDZarJQdTevGEfu3EHAXJvBIe0YFYr0TPVaMA==}
@@ -1978,21 +1962,25 @@ packages:
     resolution: {integrity: sha512-SodEX3+1/GLz0LobX9cY1QdjJ1NftSEh4C2vGpr71iA3MS9HyXuw4giqSeRQ4DpCybqpdS/3RLjVqFQEfGpcnw==}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@rspack/binding-linux-arm64-musl@1.7.3':
     resolution: {integrity: sha512-ydD2fNdEy+G7EYJ/a3FfdFZPfrLj/UnZocCNlZTTSHEhu+jURdQk0hwV11CvL+sjnKU5e/8IVMGUzhu3Gu8Ghg==}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@rspack/binding-linux-x64-gnu@1.7.3':
     resolution: {integrity: sha512-adnDbUqafSAI6/N6vZ+iONSo1W3yUpnNtJqP3rVp7+YdABhUpbOhtaY37qpIJ3uFajXctYFyISPrb4MWl1M9Yg==}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@rspack/binding-linux-x64-musl@1.7.3':
     resolution: {integrity: sha512-5jnjdODk5HCUFPN6rTaFukynDU4Fn9eCL+4TSp6mqo6YAnfnJEuzDjfetA8t3aQFcAs7WriQfNwvdcA4HvYtbA==}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@rspack/binding-wasm32-wasi@1.7.3':
     resolution: {integrity: sha512-WLQK0ksUzMkVeGoHAMIxenmeEU5tMvFDK36Aip7VRj7T6vZTcAwvbMwc38QrIAvlG7dqWoxgPQi35ba1igNNDw==}
@@ -2448,41 +2436,49 @@ packages:
     resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   '@unrs/resolver-binding-linux-arm64-musl@1.11.1':
     resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
     resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
     cpu: [ppc64]
     os: [linux]
+    libc: [glibc]
 
   '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
     resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
     cpu: [riscv64]
     os: [linux]
+    libc: [glibc]
 
   '@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
     resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
     cpu: [riscv64]
     os: [linux]
+    libc: [musl]
 
   '@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
     resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
     cpu: [s390x]
     os: [linux]
+    libc: [glibc]
 
   '@unrs/resolver-binding-linux-x64-gnu@1.11.1':
     resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   '@unrs/resolver-binding-linux-x64-musl@1.11.1':
     resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   '@unrs/resolver-binding-wasm32-wasi@1.11.1':
     resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@@ -2523,11 +2519,35 @@ packages:
   '@vscode/l10n@0.0.18':
     resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==}
 
+  '@vue-flow/background@1.3.2':
+    resolution: {integrity: sha512-eJPhDcLj1wEo45bBoqTXw1uhl0yK2RaQGnEINqvvBsAFKh/camHJd5NPmOdS1w+M9lggc9igUewxaEd3iCQX2w==}
+    peerDependencies:
+      '@vue-flow/core': ^1.23.0
+      vue: ^3.3.0
+
+  '@vue-flow/controls@1.1.3':
+    resolution: {integrity: sha512-XCf+G+jCvaWURdFlZmOjifZGw3XMhN5hHlfMGkWh9xot+9nH9gdTZtn+ldIJKtarg3B21iyHU8JjKDhYcB6JMw==}
+    peerDependencies:
+      '@vue-flow/core': ^1.23.0
+      vue: ^3.3.0
+
   '@vue-flow/core@1.48.1':
     resolution: {integrity: sha512-3IxaMBLvWRbznZ4CuK0kVhp4Y4lCDQx9nhi48Swp6PwPw29KNhmiKd2kaBogYeWjGLb/tLjlE9V0s3jEmKCYWw==}
     peerDependencies:
       vue: ^3.3.0
 
+  '@vue-flow/minimap@1.5.4':
+    resolution: {integrity: sha512-l4C+XTAXnRxsRpUdN7cAVFBennC1sVRzq4bDSpVK+ag7tdMczAnhFYGgbLkUw3v3sY6gokyWwMl8CDonp8eB2g==}
+    peerDependencies:
+      '@vue-flow/core': ^1.23.0
+      vue: ^3.3.0
+
+  '@vue-flow/node-toolbar@1.1.1':
+    resolution: {integrity: sha512-vgSnGMLd3FXstdpvC721qcBDzGkPsudmyA8urEP55/EMikCp59klgzPvVULTDxxsew5MdXtTBCumsqOi+PXJdg==}
+    peerDependencies:
+      '@vue-flow/core': ^1.23.0
+      vue: ^3.3.0
+
   '@vue/compiler-core@3.5.27':
     resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==}
 
@@ -4012,24 +4032,28 @@ packages:
     engines: {node: '>= 12.0.0'}
     cpu: [arm64]
     os: [linux]
+    libc: [glibc]
 
   lightningcss-linux-arm64-musl@1.31.1:
     resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
     engines: {node: '>= 12.0.0'}
     cpu: [arm64]
     os: [linux]
+    libc: [musl]
 
   lightningcss-linux-x64-gnu@1.31.1:
     resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
     engines: {node: '>= 12.0.0'}
     cpu: [x64]
     os: [linux]
+    libc: [glibc]
 
   lightningcss-linux-x64-musl@1.31.1:
     resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
     engines: {node: '>= 12.0.0'}
     cpu: [x64]
     os: [linux]
+    libc: [musl]
 
   lightningcss-win32-arm64-msvc@1.31.1:
     resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==}
@@ -5593,17 +5617,17 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@babel/eslint-parser@7.19.1(@babel/core@7.28.6)(eslint@9.39.1(jiti@2.6.1))':
+  '@babel/eslint-parser@7.19.1(@babel/core@7.28.6)(eslint@8.57.1)':
     dependencies:
       '@babel/core': 7.28.6
       '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1
-      eslint: 9.39.1(jiti@2.6.1)
+      eslint: 8.57.1
       eslint-visitor-keys: 2.1.0
       semver: 6.3.1
 
   '@babel/eslint-plugin@7.27.1(@babel/eslint-parser@7.19.1(@babel/core@7.28.6)(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))':
     dependencies:
-      '@babel/eslint-parser': 7.19.1(@babel/core@7.28.6)(eslint@9.39.1(jiti@2.6.1))
+      '@babel/eslint-parser': 7.19.1(@babel/core@7.28.6)(eslint@8.57.1)
       eslint: 9.39.1(jiti@2.6.1)
       eslint-rule-composer: 0.3.0
 
@@ -7219,13 +7243,13 @@ snapshots:
   '@flowgram.ai/eslint-config@1.0.7(@types/node@18.19.130)(jiti@2.6.1)(typescript@5.9.3)':
     dependencies:
       '@babel/core': 7.28.6
-      '@babel/eslint-parser': 7.19.1(@babel/core@7.28.6)(eslint@9.39.1(jiti@2.6.1))
+      '@babel/eslint-parser': 7.19.1(@babel/core@7.28.6)(eslint@8.57.1)
       '@babel/eslint-plugin': 7.27.1(@babel/eslint-parser@7.19.1(@babel/core@7.28.6)(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
       '@babel/preset-env': 7.20.2(@babel/core@7.28.6)
       '@babel/preset-react': 7.13.13(@babel/core@7.28.6)
       '@eslint/eslintrc': 3.3.3
       '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
-      '@typescript-eslint/parser': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
+      '@typescript-eslint/parser': 8.50.0(eslint@8.57.1)(typescript@5.9.3)
       eslint: 9.39.1(jiti@2.6.1)
       eslint-config-prettier: 8.10.2(eslint@9.39.1(jiti@2.6.1))
       eslint-define-config: 1.12.0
@@ -8392,7 +8416,7 @@ snapshots:
   '@typescript-eslint/eslint-plugin@8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
     dependencies:
       '@eslint-community/regexpp': 4.12.2
-      '@typescript-eslint/parser': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
+      '@typescript-eslint/parser': 8.50.0(eslint@8.57.1)(typescript@5.9.3)
       '@typescript-eslint/scope-manager': 8.50.0
       '@typescript-eslint/type-utils': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
       '@typescript-eslint/utils': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
@@ -8405,27 +8429,27 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.2)':
+  '@typescript-eslint/parser@8.50.0(eslint@8.57.1)(typescript@5.9.3)':
     dependencies:
       '@typescript-eslint/scope-manager': 8.50.0
       '@typescript-eslint/types': 8.50.0
-      '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.2)
+      '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
       '@typescript-eslint/visitor-keys': 8.50.0
       debug: 4.4.3(supports-color@5.5.0)
-      eslint: 9.39.1(jiti@2.6.1)
-      typescript: 5.9.2
+      eslint: 8.57.1
+      typescript: 5.9.3
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)':
+  '@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.2)':
     dependencies:
       '@typescript-eslint/scope-manager': 8.50.0
       '@typescript-eslint/types': 8.50.0
-      '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
+      '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.2)
       '@typescript-eslint/visitor-keys': 8.50.0
       debug: 4.4.3(supports-color@5.5.0)
       eslint: 9.39.1(jiti@2.6.1)
-      typescript: 5.9.3
+      typescript: 5.9.2
     transitivePeerDependencies:
       - supports-color
 
@@ -8550,7 +8574,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@umijs/openapi@1.14.1(typescript@5.9.3)':
+  '@umijs/openapi@1.14.1(chokidar@5.0.0)(typescript@5.9.3)':
     dependencies:
       chalk: 4.1.2
       cosmiconfig: 9.0.0(typescript@5.9.3)
@@ -8562,7 +8586,7 @@ snapshots:
       mockjs: 1.1.0
       node-fetch: 2.7.0
       number-to-words: 1.2.4
-      nunjucks: 3.2.4
+      nunjucks: 3.2.4(chokidar@5.0.0)
       openapi3-ts: 2.0.2
       prettier: 2.8.8
       reserved-words: 0.1.2
@@ -8576,13 +8600,13 @@ snapshots:
 
   '@ungap/structured-clone@1.3.0': {}
 
-  '@unocss/astro@66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))':
+  '@unocss/astro@66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))':
     dependencies:
       '@unocss/core': 66.6.0
       '@unocss/reset': 66.6.0
-      '@unocss/vite': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))
+      '@unocss/vite': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))
     optionalDependencies:
-      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
+      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)
 
   '@unocss/cli@66.6.0':
     dependencies:
@@ -8712,7 +8736,7 @@ snapshots:
     dependencies:
       '@unocss/core': 66.6.0
 
-  '@unocss/vite@66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))':
+  '@unocss/vite@66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))':
     dependencies:
       '@jridgewell/remapping': 2.3.5
       '@unocss/config': 66.6.0
@@ -8723,7 +8747,7 @@ snapshots:
       pathe: 2.0.3
       tinyglobby: 0.2.15
       unplugin-utils: 0.3.1
-      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
+      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)
 
   '@unrs/resolver-binding-android-arm-eabi@1.11.1':
     optional: true
@@ -8784,10 +8808,10 @@ snapshots:
   '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
     optional: true
 
-  '@vitejs/plugin-vue@6.0.3(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))(vue@3.5.27(typescript@5.9.3))':
+  '@vitejs/plugin-vue@6.0.3(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))(vue@3.5.27(typescript@5.9.3))':
     dependencies:
       '@rolldown/pluginutils': 1.0.0-beta.53
-      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
+      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)
       vue: 3.5.27(typescript@5.9.3)
 
   '@volar/language-core@2.4.27':
@@ -8804,6 +8828,16 @@ snapshots:
 
   '@vscode/l10n@0.0.18': {}
 
+  '@vue-flow/background@1.3.2(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
+    dependencies:
+      '@vue-flow/core': 1.48.1(vue@3.5.27(typescript@5.9.3))
+      vue: 3.5.27(typescript@5.9.3)
+
+  '@vue-flow/controls@1.1.3(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
+    dependencies:
+      '@vue-flow/core': 1.48.1(vue@3.5.27(typescript@5.9.3))
+      vue: 3.5.27(typescript@5.9.3)
+
   '@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3))':
     dependencies:
       '@vueuse/core': 10.11.1(vue@3.5.27(typescript@5.9.3))
@@ -8815,6 +8849,18 @@ snapshots:
     transitivePeerDependencies:
       - '@vue/composition-api'
 
+  '@vue-flow/minimap@1.5.4(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
+    dependencies:
+      '@vue-flow/core': 1.48.1(vue@3.5.27(typescript@5.9.3))
+      d3-selection: 3.0.0
+      d3-zoom: 3.0.0
+      vue: 3.5.27(typescript@5.9.3)
+
+  '@vue-flow/node-toolbar@1.1.1(@vue-flow/core@1.48.1(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
+    dependencies:
+      '@vue-flow/core': 1.48.1(vue@3.5.27(typescript@5.9.3))
+      vue: 3.5.27(typescript@5.9.3)
+
   '@vue/compiler-core@3.5.27':
     dependencies:
       '@babel/parser': 7.28.6
@@ -9674,14 +9720,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-module-utils@2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1)):
+  eslint-module-utils@2.12.1(@typescript-eslint/parser@8.50.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1):
     dependencies:
       debug: 3.2.7
     optionalDependencies:
-      '@typescript-eslint/parser': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
-      eslint: 9.39.1(jiti@2.6.1)
+      '@typescript-eslint/parser': 8.50.0(eslint@8.57.1)(typescript@5.9.3)
+      eslint: 8.57.1
       eslint-import-resolver-node: 0.3.9
-      eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1))
     transitivePeerDependencies:
       - supports-color
 
@@ -9701,7 +9746,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.57.1
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)))(eslint@9.39.1(jiti@2.6.1))
+      eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.50.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1)
       hasown: 2.0.2
       is-core-module: 2.16.1
       is-glob: 4.0.3
@@ -9713,7 +9758,7 @@ snapshots:
       string.prototype.trimend: 1.0.9
       tsconfig-paths: 3.15.0
     optionalDependencies:
-      '@typescript-eslint/parser': 8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
+      '@typescript-eslint/parser': 8.50.0(eslint@8.57.1)(typescript@5.9.3)
     transitivePeerDependencies:
       - eslint-import-resolver-typescript
       - eslint-import-resolver-webpack
@@ -10505,7 +10550,7 @@ snapshots:
     dependencies:
       language-subtag-registry: 0.3.23
 
-  less-loader@12.3.0(@rspack/core@1.7.3)(less@4.5.1):
+  less-loader@12.3.0(@rspack/core@1.7.3(@swc/helpers@0.5.18))(less@4.5.1):
     dependencies:
       less: 4.5.1
     optionalDependencies:
@@ -11194,11 +11239,13 @@ snapshots:
 
   number-to-words@1.2.4: {}
 
-  nunjucks@3.2.4:
+  nunjucks@3.2.4(chokidar@5.0.0):
     dependencies:
       a-sync-waterfall: 1.0.1
       asap: 2.0.6
       commander: 5.1.0
+    optionalDependencies:
+      chokidar: 5.0.0
 
   oas-kit-common@1.0.8:
     dependencies:
@@ -11753,7 +11800,7 @@ snapshots:
     dependencies:
       glob: 7.2.3
 
-  rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1):
+  rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2):
     dependencies:
       '@oxc-project/runtime': 0.97.0
       fdir: 6.5.0(picomatch@4.0.3)
@@ -11767,6 +11814,7 @@ snapshots:
       fsevents: 2.3.3
       jiti: 2.6.1
       less: 4.5.1
+      yaml: 1.10.2
 
   rolldown@1.0.0-beta.50:
     dependencies:
@@ -12318,9 +12366,9 @@ snapshots:
       unist-util-is: 6.0.1
       unist-util-visit-parents: 6.0.2
 
-  unocss@66.6.0(postcss@8.5.6)(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)):
+  unocss@66.6.0(postcss@8.5.6)(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)):
     dependencies:
-      '@unocss/astro': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))
+      '@unocss/astro': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))
       '@unocss/cli': 66.6.0
       '@unocss/core': 66.6.0
       '@unocss/postcss': 66.6.0(postcss@8.5.6)
@@ -12338,9 +12386,9 @@ snapshots:
       '@unocss/transformer-compile-class': 66.6.0
       '@unocss/transformer-directives': 66.6.0
       '@unocss/transformer-variant-group': 66.6.0
-      '@unocss/vite': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1))
+      '@unocss/vite': 66.6.0(rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2))
     optionalDependencies:
-      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)
+      vite: rolldown-vite@7.2.5(@types/node@24.10.9)(jiti@2.6.1)(less@4.5.1)(yaml@1.10.2)
     transitivePeerDependencies:
       - postcss
       - supports-color