diff --git a/plugins/process-manager/.github/workflows/release.yml b/plugins/process-manager/.github/workflows/release.yml
new file mode 100644
index 00000000..870f1b9d
--- /dev/null
+++ b/plugins/process-manager/.github/workflows/release.yml
@@ -0,0 +1,36 @@
+name: Build and Release
+
+on:
+ workflow_dispatch:
+
+permissions:
+ contents: write
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - run: npm i
+
+ - run: npm run build
+
+ - name: Get package info
+ id: pkg
+ run: |
+ echo "name=$(node -p "require('./package.json').name")" >> "$GITHUB_OUTPUT"
+ echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
+
+ - name: Zip dist
+ run: cd dist && zip -r ../${{ steps.pkg.outputs.name }}-v${{ steps.pkg.outputs.version }}.zip . && cd ..
+
+ - name: Create Release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: v${{ steps.pkg.outputs.version }}
+ files: ${{ steps.pkg.outputs.name }}-v${{ steps.pkg.outputs.version }}.zip
diff --git a/plugins/process-manager/.gitignore b/plugins/process-manager/.gitignore
new file mode 100644
index 00000000..2cbd7ded
--- /dev/null
+++ b/plugins/process-manager/.gitignore
@@ -0,0 +1,32 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+# vibe coding
+.agents
+.reasonix
+reasonix*
+.opencode
+skills-lock.json
+
diff --git a/plugins/process-manager/CHANGELOG.md b/plugins/process-manager/CHANGELOG.md
new file mode 100644
index 00000000..f09ccc97
--- /dev/null
+++ b/plugins/process-manager/CHANGELOG.md
@@ -0,0 +1,20 @@
+# Changelog
+
+## [1.0.0] — 2026-07-07
+
+### 🎉 初始发布
+
+Process Port Manager 正式发布 — 为 ZTools 打造的进程端口管理插件,支持快速搜索进程、端口、PID、路径,并一键 Kill 进程。
+
+### ✨ 功能特性
+
+- **🔍 多维搜索** — 支持按进程名、PID、端口号、文件路径模糊搜索,一处输入全字段匹配
+- **📋 一键复制** — 点击进程名 / PID / 端口号 / 路径即可复制到剪贴板
+- **⚡ 一键 Kill 进程** — 通过右键唤出确认弹窗,确认后调用 `taskkill /F` 强制终止进程
+- **🔄 自动刷新** — 5 秒缓存 TTL,进度条直观展示缓存倒计时
+- **🌙 暗色模式** — 跟随系统主题自适应,UI 与 ZTools 原生风格统一
+- **🪟 Windows 原生** — 基于 `wmic` / `netstat` / `tasklist`,零第三方系统依赖
+
+### 📄 许可
+
+MIT License
diff --git a/plugins/process-manager/LICENSE b/plugins/process-manager/LICENSE
new file mode 100644
index 00000000..2339c405
--- /dev/null
+++ b/plugins/process-manager/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 lvlizhe
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/plugins/process-manager/README.md b/plugins/process-manager/README.md
new file mode 100644
index 00000000..1aa91281
--- /dev/null
+++ b/plugins/process-manager/README.md
@@ -0,0 +1,202 @@
+
+
+
+
+进程端口管理
+Process Port Manager — 为 ZTools 打造的进程端口管理插件
+
+
+
+
+
+
+> 🤖 **本项目由 [Vibe Coding](https://github.com/nicepkg/vibe-coding) 维护** — AI 辅助驱动的开发模式,让想法快速变为代码。
+
+---
+
+## 💡 为什么选择 Process Port Manager?
+
+- **UI 和谐统一** — 背景、字体、配色沿用 ZTools 本身,如同原生功能,无视觉割裂感
+- **信息简洁清晰** — 只展示进程名、PID、端口、路径等关键信息,点击任意字段即可一键复制
+- **开放源代码** — MIT 协议开源,可自由修改、扩展、二次开发
+
+---
+
+
+## 📸 界面预览
+### 暗黑
+
+
+
+### 明亮
+
+
+
+## ✨ 功能特性
+
+- **🔍 多维搜索** — 支持按进程名、PID、端口号、文件路径模糊搜索,一处输入全字段匹配
+- **📋 一键复制** — 点击进程名 / PID / 端口号 / 路径即可复制到剪贴板
+- **⚡ 一键 Kill** — 确认后通过 `taskkill /F` 强制终止进程
+- **🔄 自动刷新** — 5 秒缓存 TTL,进度条直观展示缓存倒计时
+- **🌙 暗色模式** — 跟随系统主题自适应
+- **🪟 Windows 原生** — 基于 `wmic` / `netstat` / `tasklist`,无第三方依赖
+
+
+## 🚀 快速开始
+
+### 安装依赖
+
+```bash
+npm install
+```
+
+### 开发模式
+
+```bash
+npm run dev
+```
+
+开发服务器将在 `http://localhost:5173` 启动。ZTools 会自动加载开发版本。
+
+### 构建生产版本
+
+```bash
+npm run build
+```
+
+构建产物将输出到 `dist/` 目录。
+
+## 📁 项目结构
+
+```
+.
+├── public/
+│ ├── logo.svg # 插件图标(SVG)
+│ ├── plugin.json # 插件配置(功能指令、平台等)
+│ └── preload/
+│ └── services.js # Node.js 层:进程枚举、端口扫描、Kill
+├── src/
+│ ├── main.tsx # 入口文件
+│ ├── main.css # 全局样式(含暗色模式)
+│ ├── App.tsx # 根组件(路由分发)
+│ ├── env.d.ts # 类型声明(ztools / services)
+│ └── ProcessManager/
+│ ├── index.tsx # 主界面组件
+│ ├── index.css # 组件样式
+│ ├── search.ts # 多功能搜索(进程名/PID/端口/路径)
+│ └── useProcessData.ts # 进程数据获取 + 缓存 + 定时刷新
+├── index.html
+├── vite.config.js
+├── tsconfig.json
+├── package.json
+└── README.md
+```
+
+## 🧠 核心逻辑
+
+### 数据流
+
+```
+┌─────────────────────┐
+│ services.js │ ← Node.js preload
+│ ─ listProcesses() │ wmic / tasklist
+│ ─ scanPorts() │ netstat -ano
+│ ─ killProcess() │ taskkill /F
+└────────┬────────────┘
+ │ window.services.*
+ ▼
+┌─────────────────────┐
+│ useProcessData.ts │ ← 5s 缓存 + 防抖刷新
+│ ─ processes[] │
+│ ─ refresh() │
+└────────┬────────────┘
+ ▼
+┌─────────────────────┐
+│ search.ts │ ← 按 PID/端口/进程名/路径 过滤
+│ ─ searchProcesses()│
+└────────┬────────────┘
+ ▼
+┌─────────────────────┐
+│ ProcessManager │ ← React 组件渲染
+│ → 进程列表 + Kill │
+└─────────────────────┘
+```
+
+### 主要依赖
+
+| 模块 | 职责 |
+| -------------------------- | --------------------------------------------------------------------- |
+| `services.js` | 通过 `wmic` 枚举进程、`netstat -ano` 扫描端口、`taskkill /F` 终止进程 |
+| `useProcessData.ts` | 管理进程数据状态,5 秒缓存 TTL,自动/手动刷新 |
+| `search.ts` | 多字段模糊匹配:进程名、PID、端口、路径 |
+| `ProcessManager/index.tsx` | 主界面:搜索栏、结果列表、Kill 按钮、Toast 提示 |
+
+## 🔧 插件配置
+
+编辑 `public/plugin.json`:
+
+```json
+{
+ "name": "process-manager",
+ "title": "进程端口管理",
+ "description": "快速搜索进程、端口、PID、路径,支持一键 Kill 进程,支持深色模式",
+ "features": [
+ {
+ "code": "process",
+ "explain": "快速搜索进程、端口、PID,支持一键 Kill",
+ "cmds": ["pid", "port", "process", "端口", "进程", "进程管理"]
+ }
+ ],
+ "platform": ["win32"]
+}
+```
+
+触发指令:`pid` / `port` / `process` / `端口` / `进程` / `进程管理`
+
+> ⚠ 当前仅支持 Windows 平台(依赖 `wmic`、`netstat`、`taskkill`)。
+
+## 📦 构建与发布
+
+```bash
+npm run build # 构建
+```
+
+将 `dist/` 目录中的所有文件复制到 ZTools 插件目录即可使用。
+
+## 🎨 样式开发
+
+组件使用 CSS 变量实现主题适配与暗色模式:
+
+```css
+/* 跟随 ZTools 主题 */
+.pm {
+ background: var(--bg-color);
+ color: var(--text-color);
+}
+
+/* 暗色模式自适应 */
+@media (prefers-color-scheme: dark) {
+ .pm-item {
+ background: #2a2a2a;
+ }
+}
+```
+
+## 🤖 Vibe Coding 说明
+
+本项目采用 **Vibe Coding** 理念进行维护:
+
+- **AI 优先** — 需求描述直接转化为可用代码,快速迭代
+- **最小阻力** — 减少手动配置,聚焦核心功能
+- **持续优化** — 在 AI 辅助下不断重构和完善
+
+欢迎通过 Issue 或 PR 贡献想法和改进!
+
+
+## 📄 开源协议
+
+MIT License
+
+---
+
+**优化建议或问题?欢迎提出 Issue!** 🎉
diff --git a/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-design.md b/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-design.md
new file mode 100644
index 00000000..0bb2ad9b
--- /dev/null
+++ b/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-design.md
@@ -0,0 +1,167 @@
+# Process Port Manager — Design Spec
+
+## Overview
+
+A ZTools plugin (utools-like launcher) for searching and killing Windows processes by PID, port number, process name, or file path. Built with React 18 + Vite + TypeScript, following the existing plugin template patterns.
+
+## Architecture
+
+**Approach: React component + preload services backend**
+
+```
+preload/services.js src/ProcessManager/
+ listProcesses() index.tsx (UI component)
+ scanPorts() index.css
+ killProcess(pid) useProcessData.ts (collection + cache hook)
+ search.ts (smart matching engine)
+```
+
+- `services.js` — thin system-command layer, exposes 3 async methods
+- React component — state management, search filtering, cache control, rendering
+- `search.ts` — pure function: `(keyword, processes) => filtered[]` with auto-detect matching
+
+## Data Flow
+
+```
+User types "8080"
+ │
+ ▼
+search.ts smart matching
+ │ auto-detects: number → match PID + Port
+ ▼
+Filter in cached process list
+ │
+ ├─ click Kill ──► services.killProcess(pid) ──► toast result
+ │
+ └─ continue typing ──► real-time filter (cache only, no re-collect)
+```
+
+**Cache strategy:**
+- On feature enter: call `listProcesses()` + `scanPorts()` once
+- Merge data by PID into `ProcessInfo[]`
+- Cache for 5 seconds
+- Within 5s: search filters cache only
+- After 5s: auto-refresh on next keystroke
+
+## Preload Services API
+
+```ts
+interface ProcessRaw { pid: number; name: string; path: string; status: string }
+interface PortEntry { port: number; pid: number; protocol: string }
+
+services.listProcesses(): Promise
+services.scanPorts(): Promise
+services.killProcess(pid: number): Promise<{ success: boolean; error?: string }>
+```
+
+**Windows implementation:**
+- `listProcesses` → `tasklist /FO CSV /NH`
+- `scanPorts` → `netstat -ano` parse all TCP/UDP (listening + established)
+- `killProcess` → `taskkill /PID /F`, catch error on permission failure
+
+## Smart Matching Engine
+
+Pure function with no side effects. Matching priority:
+
+| Input | Match behavior |
+|---|---|
+| `8080` (numeric) | Match PID and Port |
+| `chrome` (alpha) | Match process name (case-insensitive) |
+| `nginx.exe` (has `.exe`) | Match name + path |
+| `C:\Users` (has path sep) | Match file path |
+| `443 8080` (multiple nums) | Match multiple ports/PIDs |
+
+Sorting: exact match > prefix match > fuzzy contains.
+
+## Core Types
+
+```ts
+interface ProcessInfo {
+ pid: number
+ name: string
+ path: string
+ ports: number[]
+}
+```
+
+## UI Layout
+
+```
+┌─────────────────────────────────────┐
+│ 🔍 搜索进程... │
+│ [进程名] [PID] [路径...] [✕] │
+│ 🔌 8080 🔌 443 🔌 3000 │
+├─────────────────────────────────────┤
+│ [chrome.exe] [1234] 路径... [✕] │
+│ 🔌 8080 🔌 443 │
+├─────────────────────────────────────┤
+│ [node.exe] [5678] 路径... [✕] │
+│ 🔌 9229 │
+├─────────────────────────────────────┤
+│ 共3个结果 5s后自动刷新 │
+└─────────────────────────────────────┘
+```
+
+- **Row 1**: `[name tag] [PID tag] [path...]` + Kill `✕` button right-aligned, vertically centered
+- **Row 2**: Port tags `🔌 port`
+- Every info element is clickable to copy its content (toast: "已复制: xxx")
+- Search auto-focuses, real-time filtering
+
+## Interaction
+
+- Enter via ZTools command trigger (keywords: `pid`, `port`, `process`, `端口`, `进程`, `进程管理`)
+- Kill button click → confirmation dialog → `services.killProcess(pid)` → success/error toast
+- Permission errors shown as toast, not thrown
+
+## Theme / Color Scheme
+
+### Light — Blue-Purple (default)
+| Element | Background | Text |
+|---|---|---|
+| Process name tag | `#e8eaf6` | `#283593` |
+| PID tag | `#f3e8ff` | `#7c3aed` |
+| Port tag | `#eef2ff` | `#4f6ef7` |
+| Path | transparent | `#b0b0c0` |
+| Search box | `#f0f2f5` | `#333` |
+| Kill button | `#fee2e2` | `#ef4444` |
+| Kill hover | `#ef4444` | `#fff` |
+
+### Dark — Terminal Green
+| Element | Background | Text |
+|---|---|---|
+| Background | `#0d1117` | — |
+| Process name tag | `#1a3a2a` | `#7ee787` |
+| PID tag | `#3a2a1a` | `#d29922` |
+| Port tag | `#1a2a3a` | `#58a6ff` |
+| Path | transparent | `#8b949e` |
+| Search box | `#21262d` | `#c9d1d9` |
+| Kill button | `#3a1a1a` | `#fca5a5` |
+| Kill hover | `#ef4444` | `#fff` |
+
+## Theme Switching
+
+Theme follows the OS-level `prefers-color-scheme` media query. No manual toggle. When the user switches their OS between light/dark mode, the plugin adapts automatically via CSS media queries.
+
+Implementation: define two CSS classless theme blocks scoped by `@media (prefers-color-scheme: light/dark)`.
+
+## YAGNI Exclusions
+
+- No CPU/memory usage display (not needed for port/process search)
+- No process status tag (removed as not meaningful)
+- No continuous polling — cached 5s refresh only
+- No batch kill — single process kill only
+- No remote process management — local Windows only
+
+## Files to Create
+
+### New files
+- `src/ProcessManager/index.tsx` — main component
+- `src/ProcessManager/index.css` — styles
+- `src/ProcessManager/search.ts` — matching engine
+- `src/ProcessManager/useProcessData.ts` — data hook
+
+### Modified files
+- `public/plugin.json` — register new feature with cmds: `pid`, `port`, `process`, `端口`, `进程`, `进程管理`
+- `public/preload/services.js` — add listProcesses, scanPorts, killProcess
+- `src/App.tsx` — add ProcessManager route
+- `src/env.d.ts` — add types for new services
diff --git a/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-plan.md b/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-plan.md
new file mode 100644
index 00000000..f7aa6cd7
--- /dev/null
+++ b/plugins/process-manager/docs/superpowers/specs/2026-07-06-process-manager-plan.md
@@ -0,0 +1,45 @@
+# Process Port Manager — Implementation Plan
+
+## Step 1: preload services (`public/preload/services.js`)
+- Add `listProcesses()` using `tasklist /FO CSV /NH` (Windows)
+- Add `scanPorts()` using `netstat -ano` parsing
+- Add `killProcess(pid)` using `taskkill /PID /F`
+- Wrap all in try/catch, return structured results
+
+## Step 2: type declarations (`src/env.d.ts`)
+- Add `ProcessRaw`, `PortEntry`, `ProcessInfo` interfaces
+- Extend `Window.services` with new methods
+
+## Step 3: plugin config (`public/plugin.json`)
+- Register new feature `code: "process"` with cmds: `pid`, `port`, `process`, `端口`, `进程`, `进程管理`
+
+## Step 4: smart matching engine (`src/ProcessManager/search.ts`)
+- Pure function `searchProcesses(keyword, list): ProcessInfo[]`
+- Numeric detection → match PID + Port
+- Alpha detection → match name (case-insensitive)
+- Path detection → match path
+- Multiple values → OR match
+- Sort: exact > prefix > fuzzy
+
+## Step 5: data hook (`src/ProcessManager/useProcessData.ts`)
+- On mount: call `services.listProcesses()` + `services.scanPorts()`
+- Merge by PID into `ProcessInfo[]`
+- Cache with 5s TTL
+- Expose `processes`, `loading`, `refresh`, `lastFetched`
+
+## Step 6: UI component (`src/ProcessManager/index.tsx` + `index.css`)
+- Search input (auto-focus, controlled)
+- Result list with items showing: [name tag] [PID tag] [path...] + Kill button
+- Port tags on second row
+- Click-to-copy on each info element
+- Kill confirmation → call services.killProcess
+- Theme light/dark via `prefers-color-scheme`
+- Footer with count + refresh timer
+
+## Step 7: routing (`src/App.tsx`)
+- Import ProcessManager
+- Add route `process` → ProcessManager
+
+## Step 8: verify
+- `npm run build` passes
+- UI matches mockups
diff --git a/plugins/process-manager/index.html b/plugins/process-manager/index.html
new file mode 100644
index 00000000..84b7eb68
--- /dev/null
+++ b/plugins/process-manager/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/process-manager/package.json b/plugins/process-manager/package.json
new file mode 100644
index 00000000..8327b646
--- /dev/null
+++ b/plugins/process-manager/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "process-manager",
+ "version": "1.0.0",
+ "description": "",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build"
+ },
+ "dependencies": {
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-icons": "^5.7.0"
+ },
+ "devDependencies": {
+ "@types/react": "^19.0.8",
+ "@types/react-dom": "^19.0.3",
+ "@vitejs/plugin-react": "^4.3.1",
+ "@ztools-center/ztools-api-types": "^1.0.1",
+ "typescript": "^5.3.0",
+ "vite": "^6.0.11"
+ }
+}
diff --git a/plugins/process-manager/pnpm-lock.yaml b/plugins/process-manager/pnpm-lock.yaml
new file mode 100644
index 00000000..5818c351
--- /dev/null
+++ b/plugins/process-manager/pnpm-lock.yaml
@@ -0,0 +1,1154 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ react:
+ specifier: ^19.0.0
+ version: 19.2.7
+ react-dom:
+ specifier: ^19.0.0
+ version: 19.2.7(react@19.2.7)
+ react-icons:
+ specifier: ^5.7.0
+ version: 5.7.0(react@19.2.7)
+ devDependencies:
+ '@types/react':
+ specifier: ^19.0.8
+ version: 19.2.17
+ '@types/react-dom':
+ specifier: ^19.0.3
+ version: 19.2.3(@types/react@19.2.17)
+ '@vitejs/plugin-react':
+ specifier: ^4.3.1
+ version: 4.7.0(vite@6.4.3)
+ '@ztools-center/ztools-api-types':
+ specifier: ^1.0.1
+ version: 1.0.3
+ typescript:
+ specifier: ^5.3.0
+ version: 5.9.3
+ vite:
+ specifier: ^6.0.11
+ version: 6.4.3
+
+packages:
+
+ '@babel/code-frame@7.29.7':
+ resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.7':
+ resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.7':
+ resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.7':
+ resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.29.7':
+ resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.29.7':
+ resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.29.7':
+ resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.29.7':
+ resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.29.7':
+ resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.29.7':
+ resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.29.7':
+ resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.29.7':
+ resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.7':
+ resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.7':
+ resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.29.7':
+ resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.29.7':
+ resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.29.7':
+ resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.7':
+ resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.7':
+ resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==}
+ engines: {node: '>=6.9.0'}
+
+ '@esbuild/aix-ppc64@0.25.12':
+ resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.25.12':
+ resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.25.12':
+ resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.25.12':
+ resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.25.12':
+ resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.25.12':
+ resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.25.12':
+ resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.25.12':
+ resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.25.12':
+ resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.25.12':
+ resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.25.12':
+ resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.25.12':
+ resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.25.12':
+ resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.25.12':
+ resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.25.12':
+ resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.25.12':
+ resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
+ '@esbuild/netbsd-x64@0.25.12':
+ resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
+ '@esbuild/openbsd-x64@0.25.12':
+ resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@esbuild/sunos-x64@0.25.12':
+ resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.25.12':
+ resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.25.12':
+ resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.25.12':
+ resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@rolldown/pluginutils@1.0.0-beta.27':
+ resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+
+ '@rollup/rollup-android-arm-eabi@4.62.2':
+ resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.62.2':
+ resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.62.2':
+ resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.62.2':
+ resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.62.2':
+ resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.62.2':
+ resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.62.2':
+ resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==}
+ cpu: [arm]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.62.2':
+ resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==}
+ cpu: [arm]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-arm64-gnu@4.62.2':
+ resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-arm64-musl@4.62.2':
+ resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-loong64-gnu@4.62.2':
+ resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-loong64-musl@4.62.2':
+ resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==}
+ cpu: [loong64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.62.2':
+ resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-ppc64-musl@4.62.2':
+ resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.62.2':
+ resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-riscv64-musl@4.62.2':
+ resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-linux-s390x-gnu@4.62.2':
+ resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-gnu@4.62.2':
+ resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rollup/rollup-linux-x64-musl@4.62.2':
+ resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rollup/rollup-openbsd-x64@4.62.2':
+ resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@rollup/rollup-openharmony-arm64@4.62.2':
+ resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rollup/rollup-win32-arm64-msvc@4.62.2':
+ resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.62.2':
+ resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-gnu@4.62.2':
+ resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==}
+ cpu: [x64]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.62.2':
+ resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/estree@1.0.9':
+ resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
+
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
+ '@types/react@19.2.17':
+ resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==}
+
+ '@vitejs/plugin-react@4.7.0':
+ resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ '@ztools-center/ztools-api-types@1.0.3':
+ resolution: {integrity: sha512-dv1eOAIasAupqKaQL/gESk1i2+RebdM/1gvZhrvH2D/bo3enCUsAGJ8nrHnlCLBSOGB81eC/SU0IH8BNsUlmvA==}
+
+ baseline-browser-mapping@2.10.42:
+ resolution: {integrity: sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ browserslist@4.28.5:
+ resolution: {integrity: sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ caniuse-lite@1.0.30001803:
+ resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ electron-to-chromium@1.5.388:
+ resolution: {integrity: sha512-Pl/aJaqOOxYxda3vcx1IKSJimwYXHDkEnGn0F+kG2EE68dDtx2uCinaS+Vih8Z91B9t8CSAbiF/HKyWcnXjhzw==}
+
+ esbuild@0.25.12:
+ resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.15:
+ resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-releases@2.0.50:
+ resolution: {integrity: sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==}
+ engines: {node: '>=18'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.5:
+ resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
+ engines: {node: '>=12'}
+
+ postcss@8.5.16:
+ resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ react-dom@19.2.7:
+ resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==}
+ peerDependencies:
+ react: ^19.2.7
+
+ react-icons@5.7.0:
+ resolution: {integrity: sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw==}
+ peerDependencies:
+ react: '*'
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@19.2.7:
+ resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==}
+ engines: {node: '>=0.10.0'}
+
+ rollup@4.62.2:
+ resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
+ typescript@5.9.3:
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ vite@6.4.3:
+ resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+snapshots:
+
+ '@babel/code-frame@7.29.7':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.29.7
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.7': {}
+
+ '@babel/core@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.7
+ '@babel/helper-compilation-targets': 7.29.7
+ '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
+ '@babel/helpers': 7.29.7
+ '@babel/parser': 7.29.7
+ '@babel/template': 7.29.7
+ '@babel/traverse': 7.29.7
+ '@babel/types': 7.29.7
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.7':
+ dependencies:
+ '@babel/parser': 7.29.7
+ '@babel/types': 7.29.7
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.29.7':
+ dependencies:
+ '@babel/compat-data': 7.29.7
+ '@babel/helper-validator-option': 7.29.7
+ browserslist: 4.28.5
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.29.7': {}
+
+ '@babel/helper-module-imports@7.29.7':
+ dependencies:
+ '@babel/traverse': 7.29.7
+ '@babel/types': 7.29.7
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-module-imports': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+ '@babel/traverse': 7.29.7
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.29.7': {}
+
+ '@babel/helper-string-parser@7.29.7': {}
+
+ '@babel/helper-validator-identifier@7.29.7': {}
+
+ '@babel/helper-validator-option@7.29.7': {}
+
+ '@babel/helpers@7.29.7':
+ dependencies:
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.7
+
+ '@babel/parser@7.29.7':
+ dependencies:
+ '@babel/types': 7.29.7
+
+ '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-plugin-utils': 7.29.7
+
+ '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/helper-plugin-utils': 7.29.7
+
+ '@babel/template@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/parser': 7.29.7
+ '@babel/types': 7.29.7
+
+ '@babel/traverse@7.29.7':
+ dependencies:
+ '@babel/code-frame': 7.29.7
+ '@babel/generator': 7.29.7
+ '@babel/helper-globals': 7.29.7
+ '@babel/parser': 7.29.7
+ '@babel/template': 7.29.7
+ '@babel/types': 7.29.7
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.7':
+ dependencies:
+ '@babel/helper-string-parser': 7.29.7
+ '@babel/helper-validator-identifier': 7.29.7
+
+ '@esbuild/aix-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/android-arm@0.25.12':
+ optional: true
+
+ '@esbuild/android-x64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/darwin-x64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-arm@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/linux-loong64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.25.12':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.25.12':
+ optional: true
+
+ '@esbuild/linux-s390x@0.25.12':
+ optional: true
+
+ '@esbuild/linux-x64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.25.12':
+ optional: true
+
+ '@esbuild/openharmony-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/sunos-x64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-arm64@0.25.12':
+ optional: true
+
+ '@esbuild/win32-ia32@0.25.12':
+ optional: true
+
+ '@esbuild/win32-x64@0.25.12':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@rolldown/pluginutils@1.0.0-beta.27': {}
+
+ '@rollup/rollup-android-arm-eabi@4.62.2':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-loong64-musl@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-musl@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.62.2':
+ optional: true
+
+ '@rollup/rollup-openbsd-x64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-openharmony-arm64@4.62.2':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.62.2':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.62.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-gnu@4.62.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.62.2':
+ optional: true
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.29.7
+ '@babel/types': 7.29.7
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.29.7
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.29.7
+ '@babel/types': 7.29.7
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.29.7
+
+ '@types/estree@1.0.9': {}
+
+ '@types/react-dom@19.2.3(@types/react@19.2.17)':
+ dependencies:
+ '@types/react': 19.2.17
+
+ '@types/react@19.2.17':
+ dependencies:
+ csstype: 3.2.3
+
+ '@vitejs/plugin-react@4.7.0(vite@6.4.3)':
+ dependencies:
+ '@babel/core': 7.29.7
+ '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7)
+ '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7)
+ '@rolldown/pluginutils': 1.0.0-beta.27
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 6.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@ztools-center/ztools-api-types@1.0.3': {}
+
+ baseline-browser-mapping@2.10.42: {}
+
+ browserslist@4.28.5:
+ dependencies:
+ baseline-browser-mapping: 2.10.42
+ caniuse-lite: 1.0.30001803
+ electron-to-chromium: 1.5.388
+ node-releases: 2.0.50
+ update-browserslist-db: 1.2.3(browserslist@4.28.5)
+
+ caniuse-lite@1.0.30001803: {}
+
+ convert-source-map@2.0.0: {}
+
+ csstype@3.2.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ electron-to-chromium@1.5.388: {}
+
+ esbuild@0.25.12:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.25.12
+ '@esbuild/android-arm': 0.25.12
+ '@esbuild/android-arm64': 0.25.12
+ '@esbuild/android-x64': 0.25.12
+ '@esbuild/darwin-arm64': 0.25.12
+ '@esbuild/darwin-x64': 0.25.12
+ '@esbuild/freebsd-arm64': 0.25.12
+ '@esbuild/freebsd-x64': 0.25.12
+ '@esbuild/linux-arm': 0.25.12
+ '@esbuild/linux-arm64': 0.25.12
+ '@esbuild/linux-ia32': 0.25.12
+ '@esbuild/linux-loong64': 0.25.12
+ '@esbuild/linux-mips64el': 0.25.12
+ '@esbuild/linux-ppc64': 0.25.12
+ '@esbuild/linux-riscv64': 0.25.12
+ '@esbuild/linux-s390x': 0.25.12
+ '@esbuild/linux-x64': 0.25.12
+ '@esbuild/netbsd-arm64': 0.25.12
+ '@esbuild/netbsd-x64': 0.25.12
+ '@esbuild/openbsd-arm64': 0.25.12
+ '@esbuild/openbsd-x64': 0.25.12
+ '@esbuild/openharmony-arm64': 0.25.12
+ '@esbuild/sunos-x64': 0.25.12
+ '@esbuild/win32-arm64': 0.25.12
+ '@esbuild/win32-ia32': 0.25.12
+ '@esbuild/win32-x64': 0.25.12
+
+ escalade@3.2.0: {}
+
+ fdir@6.5.0(picomatch@4.0.5):
+ optionalDependencies:
+ picomatch: 4.0.5
+
+ fsevents@2.3.3:
+ optional: true
+
+ gensync@1.0.0-beta.2: {}
+
+ js-tokens@4.0.0: {}
+
+ jsesc@3.1.0: {}
+
+ json5@2.2.3: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.15: {}
+
+ node-releases@2.0.50: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.5: {}
+
+ postcss@8.5.16:
+ dependencies:
+ nanoid: 3.3.15
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ react-dom@19.2.7(react@19.2.7):
+ dependencies:
+ react: 19.2.7
+ scheduler: 0.27.0
+
+ react-icons@5.7.0(react@19.2.7):
+ dependencies:
+ react: 19.2.7
+
+ react-refresh@0.17.0: {}
+
+ react@19.2.7: {}
+
+ rollup@4.62.2:
+ dependencies:
+ '@types/estree': 1.0.9
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.62.2
+ '@rollup/rollup-android-arm64': 4.62.2
+ '@rollup/rollup-darwin-arm64': 4.62.2
+ '@rollup/rollup-darwin-x64': 4.62.2
+ '@rollup/rollup-freebsd-arm64': 4.62.2
+ '@rollup/rollup-freebsd-x64': 4.62.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.62.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.62.2
+ '@rollup/rollup-linux-arm64-gnu': 4.62.2
+ '@rollup/rollup-linux-arm64-musl': 4.62.2
+ '@rollup/rollup-linux-loong64-gnu': 4.62.2
+ '@rollup/rollup-linux-loong64-musl': 4.62.2
+ '@rollup/rollup-linux-ppc64-gnu': 4.62.2
+ '@rollup/rollup-linux-ppc64-musl': 4.62.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.62.2
+ '@rollup/rollup-linux-riscv64-musl': 4.62.2
+ '@rollup/rollup-linux-s390x-gnu': 4.62.2
+ '@rollup/rollup-linux-x64-gnu': 4.62.2
+ '@rollup/rollup-linux-x64-musl': 4.62.2
+ '@rollup/rollup-openbsd-x64': 4.62.2
+ '@rollup/rollup-openharmony-arm64': 4.62.2
+ '@rollup/rollup-win32-arm64-msvc': 4.62.2
+ '@rollup/rollup-win32-ia32-msvc': 4.62.2
+ '@rollup/rollup-win32-x64-gnu': 4.62.2
+ '@rollup/rollup-win32-x64-msvc': 4.62.2
+ fsevents: 2.3.3
+
+ scheduler@0.27.0: {}
+
+ semver@6.3.1: {}
+
+ source-map-js@1.2.1: {}
+
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
+
+ typescript@5.9.3: {}
+
+ update-browserslist-db@1.2.3(browserslist@4.28.5):
+ dependencies:
+ browserslist: 4.28.5
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ vite@6.4.3:
+ dependencies:
+ esbuild: 0.25.12
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
+ postcss: 8.5.16
+ rollup: 4.62.2
+ tinyglobby: 0.2.17
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ yallist@3.1.1: {}
diff --git a/plugins/process-manager/public/logo.svg b/plugins/process-manager/public/logo.svg
new file mode 100644
index 00000000..7300af33
--- /dev/null
+++ b/plugins/process-manager/public/logo.svg
@@ -0,0 +1,33 @@
+
\ No newline at end of file
diff --git a/plugins/process-manager/public/plugin.json b/plugins/process-manager/public/plugin.json
new file mode 100644
index 00000000..2a5b3ece
--- /dev/null
+++ b/plugins/process-manager/public/plugin.json
@@ -0,0 +1,33 @@
+{
+ "$schema": "node_modules/@ztools-center/ztools-api-types/resource/ztools.schema.json",
+ "name": "process-manager",
+ "title": "进程端口管理",
+ "description": "快速搜索进程、端口、PID、路径,支持一键 Kill 进程,支持深色模式",
+ "author": "Agitator",
+ "version": "1.0.0",
+ "homepage": "https://github.com/Code-Agitator/process-manager",
+ "main": "index.html",
+ "preload": "preload/services.js",
+ "logo": "logo.svg",
+ "development": {
+ "main": "http://localhost:5173"
+ },
+ "features": [
+ {
+ "code": "process",
+ "explain": "快速搜索进程、端口、PID,支持一键 Kill",
+ "icon": "logo.svg",
+ "cmds": [
+ "pid",
+ "port",
+ "process",
+ "端口",
+ "进程",
+ "进程管理"
+ ]
+ }
+ ],
+ "platform": [
+ "win32"
+ ]
+}
\ No newline at end of file
diff --git a/plugins/process-manager/public/preload/package.json b/plugins/process-manager/public/preload/package.json
new file mode 100644
index 00000000..5bbefffb
--- /dev/null
+++ b/plugins/process-manager/public/preload/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "commonjs"
+}
diff --git a/plugins/process-manager/public/preload/services.js b/plugins/process-manager/public/preload/services.js
new file mode 100644
index 00000000..4eae12cb
--- /dev/null
+++ b/plugins/process-manager/public/preload/services.js
@@ -0,0 +1,99 @@
+const { exec, spawn } = require('node:child_process')
+
+function execAsync(cmd, timeout) {
+ return new Promise((resolve) => {
+ exec(cmd, { timeout }, (err, stdout) => {
+ resolve(err ? '' : stdout)
+ })
+ })
+}
+
+function parseWmicCsv(output) {
+ const lines = output.trim().replace(/\r/g, '').split('\n').filter(Boolean)
+ if (lines.length < 2) return []
+ const header = lines[0].split(',').map(h => h.trim().toLowerCase())
+ const nameIdx = header.indexOf('name')
+ const pidIdx = header.indexOf('processid')
+ const pathIdx = header.indexOf('executablepath')
+ if (nameIdx === -1 || pidIdx === -1) return []
+
+ return lines.slice(1).map(line => {
+ const parts = line.startsWith('"')
+ ? line.replace(/^"|"$/g, '').split('","')
+ : line.split(',')
+ return {
+ name: (parts[nameIdx] || '').trim(),
+ pid: parseInt(parts[pidIdx], 10) || 0,
+ path: (parts[pathIdx] || '').trim()
+ }
+ }).filter(p => p.pid > 0)
+}
+
+function parseNetstat(output) {
+ const lines = output.trim().replace(/\r/g, '').split('\n').filter(Boolean)
+ const ports = []
+ for (const line of lines) {
+ const parts = line.trim().split(/\s+/)
+ if (parts.length < 5) continue
+ const addr = parts[1]
+ const pid = parseInt(parts[4], 10)
+ if (!addr || isNaN(pid)) continue
+ const portMatch = addr.match(/:(\d+)$/)
+ if (portMatch) {
+ ports.push({ port: parseInt(portMatch[1], 10), pid, protocol: parts[0] })
+ }
+ }
+ return ports
+}
+
+window.services = {
+ async listProcesses() {
+ let raw = await execAsync('wmic process get ProcessId,Name,ExecutablePath /FORMAT:CSV', 8000)
+ if (raw) return parseWmicCsv(raw)
+ raw = await execAsync('tasklist /FO CSV /NH', 5000)
+ if (!raw) return []
+ const lines = raw.trim().replace(/\r/g, '').split('\n').filter(Boolean)
+ return lines.map(line => {
+ const parts = line.replace(/^"|"$/g, '').split('","')
+ return { name: parts[0] || '', pid: parseInt(parts[1], 10) || 0, path: '' }
+ }).filter(p => p.pid > 0)
+ },
+
+ async scanPorts() {
+ const raw = await execAsync('netstat -ano', 5000)
+ return raw ? parseNetstat(raw) : []
+ },
+
+ async killProcess(pid) {
+ // 严格校验 pid 为正整数
+ if (!Number.isInteger(pid) || pid <= 0) {
+ return { success: false, error: '无效的 PID' }
+ }
+
+ return new Promise((resolve) => {
+ const child = spawn('taskkill', ['/PID', String(pid), '/F'], {
+ timeout: 3000,
+ stdio: ['ignore', 'pipe', 'pipe']
+ })
+
+ let stderr = ''
+ child.stderr.on('data', (data) => {
+ stderr += data.toString()
+ })
+
+ child.on('close', (code) => {
+ if (code === 0) {
+ resolve({ success: true })
+ } else {
+ console.error('Kill process failed:', stderr)
+ resolve({ success: false, error: 'Kill 失败' })
+ }
+ })
+
+ child.on('error', (err) => {
+ console.error('Kill process error:', err)
+ resolve({ success: false, error: 'Kill 失败' })
+ })
+ })
+ }
+}
diff --git a/plugins/process-manager/snapshot/image1.png b/plugins/process-manager/snapshot/image1.png
new file mode 100644
index 00000000..199a0f93
Binary files /dev/null and b/plugins/process-manager/snapshot/image1.png differ
diff --git a/plugins/process-manager/snapshot/image2.png b/plugins/process-manager/snapshot/image2.png
new file mode 100644
index 00000000..f83839fb
Binary files /dev/null and b/plugins/process-manager/snapshot/image2.png differ
diff --git a/plugins/process-manager/snapshot/image3.png b/plugins/process-manager/snapshot/image3.png
new file mode 100644
index 00000000..b192c526
Binary files /dev/null and b/plugins/process-manager/snapshot/image3.png differ
diff --git a/plugins/process-manager/snapshot/image4.png b/plugins/process-manager/snapshot/image4.png
new file mode 100644
index 00000000..5ac2742b
Binary files /dev/null and b/plugins/process-manager/snapshot/image4.png differ
diff --git a/plugins/process-manager/src/App.tsx b/plugins/process-manager/src/App.tsx
new file mode 100644
index 00000000..cb8aaec6
--- /dev/null
+++ b/plugins/process-manager/src/App.tsx
@@ -0,0 +1,28 @@
+import { useEffect, useState } from 'react'
+import ProcessManager from './ProcessManager'
+
+export default function App() {
+ const [_, setRoute] = useState('')
+ const [keyword, setKeyword] = useState('')
+
+ useEffect(() => {
+ window.ztools.onPluginEnter((action) => {
+ setRoute(action.code)
+ if (action.code === 'process') {
+ setKeyword('')
+ window.ztools.setSubInput(
+ (input) => setKeyword(input.text),
+ '输入 PID / 端口 / 进程名 / 路径搜索...'
+ )
+ }
+ })
+ window.ztools.onPluginOut(() => {
+ setRoute('')
+ setKeyword('')
+ window.ztools.removeSubInput()
+ })
+ }, [])
+
+ return
+
+}
diff --git a/plugins/process-manager/src/ProcessManager/index.css b/plugins/process-manager/src/ProcessManager/index.css
new file mode 100644
index 00000000..3ae1b085
--- /dev/null
+++ b/plugins/process-manager/src/ProcessManager/index.css
@@ -0,0 +1,448 @@
+.pm {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ overflow: hidden;
+ background: transparent;
+ color: #333;
+ font-size: 13px;
+}
+
+.pm-header {
+ padding: 10px 16px;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+}
+
+.pm-hints {
+ display: flex;
+ gap: 4px;
+ flex-wrap: wrap;
+}
+
+.pm-hint {
+ font-size: 10px;
+ padding: 1px 7px;
+ border-radius: 4px;
+ font-weight: 500;
+}
+
+.pm-hint-name { background: #e8eaf6; color: #283593; }
+.pm-hint-pid { background: #f3e8ff; color: #7c3aed; }
+.pm-hint-port { background: #eef2ff; color: #4f6ef7; }
+.pm-hint-path { background: rgba(0, 0, 0, 0.06); color: #888; }
+
+.pm-body {
+ flex: 1;
+ overflow-y: auto;
+ padding: 4px 0;
+ width: 100%;
+ scrollbar-width: thin;
+ scrollbar-color: rgba(0, 0, 0, 0.2) rgba(0, 0, 0, 0.05);
+}
+
+.pm-body::-webkit-scrollbar {
+ width: 6px;
+}
+
+.pm-body::-webkit-scrollbar-track {
+ background: rgba(0, 0, 0, 0.05);
+}
+
+.pm-body::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 3px;
+}
+
+.pm-body::-webkit-scrollbar-thumb:hover {
+ background: rgba(0, 0, 0, 0.35);
+}
+
+.pm-empty {
+ text-align: center;
+ padding: 40px 16px;
+ color: #b0b0c0;
+ font-size: 13px;
+}
+
+.pm-item {
+ padding: 12px 0;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ transition: background 0.15s;
+}
+
+.pm-item:hover {
+ background: rgba(0, 0, 0, 0.03);
+}
+
+.pm-item:last-child {
+ border-bottom: none;
+}
+
+.pm-item-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ padding: 0 16px;
+}
+
+.pm-item-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.pm-item-row1 {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.pm-tag {
+ display: inline-block;
+ font-size: 10px;
+ padding: 2px 7px;
+ border-radius: 4px;
+ font-weight: 500;
+ white-space: nowrap;
+ cursor: pointer;
+ flex-shrink: 0;
+ transition: opacity 0.15s;
+}
+
+.pm-tag:active {
+ opacity: 0.5;
+}
+
+.pm-tag-name { background: #e8eaf6; color: #283593; }
+.pm-tag-pid { background: #f3e8ff; color: #7c3aed; }
+.pm-tag-port { background: #eef2ff; color: #4f6ef7; }
+.pm-tag-none { background: rgba(0, 0, 0, 0.06); color: #999; cursor: default; }
+
+.pm-path {
+ font-size: 11px;
+ color: #b0b0c0;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex: 1;
+ min-width: 0;
+ cursor: pointer;
+ padding: 2px 4px;
+ border-radius: 4px;
+ transition: background 0.15s;
+}
+
+.pm-path:hover {
+ background: rgba(0, 0, 0, 0.05);
+}
+
+.pm-tags {
+ display: flex;
+ gap: 3px;
+ flex-wrap: wrap;
+ margin-top: 5px;
+}
+
+.pm-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 16px;
+ border-top: 1px solid rgba(0, 0, 0, 0.08);
+ font-size: 11px;
+ color: #b0b0c0;
+ flex-shrink: 0;
+}
+
+.pm-footer-right {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.pm-updated {
+ font-variant-numeric: tabular-nums;
+ color: #ccc;
+}
+
+.pm-progress-tag {
+ display: inline-block;
+ width: 32px;
+ height: 6px;
+ background: #e8eaf6;
+ border-radius: 3px;
+ overflow: hidden;
+ flex-shrink: 0;
+}
+
+.pm-progress-tag .pm-progress-fill {
+ display: block;
+ height: 100%;
+ width: 0%;
+ background: linear-gradient(90deg, #4f6ef7, #7c3aed);
+ border-radius: 3px;
+}
+
+.pm-refresh {
+ background: none;
+ border: none;
+ color: #4f6ef7;
+ cursor: pointer;
+ font-weight: 500;
+ font-size: 13px;
+ padding: 0;
+ line-height: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.pm-refresh:hover {
+ opacity: 0.7;
+ transform: rotate(180deg);
+ transition: transform 0.3s ease;
+}
+
+.pm-hint-tip {
+ background: rgba(239, 68, 68, 0.08);
+ color: #ef4444;
+ font-weight: 600;
+}
+
+.pm-toast {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: #333;
+ color: #fff;
+ font-size: 12px;
+ padding: 6px 16px;
+ border-radius: 8px;
+ z-index: 1000;
+ white-space: nowrap;
+ pointer-events: none;
+}
+
+.pm-modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.4);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 2000;
+ animation: fadeIn 0.05s ease;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0.5; }
+ to { opacity: 1; }
+}
+
+.pm-modal {
+ background: #fff;
+ border-radius: 12px;
+ padding: 20px;
+ min-width: 280px;
+ max-width: 360px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+ animation: slideIn 0.08s ease;
+}
+
+@keyframes slideIn {
+ from {
+ opacity: 0.8;
+ transform: scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+.pm-modal-title {
+ font-size: 15px;
+ font-weight: 600;
+ color: #1a1a2e;
+ margin-bottom: 12px;
+}
+
+.pm-modal-content {
+ font-size: 13px;
+ color: #666;
+ line-height: 1.5;
+ margin-bottom: 20px;
+}
+
+.pm-modal-content strong {
+ color: #333;
+ font-weight: 600;
+}
+
+.pm-modal-actions {
+ display: flex;
+ gap: 10px;
+ justify-content: flex-end;
+}
+
+.pm-modal-btn {
+ padding: 8px 16px;
+ border-radius: 8px;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ border: none;
+}
+
+.pm-modal-btn-cancel {
+ background: #f0f0f0;
+ color: #666;
+}
+
+.pm-modal-btn-cancel:hover {
+ background: #e0e0e0;
+}
+
+.pm-modal-btn-confirm {
+ background: #ef4444;
+ color: #fff;
+}
+
+.pm-modal-btn-confirm:hover {
+ background: #dc2626;
+}
+
+@media (prefers-color-scheme: dark) {
+ .pm {
+ background: transparent;
+ color: #c9d1d9;
+ }
+
+ .pm-header {
+ border-bottom-color: rgba(255, 255, 255, 0.1);
+ }
+
+ .pm-hint-name { background: rgba(126, 231, 135, 0.15); color: #7ee787; }
+ .pm-hint-pid { background: rgba(210, 153, 34, 0.15); color: #d29922; }
+ .pm-hint-port { background: rgba(88, 166, 255, 0.15); color: #58a6ff; }
+ .pm-hint-path { background: rgba(255, 255, 255, 0.1); color: #8b949e; }
+
+ .pm-empty {
+ color: #8b949e;
+ }
+
+ .pm-item {
+ border-bottom-color: rgba(255, 255, 255, 0.1);
+ }
+
+ .pm-item:hover {
+ background: rgba(255, 255, 255, 0.05);
+ }
+
+ .pm-tag-name { background: rgba(126, 231, 135, 0.15); color: #7ee787; }
+ .pm-tag-pid { background: rgba(210, 153, 34, 0.15); color: #d29922; }
+ .pm-tag-port { background: rgba(88, 166, 255, 0.15); color: #58a6ff; }
+ .pm-tag-none { background: rgba(255, 255, 255, 0.1); color: #8b949e; }
+
+ .pm-path {
+ color: #8b949e;
+ }
+
+ .pm-path:hover {
+ background: rgba(255, 255, 255, 0.08);
+ }
+
+ .pm-body::-webkit-scrollbar-track {
+ background: rgba(255, 255, 255, 0.05);
+ }
+
+ .pm-body::-webkit-scrollbar-thumb {
+ background: rgba(255, 255, 255, 0.2);
+ }
+
+ .pm-body::-webkit-scrollbar-thumb:hover {
+ background: rgba(255, 255, 255, 0.35);
+ }
+
+ .pm-body {
+ scrollbar-color: rgba(255, 255, 255, 0.2) rgba(255, 255, 255, 0.05);
+ }
+
+ .pm-hint-tip {
+ background: rgba(248, 81, 73, 0.15);
+ color: #fca5a5;
+ }
+
+ .pm-toast {
+ background: #c9d1d9;
+ color: #0d1117;
+ }
+
+ .pm-footer {
+ border-top-color: rgba(255, 255, 255, 0.1);
+ color: #8b949e;
+ }
+
+ .pm-updated {
+ color: #484f58;
+ }
+ .pm-progress-tag {
+ background: rgba(255, 255, 255, 0.1);
+ }
+ .pm-progress-tag .pm-progress-fill {
+ background: linear-gradient(90deg, #58a6ff, #7ee787);
+ }
+
+ .pm-refresh {
+ color: #58a6ff;
+ }
+
+ .pm-refresh:hover {
+ opacity: 0.7;
+ transform: rotate(180deg);
+ transition: transform 0.3s ease;
+ }
+
+ .pm-modal {
+ background: #161b22;
+ }
+
+ .pm-modal-title {
+ color: #c9d1d9;
+ }
+
+ .pm-modal-content {
+ color: #8b949e;
+ }
+
+ .pm-modal-content strong {
+ color: #c9d1d9;
+ }
+
+ .pm-modal-btn-cancel {
+ background: rgba(255, 255, 255, 0.1);
+ color: #8b949e;
+ }
+
+ .pm-modal-btn-cancel:hover {
+ background: rgba(255, 255, 255, 0.15);
+ }
+
+ .pm-modal-btn-confirm {
+ background: #da3633;
+ }
+
+ .pm-modal-btn-confirm:hover {
+ background: #f85149;
+ }
+}
diff --git a/plugins/process-manager/src/ProcessManager/index.tsx b/plugins/process-manager/src/ProcessManager/index.tsx
new file mode 100644
index 00000000..54808f4b
--- /dev/null
+++ b/plugins/process-manager/src/ProcessManager/index.tsx
@@ -0,0 +1,166 @@
+import { useState, useRef, useEffect, useCallback } from 'react'
+import { FiRefreshCw } from 'react-icons/fi'
+import './index.css'
+import { searchProcesses } from './search'
+import { useProcessData } from './useProcessData'
+
+const CACHE_TTL = 5000
+
+interface Props {
+ keyword: string
+}
+
+export default function ProcessManager({ keyword }: Props) {
+ const { processes, loading, refresh, lastUpdated } = useProcessData()
+ const [toast, setToast] = useState('')
+ const [killModal, setKillModal] = useState<{ pid: number; name: string } | null>(null)
+ const [killing, setKilling] = useState(false)
+ const barRef = useRef(null)
+ const startRef = useRef(0)
+ const rafRef = useRef(0)
+ const toastTimer = useRef>(undefined)
+
+ useEffect(() => {
+ const fill = barRef.current
+ if (!fill) return
+ const tick = () => {
+ const pct = Math.min((Date.now() - startRef.current) / CACHE_TTL * 100, 100)
+ fill.style.width = pct + '%'
+ rafRef.current = requestAnimationFrame(tick)
+ }
+ startRef.current = Date.now()
+ rafRef.current = requestAnimationFrame(tick)
+ return () => cancelAnimationFrame(rafRef.current)
+ }, [])
+
+ useEffect(() => {
+ startRef.current = Date.now()
+ }, [lastUpdated])
+
+ const showToast = useCallback((msg: string) => {
+ setToast(msg)
+ clearTimeout(toastTimer.current)
+ toastTimer.current = setTimeout(() => setToast(''), 1500)
+ }, [])
+
+ const copy = useCallback((text: string) => {
+ navigator.clipboard.writeText(text).then(() => showToast('已复制: ' + text))
+ }, [showToast])
+
+ const confirmKill = useCallback((pid: number, name: string) => {
+ setKillModal({ pid, name })
+ }, [])
+
+ const executeKill = useCallback(async () => {
+ if (!killModal || killing) return
+
+ setKilling(true)
+ const result = await window.services.killProcess(killModal.pid)
+ setKilling(false)
+ setKillModal(null)
+
+ if (result.success) {
+ showToast(`已 Kill ${killModal.name} (PID: ${killModal.pid})`)
+ refresh(true)
+ } else {
+ showToast(`Kill 失败: ${result.error}`)
+ }
+ }, [killModal, killing, showToast, refresh])
+
+ const cancelKill = useCallback(() => {
+ if (killing) return
+ setKillModal(null)
+ }, [killing])
+
+ const handleContextMenu = useCallback((e: React.MouseEvent, pid: number, name: string) => {
+ e.preventDefault()
+ confirmKill(pid, name)
+ }, [confirmKill])
+
+ const filtered = searchProcesses(keyword, processes)
+
+ return (
+
+
+
+ 进程名
+ PID
+ 端口号
+ 文件路径
+
+
右键可 Kill 进程
+
+
+ {toast &&
{toast}
}
+
+
+ {loading && processes.length === 0 && (
+
正在获取进程列表...
+ )}
+
+ {!loading && filtered.length === 0 && (
+
+ {keyword ? '没有匹配的进程' : '暂无进程数据,请刷新'}
+
+ )}
+
+ {filtered.map(p => (
+
handleContextMenu(e, p.pid, p.name)}
+ >
+
+
+
+ copy(p.name)}>{p.name}
+ copy(String(p.pid))}>{p.pid}
+ copy(p.path)} title={p.path}>{p.path}
+
+
+ {p.ports.length > 0
+ ? p.ports.map(port => (
+ copy(String(port))}>{port}
+ ))
+ : 无端口占用
+ }
+
+
+
+
+ ))}
+
+
+
+ 共 {filtered.length} 个结果
+
+ {lastUpdated || '--:--:--'}
+
+
+
+
+
+ {killModal && (
+
+
e.stopPropagation()}>
+
确认 Kill 进程
+
+ {killing
+ ? <>正在 Kill {killModal.name} (PID: {killModal.pid})...>
+ : <>确定要 Kill 进程 {killModal.name} (PID: {killModal.pid}) 吗?>
+ }
+
+
+
+
+
+
+
+ )}
+
+ )
+}
diff --git a/plugins/process-manager/src/ProcessManager/search.ts b/plugins/process-manager/src/ProcessManager/search.ts
new file mode 100644
index 00000000..082f7f9f
--- /dev/null
+++ b/plugins/process-manager/src/ProcessManager/search.ts
@@ -0,0 +1,54 @@
+function compareByPortPath(a: ProcessInfo, b: ProcessInfo): number {
+ const aHasPorts = a.ports.length > 0
+ const bHasPorts = b.ports.length > 0
+ const aHasPath = a.path.length > 0
+ const bHasPath = b.path.length > 0
+
+ if (aHasPorts && aHasPath && !(bHasPorts && bHasPath)) return -1
+ if (bHasPorts && bHasPath && !(aHasPorts && aHasPath)) return 1
+ if (aHasPorts && !bHasPorts) return -1
+ if (bHasPorts && !aHasPorts) return 1
+ if (aHasPath && !bHasPath) return -1
+ if (bHasPath && !aHasPath) return 1
+
+ return 0
+}
+
+export function searchProcesses(keyword: string, processes: ProcessInfo[]): ProcessInfo[] {
+ const kw = keyword.trim()
+
+ if (!kw) {
+ return [...processes].sort(compareByPortPath)
+ }
+
+ const lower = kw.toLowerCase()
+
+ return processes
+ .map(p => {
+ let score = -1
+ const nameLower = p.name.toLowerCase()
+ const pathLower = p.path.toLowerCase()
+ const pidStr = String(p.pid)
+
+ // PID 精确匹配
+ if (pidStr === kw) return { process: p, score: 110 }
+
+ // PID/端口包含匹配
+ if (pidStr.includes(kw)) score = Math.max(score, 90)
+ if (p.ports.some(port => String(port).includes(kw))) score = Math.max(score, 85)
+
+ // 名称/路径匹配
+ if (nameLower === lower) score = Math.max(score, 100)
+ else if (nameLower.startsWith(lower)) score = Math.max(score, 80)
+ else if (nameLower.includes(lower)) score = Math.max(score, 60)
+ else if (pathLower.includes(lower)) score = Math.max(score, 50)
+
+ return { process: p, score }
+ })
+ .filter(s => s.score >= 0)
+ .sort((a, b) => {
+ if (b.score !== a.score) return b.score - a.score
+ return compareByPortPath(a.process, b.process)
+ })
+ .map(s => s.process)
+}
diff --git a/plugins/process-manager/src/ProcessManager/useProcessData.ts b/plugins/process-manager/src/ProcessManager/useProcessData.ts
new file mode 100644
index 00000000..51012d22
--- /dev/null
+++ b/plugins/process-manager/src/ProcessManager/useProcessData.ts
@@ -0,0 +1,60 @@
+import { useState, useEffect, useCallback, useRef } from 'react'
+
+const CACHE_TTL = 5000
+
+function mergeData(rawList: ProcessRaw[], rawPorts: PortEntry[]): ProcessInfo[] {
+ const portMap: Record = {}
+ for (const entry of rawPorts) {
+ if (!portMap[entry.pid]) portMap[entry.pid] = []
+ if (!portMap[entry.pid].includes(entry.port)) {
+ portMap[entry.pid].push(entry.port)
+ }
+ }
+
+ return rawList.map(p => ({
+ pid: p.pid,
+ name: p.name,
+ path: p.path,
+ ports: portMap[p.pid] || []
+ }))
+}
+
+export function useProcessData() {
+ const [processes, setProcesses] = useState([])
+ const [loading, setLoading] = useState(false)
+ const [lastUpdated, setLastUpdated] = useState('')
+ const lastFetchRef = useRef(0)
+
+ const refresh = useCallback(async (force?: boolean) => {
+ const now = Date.now()
+ if (!force && now - lastFetchRef.current < CACHE_TTL) return
+
+ if (!window.services?.listProcesses) {
+ console.warn('services not available')
+ return
+ }
+
+ setLoading(true)
+ try {
+ const [list, ports] = await Promise.all([
+ window.services.listProcesses(),
+ window.services.scanPorts()
+ ])
+ setProcesses(mergeData(list || [], ports || []))
+ setLastUpdated(new Date().toLocaleTimeString())
+ lastFetchRef.current = now
+ } catch (e) {
+ console.error('useProcessData error:', e)
+ } finally {
+ setLoading(false)
+ }
+ }, [])
+
+ useEffect(() => {
+ refresh()
+ const timer = setInterval(refresh, CACHE_TTL)
+ return () => clearInterval(timer)
+ }, [refresh])
+
+ return { processes, loading, refresh, lastUpdated }
+}
diff --git a/plugins/process-manager/src/env.d.ts b/plugins/process-manager/src/env.d.ts
new file mode 100644
index 00000000..8f864562
--- /dev/null
+++ b/plugins/process-manager/src/env.d.ts
@@ -0,0 +1,36 @@
+///
+///
+
+interface ProcessRaw {
+ name: string
+ pid: number
+ path: string
+}
+
+interface PortEntry {
+ port: number
+ pid: number
+ protocol: string
+}
+
+interface KillResult {
+ success: boolean
+ error?: string
+}
+
+interface ProcessInfo {
+ pid: number
+ name: string
+ path: string
+ ports: number[]
+}
+
+interface Services {
+ listProcesses: () => Promise
+ scanPorts: () => Promise
+ killProcess: (pid: number) => Promise
+}
+
+interface Window {
+ services: Services
+}
diff --git a/plugins/process-manager/src/main.css b/plugins/process-manager/src/main.css
new file mode 100644
index 00000000..ac61ff74
--- /dev/null
+++ b/plugins/process-manager/src/main.css
@@ -0,0 +1,14 @@
+html, body {
+ margin: 0;
+ padding: 0;
+}
+
+@media (prefers-color-scheme: light) {
+
+}
+
+@media (prefers-color-scheme: dark) {
+ body {
+ color: #fff;
+ }
+}
diff --git a/plugins/process-manager/src/main.tsx b/plugins/process-manager/src/main.tsx
new file mode 100644
index 00000000..73fb2013
--- /dev/null
+++ b/plugins/process-manager/src/main.tsx
@@ -0,0 +1,6 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import './main.css'
+import App from './App'
+
+ReactDOM.createRoot(document.getElementById('root')!).render()
diff --git a/plugins/process-manager/tsconfig.json b/plugins/process-manager/tsconfig.json
new file mode 100644
index 00000000..d49c64de
--- /dev/null
+++ b/plugins/process-manager/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": false,
+ "noImplicitAny": false,
+ "types": ["@ztools-center/ztools-api-types"]
+ },
+ "include": ["src"]
+}
diff --git a/plugins/process-manager/vite.config.js b/plugins/process-manager/vite.config.js
new file mode 100644
index 00000000..2d511098
--- /dev/null
+++ b/plugins/process-manager/vite.config.js
@@ -0,0 +1,8 @@
+import react from '@vitejs/plugin-react'
+import { defineConfig } from 'vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ base: './'
+})