vite-plugin-aipanel 1.2.22 → 1.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -87
- package/es/core/mcp-tools.d.ts +22 -0
- package/es/core/mcp-tools.mjs +159 -0
- package/es/endpoints/index.d.ts +3 -1
- package/es/endpoints/index.mjs +9 -2
- package/es/endpoints/mcp.d.ts +3 -1
- package/es/endpoints/mcp.mjs +36 -27
- package/es/index.mjs +2 -1
- package/lib/client.js +847 -854
- package/lib/core/mcp-tools.cjs +166 -0
- package/lib/core/mcp-tools.d.ts +22 -0
- package/lib/endpoints/index.cjs +9 -2
- package/lib/endpoints/index.d.ts +3 -1
- package/lib/endpoints/mcp.cjs +26 -25
- package/lib/endpoints/mcp.d.ts +3 -1
- package/lib/index.cjs +2 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -10,25 +10,14 @@
|
|
|
10
10
|
- Chrome / Edge / Arc / Brave 等 Chromium 内核浏览器
|
|
11
11
|
- 任选其一:OpenCode CLI(默认)或 DeepSeek Harness (dsh) CLI
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
### 1. 安装 AI 引擎
|
|
16
|
-
|
|
17
|
-
**默认引擎 OpenCode CLI:**
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
curl -fsSL https://opencode.ai/install | bash
|
|
21
|
-
opencode --version # 验证
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
> 使用 DeepSeek Harness 请改装:`npm i -g @deepseek-ai/dsh` + `npm i -D @aipanel/provider-deepseek`,并配置 `provider: "deepseek"`(见下)。
|
|
25
|
-
|
|
26
|
-
### 2. 安装并配置 Vite 插件
|
|
13
|
+
## 安装
|
|
27
14
|
|
|
28
15
|
```bash
|
|
29
16
|
npm install -D vite-plugin-aipanel
|
|
30
17
|
```
|
|
31
18
|
|
|
19
|
+
## 快速开始
|
|
20
|
+
|
|
32
21
|
```ts
|
|
33
22
|
// vite.config.ts
|
|
34
23
|
import { defineConfig } from "vite";
|
|
@@ -39,90 +28,26 @@ export default defineConfig({
|
|
|
39
28
|
});
|
|
40
29
|
```
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npm run dev
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
插件自动完成:校验引擎 → 启动 AIPanel Web 服务(默认 5097)与代理(默认 6097,端口占用自动换)→ 复用/创建当前项目会话。
|
|
49
|
-
|
|
50
|
-
### 4. 安装浏览器扩展
|
|
51
|
-
|
|
52
|
-
1. [下载扩展包](https://github.com/code-farmer-i/vite-plugin-aipanel/raw/main/packages/extension/aipanel-assistant.zip)
|
|
53
|
-
2. Chrome 打开 `chrome://extensions/`,开启右上角**「开发者模式」**
|
|
54
|
-
3. 解压 `.zip` → **「加载已解压的扩展程序」** → 选择解压目录
|
|
55
|
-
4. 打开 `localhost` 开发页面,点击工具栏 **AIPanel 图标**(或 `Ctrl/Cmd + K`)唤起侧边栏
|
|
56
|
-
|
|
57
|
-
> Edge / Arc / Brave 入口分别是 `edge://extensions/` / `arc://extensions/` / `brave://extensions/`。
|
|
31
|
+
启动 `npm run dev` 后,插件自动完成:校验引擎 → 启动 AIPanel Web 服务(默认 5097)与代理(默认 6097,端口占用自动换)→ 复用/创建当前项目会话。
|
|
58
32
|
|
|
59
33
|
## 切换 AI 引擎
|
|
60
34
|
|
|
61
35
|
插件默认 `provider: "default"`(等价 `"opencode"`,适配已内置,仅需安装 opencode CLI)。
|
|
62
36
|
|
|
63
|
-
| provider
|
|
64
|
-
|
|
|
65
|
-
| `default`
|
|
66
|
-
| `opencode`
|
|
67
|
-
| `deepseek`
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
// 使用 DeepSeek Harness 引擎(先安装其依赖)
|
|
71
|
-
aipanelAssistant({
|
|
72
|
-
provider: "deepseek",
|
|
73
|
-
providerOptions: {
|
|
74
|
-
// home: "~/.dsh", // dsh 数据目录
|
|
75
|
-
// agentPreset: "standard", // 新建会话的默认 Agent 预设
|
|
76
|
-
// permissionPreset: "read-only", // 默认权限预设
|
|
77
|
-
// busyEnter: "queue", // 繁忙时 Enter 行为
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
> **注意**:插件**不会自动探测**已安装的引擎,引擎由 `provider` 字段决定;切换前请确认对应 CLI 已安装。
|
|
37
|
+
| provider | 引擎 | 额外依赖 |
|
|
38
|
+
| ----------- | ---------------------- | ---------------------------------------- |
|
|
39
|
+
| `default` | OpenCode CLI | 无(适配内置;需另装 opencode CLI) |
|
|
40
|
+
| `opencode` | OpenCode CLI | 无(适配内置;需另装 opencode CLI) |
|
|
41
|
+
| `deepseek` | DeepSeek Harness (dsh) | `@aipanel/provider-deepseek` + dsh CLI |
|
|
83
42
|
|
|
84
43
|
## 纯净 MCP 模式
|
|
85
44
|
|
|
86
|
-
`mcpOnly: true`
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
aipanelAssistant({ mcpOnly: true });
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
端点挂在 Vite dev server 上(需保持 `vite dev` 运行),外部 MCP 客户端按 Streamable HTTP 配置:
|
|
93
|
-
|
|
94
|
-
```json
|
|
95
|
-
{
|
|
96
|
-
"mcpServers": {
|
|
97
|
-
"aipanel": {
|
|
98
|
-
"type": "http",
|
|
99
|
-
"url": "http://localhost:5173/__aipanel_mcp__"
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
> 端口随 Vite dev server 变化(默认 5173),以启动日志中的 `MCP endpoint` 为准;`Claude Code` / `Cursor` 等客户端配置详见在线文档。
|
|
106
|
-
|
|
107
|
-
## 工作原理
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
┌────────────────┐ ┌────────────────┐ ┌─────────────┐
|
|
111
|
-
│ Vite 插件 │ │ 浏览器扩展 │ │ OpenCode/dsh │
|
|
112
|
-
│ 启动 Web 服务 │◀────▶│ 侧边栏面板 │◀────▶│ AI 引擎 │
|
|
113
|
-
│ 代理跨域 │ │ 页面上下文同步 │ │ 会话管理 │
|
|
114
|
-
└────────────────┘ └────────────────┘ └─────────────┘
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
- Vite 插件在项目启动时自动拉起 AIPanel Web 服务
|
|
118
|
-
- 浏览器扩展检测到 `localhost` 页面后自动连接该服务
|
|
119
|
-
- 实时同步页面 URL、标题等上下文给 AI
|
|
120
|
-
- 多标签页自动切换对应项目的会话
|
|
45
|
+
`mcpOnly: true` 时插件只暴露 MCP 工具服务(Chrome DevTools 控制、Vue DevTools、日志读取等),不启动 AI 引擎、不注入对话界面,适合作为独立 MCP server 供外部 Agent 消费。
|
|
121
46
|
|
|
122
47
|
## 文档
|
|
123
48
|
|
|
124
|
-
|
|
49
|
+
完整使用指南(浏览器扩展安装、MCP 客户端配置等)请访问 [在线文档](https://code-farmer-i.github.io/vite-plugin-aipanel/),仓库见 [code-farmer-i/vite-plugin-aipanel](https://github.com/code-farmer-i/vite-plugin-aipanel)。
|
|
125
50
|
|
|
126
51
|
## License
|
|
127
52
|
|
|
128
|
-
MIT
|
|
53
|
+
MIT
|
package/es/core/mcp-tools.d.ts
CHANGED
|
@@ -5,9 +5,17 @@
|
|
|
5
5
|
* (schema/描述运行时同步自官方 tools/list,见 official-tools.ts)+ 本项目自定义工具。
|
|
6
6
|
* 工具层限制(白名单、必填 pageId、仅项目页)由本文件 + endpoints/mcp.ts 的 tools/call 共同执行。
|
|
7
7
|
*/
|
|
8
|
+
import { type VueDevtoolsAction } from "@aipanel/core";
|
|
8
9
|
/** 模型可见名前缀:官方短名 → chrome-devtools_<name> */
|
|
9
10
|
export declare const MCP_PREFIX = "chrome-devtools_";
|
|
10
11
|
export declare function displayToolName(short: string): string;
|
|
12
|
+
/** 本地桥接工具族前缀(tools/list 暴露面与 tools/call 路由共用) */
|
|
13
|
+
export declare const VUE_DEVTOOLS_PREFIX = "vue-devtools_";
|
|
14
|
+
export declare const LOGS_DEVTOOLS_PREFIX = "logs-devtools_";
|
|
15
|
+
/** Vite 进程日志工具名(工具定义与调用路由共用) */
|
|
16
|
+
export declare const VITE_LOGS_TOOL_NAME = "logs-devtools_vite_logs";
|
|
17
|
+
/** 服务日志文件工具名(按 LogFileConfig.name 生成,暴露与路由共用) */
|
|
18
|
+
export declare function serviceLogToolName(name: string): string;
|
|
11
19
|
export interface CustomTool {
|
|
12
20
|
name: string;
|
|
13
21
|
description: string;
|
|
@@ -44,6 +52,20 @@ export declare function withPageIdSchema(schema: CustomTool["inputSchema"]): Cus
|
|
|
44
52
|
export declare const PROJECT_DESCRIPTION_NOTES: Record<string, string>;
|
|
45
53
|
/** 自定义工具(官方无对应,工具层本地实现) */
|
|
46
54
|
export declare const CUSTOM_TOOLS: CustomTool[];
|
|
55
|
+
/**
|
|
56
|
+
* 页面桥接工具:描述与输入 schema(模型可见)+ 后端 action(调用分发)单一来源。
|
|
57
|
+
* tools/list 与 tools/call 都取自本定义,避免"清单"与"路由"两份来源各自漂移。
|
|
58
|
+
* 只在注入 Vue DevTools 桥的项目(Vue 项目)暴露。
|
|
59
|
+
*/
|
|
60
|
+
export interface VueDevtoolsTool extends CustomTool {
|
|
61
|
+
/** 页面桥后端 action(endpoints/vue-devtools.ts executeAction) */
|
|
62
|
+
action: VueDevtoolsAction;
|
|
63
|
+
}
|
|
64
|
+
export declare const VUE_DEVTOOLS_TOOLS: readonly VueDevtoolsTool[];
|
|
65
|
+
/** vue-devtools_* 工具名 → 定义(未知名称返回 undefined) */
|
|
66
|
+
export declare function findVueDevtoolsTool(name: string): VueDevtoolsTool | undefined;
|
|
67
|
+
/** vue-devtools_* 的 tools/list 暴露面(剥掉仅用于路由分发的 action 字段) */
|
|
68
|
+
export declare function vueDevtoolsToolList(): CustomTool[];
|
|
47
69
|
/** 官方声明了条件、且属于可开启范围的工具(由官方元数据派生,无手写) */
|
|
48
70
|
export declare function isOfficialExtraTool(short: string): boolean;
|
|
49
71
|
/** 由官方 conditions 推导所需 flag(experimentalX → --experimental-x,与官方 CLI 一致) */
|
package/es/core/mcp-tools.mjs
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { VUE_DEVTOOLS_ACTIONS } from "@aipanel/core";
|
|
1
2
|
import { OFFICIAL_TOOL_META } from "./official-meta.mjs";
|
|
2
3
|
const MCP_PREFIX = "chrome-devtools_";
|
|
3
4
|
function displayToolName(short) {
|
|
4
5
|
return MCP_PREFIX + short;
|
|
5
6
|
}
|
|
7
|
+
const VUE_DEVTOOLS_PREFIX = "vue-devtools_";
|
|
8
|
+
const LOGS_DEVTOOLS_PREFIX = "logs-devtools_";
|
|
9
|
+
const VITE_LOGS_TOOL_NAME = `${LOGS_DEVTOOLS_PREFIX}vite_logs`;
|
|
10
|
+
function serviceLogToolName(name) {
|
|
11
|
+
return `${LOGS_DEVTOOLS_PREFIX}${name}_logs`;
|
|
12
|
+
}
|
|
6
13
|
const OFFICIAL_GLOBAL_POLICY = [
|
|
7
14
|
"evaluate_script",
|
|
8
15
|
"list_console_messages",
|
|
@@ -33,8 +40,153 @@ const CUSTOM_TOOLS = [
|
|
|
33
40
|
name: displayToolName("current_page"),
|
|
34
41
|
description: "Get the page the user is currently browsing (URL, title, and page ID). Resolves the project page with injected context; for allowOrigins pages use list_pages and pass its pageId to page tools instead.",
|
|
35
42
|
inputSchema: { type: "object", properties: {} }
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: VITE_LOGS_TOOL_NAME,
|
|
46
|
+
description: `\u83B7\u53D6 Vite \u5F00\u53D1\u670D\u52A1\u5668\u7684\u8FD0\u884C\u65E5\u5FD7\u3002
|
|
47
|
+
|
|
48
|
+
**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A
|
|
49
|
+
- \u7528\u6237\u62A5\u544A"\u9875\u9762\u6CA1\u66F4\u65B0"\u3001"\u70ED\u66F4\u65B0\u4E0D\u5DE5\u4F5C"\u3001"HMR \u5931\u6548"\u65F6
|
|
50
|
+
- \u6784\u5EFA\u62A5\u9519\u6216\u7F16\u8BD1\u5931\u8D25\uFF0C\u9700\u8981\u67E5\u770B\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F
|
|
51
|
+
- \u9875\u9762\u767D\u5C4F\u3001\u6837\u5F0F\u4E22\u5931\u3001\u6A21\u5757\u52A0\u8F7D\u5931\u8D25\u7B49\u5F00\u53D1\u95EE\u9898
|
|
52
|
+
- \u7528\u6237\u63D0\u5230"\u5F00\u53D1\u670D\u52A1\u5668\u6709\u95EE\u9898"\u3001"vite \u62A5\u9519"
|
|
53
|
+
- \u9700\u8981\u786E\u8BA4\u6700\u8FD1\u7684\u6587\u4EF6\u53D8\u66F4\u662F\u5426\u88AB Vite \u6B63\u786E\u5904\u7406
|
|
54
|
+
|
|
55
|
+
**\u65E5\u5FD7\u5185\u5BB9**\uFF1A
|
|
56
|
+
- Vite HMR \u70ED\u66F4\u65B0\u65E5\u5FD7\uFF08\u54EA\u4E9B\u6587\u4EF6\u88AB\u66F4\u65B0\u3001\u66F4\u65B0\u72B6\u6001\uFF09
|
|
57
|
+
- \u6784\u5EFA\u7F16\u8BD1\u65E5\u5FD7\uFF08\u9519\u8BEF\u3001\u8B66\u544A\u3001\u6210\u529F\u4FE1\u606F\uFF09
|
|
58
|
+
- OpenCode Web \u8FDB\u7A0B\u8F93\u51FA
|
|
59
|
+
- \u63D2\u4EF6\u8FD0\u884C\u65E5\u5FD7
|
|
60
|
+
|
|
61
|
+
\u65E5\u5FD7\u4FDD\u5B58\u5728\u5185\u5B58\u7F13\u51B2\u533A\uFF08\u6700\u8FD1 500 \u6761\uFF09\u3002`,
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {
|
|
65
|
+
level: {
|
|
66
|
+
type: "string",
|
|
67
|
+
description: "\u65E5\u5FD7\u7EA7\u522B\u8FC7\u6EE4\uFF1Aerror(\u9519\u8BEF)\u3001warn(\u8B66\u544A)\u3001info(\u4FE1\u606F)\u3001debug(\u8C03\u8BD5)\u3001log(\u666E\u901A)\u3002\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF0C\u5982 'error,warn'"
|
|
68
|
+
},
|
|
69
|
+
limit: {
|
|
70
|
+
type: "integer",
|
|
71
|
+
minimum: 1,
|
|
72
|
+
maximum: 200,
|
|
73
|
+
default: 50,
|
|
74
|
+
description: "\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 50\uFF0C\u6700\u5927 200"
|
|
75
|
+
},
|
|
76
|
+
source: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "\u6765\u6E90\u8FC7\u6EE4\uFF1Aconsole(\u63A7\u5236\u53F0)\u3001provider-stdout(\u670D\u52A1\u8F93\u51FA)\u3001provider-stderr(\u670D\u52A1\u9519\u8BEF)"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
const VUE_DEVTOOLS_TOOLS = [
|
|
85
|
+
{
|
|
86
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_apps`,
|
|
87
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_APPS,
|
|
88
|
+
description: `\u83B7\u53D6\u6307\u5B9A\u9875\u9762\u6240\u6709 Vue \u5E94\u7528\u5B9E\u4F8B\u5217\u8868\u3002
|
|
89
|
+
|
|
90
|
+
**\u4F55\u65F6\u4F7F\u7528**\uFF1A
|
|
91
|
+
- \u6392\u67E5\u5FAE\u524D\u7AEF/\u591A\u5B9E\u4F8B\u573A\u666F\u4E0B\u64CD\u4F5C\u7684\u662F\u54EA\u4E2A\u5E94\u7528
|
|
92
|
+
- \u5207\u6362\u6D3B\u8DC3\u5E94\u7528\u524D\u67E5\u770B\u6709\u54EA\u4E9B\u53EF\u7528`,
|
|
93
|
+
inputSchema: withPageIdSchema({ type: "object", properties: {} })
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: `${VUE_DEVTOOLS_PREFIX}set_active_app`,
|
|
97
|
+
action: VUE_DEVTOOLS_ACTIONS.TOGGLE_APP,
|
|
98
|
+
description: `\u5207\u6362\u6307\u5B9A\u9875\u9762\u7684\u6D3B\u8DC3 Vue \u5E94\u7528\u5B9E\u4F8B\u3002\u540E\u7EED\u6240\u6709 vue-devtools_* \u5DE5\u5177\u90FD\u64CD\u4F5C\u8FD9\u4E2A\u5E94\u7528\u3002`,
|
|
99
|
+
inputSchema: withPageIdSchema({
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
appId: { type: "string", description: "\u5E94\u7528 ID\uFF08\u4ECE vue-devtools_get_apps \u83B7\u53D6\uFF09" }
|
|
103
|
+
},
|
|
104
|
+
required: ["appId"]
|
|
105
|
+
})
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_component_tree`,
|
|
109
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_TREE,
|
|
110
|
+
description: `\u83B7\u53D6\u6307\u5B9A\u9875\u9762\u5F53\u524D\u6D3B\u8DC3 Vue \u5E94\u7528\u7684\u7EC4\u4EF6\u6811\u3002
|
|
111
|
+
|
|
112
|
+
**\u4F55\u65F6\u4F7F\u7528**\uFF1A
|
|
113
|
+
- \u4E86\u89E3\u9875\u9762\u7EC4\u4EF6\u5C42\u7EA7\u7ED3\u6784
|
|
114
|
+
- \u627E\u5230\u76EE\u6807\u7EC4\u4EF6\u7684 nodeId\uFF08\u540E\u7EED\u67E5\u72B6\u6001\u7528\uFF09
|
|
115
|
+
- \u6392\u67E5\u7EC4\u4EF6\u672A\u6E32\u67D3\u95EE\u9898
|
|
116
|
+
- \u53EA\u5173\u5FC3\u67D0\u7C7B\u7EC4\u4EF6\u65F6\u7528 filter \u7F29\u5C0F\u8303\u56F4
|
|
117
|
+
|
|
118
|
+
**\u8FD4\u56DE**\uFF1A\u7EC4\u4EF6\u6811 [{ id, name, children, file, ... }]`,
|
|
119
|
+
inputSchema: withPageIdSchema({
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
filter: { type: "string", description: "\u6309\u7EC4\u4EF6\u540D\u8FC7\u6EE4\uFF08\u5927\u5C0F\u5199\u4E0D\u654F\u611F\u7684\u5B50\u4E32\u5339\u914D\uFF09\uFF0C\u53EF\u9009" }
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_component_state`,
|
|
128
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_STATE,
|
|
129
|
+
description: `\u83B7\u53D6\u6307\u5B9A\u7EC4\u4EF6\u7684\u5B8C\u6574\u8FD0\u884C\u65F6\u72B6\u6001\u3002
|
|
130
|
+
|
|
131
|
+
**\u4F55\u65F6\u4F7F\u7528**\uFF1A
|
|
132
|
+
- \u6392\u67E5 props \u4F20\u503C\u662F\u5426\u6B63\u786E
|
|
133
|
+
- \u67E5\u770B ref/reactive \u54CD\u5E94\u5F0F\u6570\u636E\u7684\u5F53\u524D\u503C
|
|
134
|
+
- \u68C0\u67E5 computed \u8BA1\u7B97\u7ED3\u679C
|
|
135
|
+
- \u67E5\u770B attrs / events / inject / provide / template refs`,
|
|
136
|
+
inputSchema: withPageIdSchema({
|
|
137
|
+
type: "object",
|
|
138
|
+
properties: {
|
|
139
|
+
nodeId: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "\u7EC4\u4EF6\u8282\u70B9 ID\uFF08\u4ECE vue-devtools_get_component_tree \u83B7\u53D6\uFF09"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
required: ["nodeId"]
|
|
145
|
+
})
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_component_render_code`,
|
|
149
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_RENDER_CODE,
|
|
150
|
+
description: `\u83B7\u53D6\u7EC4\u4EF6\u7684\u6E32\u67D3\u51FD\u6570\u6E90\u7801\u3002`,
|
|
151
|
+
inputSchema: withPageIdSchema({
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: { nodeId: { type: "string", description: "\u7EC4\u4EF6\u8282\u70B9 ID" } },
|
|
154
|
+
required: ["nodeId"]
|
|
155
|
+
})
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_current_route`,
|
|
159
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO,
|
|
160
|
+
description: `\u83B7\u53D6 Vue Router \u7684\u5F53\u524D\u8DEF\u7531\u4FE1\u606F\u3002
|
|
161
|
+
|
|
162
|
+
**\u4F55\u65F6\u4F7F\u7528**\uFF1A
|
|
163
|
+
- \u6392\u67E5\u8DEF\u7531\u8DF3\u8F6C\u95EE\u9898
|
|
164
|
+
- \u67E5\u770B\u5F53\u524D\u8DEF\u7531 path/params/query/hash
|
|
165
|
+
- \u786E\u8BA4\u8DEF\u7531\u5B88\u536B\u548C matched \u8BB0\u5F55`,
|
|
166
|
+
inputSchema: withPageIdSchema({ type: "object", properties: {} })
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: `${VUE_DEVTOOLS_PREFIX}get_routes`,
|
|
170
|
+
action: VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO,
|
|
171
|
+
description: `\u83B7\u53D6 Vue Router \u7684\u5B8C\u6574\u8DEF\u7531\u8868\u3002
|
|
172
|
+
|
|
173
|
+
**\u4F55\u65F6\u4F7F\u7528**\uFF1A
|
|
174
|
+
- \u67E5\u770B\u6240\u6709\u5DF2\u6CE8\u518C\u8DEF\u7531
|
|
175
|
+
- \u786E\u8BA4\u8DEF\u7531\u914D\u7F6E\u662F\u5426\u6B63\u786E
|
|
176
|
+
- \u67E5\u770B\u8DEF\u7531\u5D4C\u5957\u5173\u7CFB`,
|
|
177
|
+
inputSchema: withPageIdSchema({ type: "object", properties: {} })
|
|
36
178
|
}
|
|
37
179
|
];
|
|
180
|
+
function findVueDevtoolsTool(name) {
|
|
181
|
+
return VUE_DEVTOOLS_TOOLS.find((t) => t.name === name);
|
|
182
|
+
}
|
|
183
|
+
function vueDevtoolsToolList() {
|
|
184
|
+
return VUE_DEVTOOLS_TOOLS.map(({ name, description, inputSchema }) => ({
|
|
185
|
+
name,
|
|
186
|
+
description,
|
|
187
|
+
inputSchema
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
38
190
|
const UNSAFE_CATEGORIES = /* @__PURE__ */ new Set(["EXTENSIONS", "PWA", "THIRD_PARTY", "WEBMCP"]);
|
|
39
191
|
function metaByName(short) {
|
|
40
192
|
return OFFICIAL_TOOL_META.find((m) => m.name === short);
|
|
@@ -106,18 +258,25 @@ function isAllowedToolName(name) {
|
|
|
106
258
|
}
|
|
107
259
|
export {
|
|
108
260
|
CUSTOM_TOOLS,
|
|
261
|
+
LOGS_DEVTOOLS_PREFIX,
|
|
109
262
|
MCP_PREFIX,
|
|
110
263
|
OFFICIAL_GLOBAL_POLICY,
|
|
111
264
|
OFFICIAL_NO_PAGE_TOOLS,
|
|
112
265
|
PAGE_ID_PROP,
|
|
113
266
|
PROJECT_DESCRIPTION_NOTES,
|
|
267
|
+
VITE_LOGS_TOOL_NAME,
|
|
268
|
+
VUE_DEVTOOLS_PREFIX,
|
|
269
|
+
VUE_DEVTOOLS_TOOLS,
|
|
114
270
|
configureToolScope,
|
|
115
271
|
currentOfficialShorts,
|
|
116
272
|
displayToolName,
|
|
117
273
|
extraToolFlag,
|
|
274
|
+
findVueDevtoolsTool,
|
|
118
275
|
isAllowedToolName,
|
|
119
276
|
isOfficialExtraTool,
|
|
120
277
|
officialDefaultShorts,
|
|
121
278
|
officialExtraCandidates,
|
|
279
|
+
serviceLogToolName,
|
|
280
|
+
vueDevtoolsToolList,
|
|
122
281
|
withPageIdSchema
|
|
123
282
|
};
|
package/es/endpoints/index.d.ts
CHANGED
|
@@ -6,4 +6,6 @@ import type { McpProxy } from "../core/mcp-proxy";
|
|
|
6
6
|
import { LOGS_API_PATH, type ChromeProjectOptions, type LogFileConfig } from "@aipanel/core";
|
|
7
7
|
export * from "./types";
|
|
8
8
|
export { LOGS_API_PATH, MCP_API_PATH, VUE_DEVTOOLS_API_PATH };
|
|
9
|
-
export declare function setupMiddlewares(server: ViteDevServer, ctx: EndpointContext, mcp?: McpProxy, logFiles?: LogFileConfig[], chromeProject?: ChromeProjectOptions
|
|
9
|
+
export declare function setupMiddlewares(server: ViteDevServer, ctx: EndpointContext, mcp?: McpProxy, logFiles?: LogFileConfig[], chromeProject?: ChromeProjectOptions,
|
|
10
|
+
/** 是否暴露 vue-devtools_* 工具(Vue 项目才有页面桥;未识别框架按保守策略视为 Vue) */
|
|
11
|
+
exposeVueDevtools?: boolean): void;
|
package/es/endpoints/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { setupMcpEndpoint, MCP_API_PATH } from "./mcp.mjs";
|
|
|
10
10
|
import { setupVueDevtoolsEndpoint, VUE_DEVTOOLS_API_PATH } from "./vue-devtools.mjs";
|
|
11
11
|
import { LOGS_API_PATH } from "@aipanel/core";
|
|
12
12
|
export * from "./types.mjs";
|
|
13
|
-
function setupMiddlewares(server, ctx, mcp, logFiles, chromeProject) {
|
|
13
|
+
function setupMiddlewares(server, ctx, mcp, logFiles, chromeProject, exposeVueDevtools = true) {
|
|
14
14
|
setupWidgetEndpoints(server, ctx);
|
|
15
15
|
setupContextEndpoint(server, ctx);
|
|
16
16
|
setupStartEndpoint(server, ctx);
|
|
@@ -20,7 +20,14 @@ function setupMiddlewares(server, ctx, mcp, logFiles, chromeProject) {
|
|
|
20
20
|
setupWarmupEndpoint(server, ctx);
|
|
21
21
|
setupLogsEndpoint(server);
|
|
22
22
|
if (mcp) {
|
|
23
|
-
setupMcpEndpoint(
|
|
23
|
+
setupMcpEndpoint(
|
|
24
|
+
server,
|
|
25
|
+
mcp,
|
|
26
|
+
() => ctx.getPageContext(),
|
|
27
|
+
logFiles ?? [],
|
|
28
|
+
chromeProject,
|
|
29
|
+
exposeVueDevtools
|
|
30
|
+
);
|
|
24
31
|
setupVueDevtoolsEndpoint(server, mcp);
|
|
25
32
|
}
|
|
26
33
|
}
|
package/es/endpoints/mcp.d.ts
CHANGED
|
@@ -3,4 +3,6 @@ import type { ChromeProjectOptions, LogFileConfig, PageContext } from "@aipanel/
|
|
|
3
3
|
import { MCP_API_PATH } from "@aipanel/core";
|
|
4
4
|
import { McpProxy } from "../core/mcp-proxy";
|
|
5
5
|
export { MCP_API_PATH };
|
|
6
|
-
export declare function setupMcpEndpoint(server: ViteDevServer, mcp: McpProxy, getPageContext: () => PageContext, logFiles?: LogFileConfig[], chromeProject?: ChromeProjectOptions
|
|
6
|
+
export declare function setupMcpEndpoint(server: ViteDevServer, mcp: McpProxy, getPageContext: () => PageContext, logFiles?: LogFileConfig[], chromeProject?: ChromeProjectOptions,
|
|
7
|
+
/** Vue 项目才注入 vue-devtools 桥;非 Vue 项目既不上架也不路由这些工具,避免模型调用必失败的工具 */
|
|
8
|
+
exposeVueDevtools?: boolean): void;
|
package/es/endpoints/mcp.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MCP_API_PATH
|
|
1
|
+
import { MCP_API_PATH } from "@aipanel/core";
|
|
2
2
|
import {
|
|
3
3
|
createLogger,
|
|
4
4
|
getProcessLogBuffer,
|
|
@@ -12,12 +12,20 @@ import {
|
|
|
12
12
|
validatePageId
|
|
13
13
|
} from "../core/mcp-chrome.mjs";
|
|
14
14
|
import { resolveProjectScope } from "../core/chrome-project.mjs";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
CUSTOM_TOOLS,
|
|
17
|
+
findVueDevtoolsTool,
|
|
18
|
+
isAllowedToolName,
|
|
19
|
+
serviceLogToolName,
|
|
20
|
+
VITE_LOGS_TOOL_NAME,
|
|
21
|
+
VUE_DEVTOOLS_PREFIX,
|
|
22
|
+
vueDevtoolsToolList
|
|
23
|
+
} from "../core/mcp-tools.mjs";
|
|
16
24
|
import { getOfficialProjectTools } from "../core/official-tools.mjs";
|
|
17
25
|
import { executeAction } from "./vue-devtools.mjs";
|
|
18
26
|
import { findGitRoot } from "@aipanel/core/node";
|
|
19
27
|
const log = createLogger("McpEndpoint");
|
|
20
|
-
function setupMcpEndpoint(server, mcp, getPageContext, logFiles = [], chromeProject) {
|
|
28
|
+
function setupMcpEndpoint(server, mcp, getPageContext, logFiles = [], chromeProject, exposeVueDevtools = true) {
|
|
21
29
|
const projectRoot = findGitRoot(process.cwd());
|
|
22
30
|
server.middlewares.use(async (req, res, next) => {
|
|
23
31
|
if (!req.url?.startsWith(MCP_API_PATH)) return next();
|
|
@@ -50,7 +58,8 @@ function setupMcpEndpoint(server, mcp, getPageContext, logFiles = [], chromeProj
|
|
|
50
58
|
scope.includeExtensions,
|
|
51
59
|
getPageContext,
|
|
52
60
|
logFiles,
|
|
53
|
-
projectRoot
|
|
61
|
+
projectRoot,
|
|
62
|
+
exposeVueDevtools
|
|
54
63
|
);
|
|
55
64
|
return;
|
|
56
65
|
}
|
|
@@ -68,7 +77,7 @@ function handleGetSse(req, res, mcp) {
|
|
|
68
77
|
const keepAlive = setInterval(() => res.write(":ping\n\n"), 15e3);
|
|
69
78
|
req.on("close", () => clearInterval(keepAlive));
|
|
70
79
|
}
|
|
71
|
-
async function handlePost(req, res, mcp, projectOrigins, operationsOrigins, includeExtensions, getPageContext, logFiles, projectRoot) {
|
|
80
|
+
async function handlePost(req, res, mcp, projectOrigins, operationsOrigins, includeExtensions, getPageContext, logFiles, projectRoot, exposeVueDevtools) {
|
|
72
81
|
try {
|
|
73
82
|
const body = await readBody(req);
|
|
74
83
|
if (!body) {
|
|
@@ -80,7 +89,7 @@ async function handlePost(req, res, mcp, projectOrigins, operationsOrigins, incl
|
|
|
80
89
|
log.debug("MCP request", { method, body: body.substring(0, 150) });
|
|
81
90
|
switch (method) {
|
|
82
91
|
case "tools/list":
|
|
83
|
-
return await handleToolsList(res, id, mcp, logFiles);
|
|
92
|
+
return await handleToolsList(res, id, mcp, logFiles, exposeVueDevtools);
|
|
84
93
|
case "tools/call":
|
|
85
94
|
return await handleToolsCall(
|
|
86
95
|
res,
|
|
@@ -92,7 +101,8 @@ async function handlePost(req, res, mcp, projectOrigins, operationsOrigins, incl
|
|
|
92
101
|
includeExtensions,
|
|
93
102
|
getPageContext,
|
|
94
103
|
logFiles,
|
|
95
|
-
projectRoot
|
|
104
|
+
projectRoot,
|
|
105
|
+
exposeVueDevtools
|
|
96
106
|
);
|
|
97
107
|
default:
|
|
98
108
|
return await handleForward(res, body, mcp);
|
|
@@ -105,7 +115,7 @@ async function handlePost(req, res, mcp, projectOrigins, operationsOrigins, incl
|
|
|
105
115
|
});
|
|
106
116
|
}
|
|
107
117
|
}
|
|
108
|
-
async function handleToolsList(res, id, mcp, logFiles) {
|
|
118
|
+
async function handleToolsList(res, id, mcp, logFiles, exposeVueDevtools) {
|
|
109
119
|
let official = [];
|
|
110
120
|
try {
|
|
111
121
|
official = await getOfficialProjectTools(mcp);
|
|
@@ -114,20 +124,28 @@ async function handleToolsList(res, id, mcp, logFiles) {
|
|
|
114
124
|
error: e instanceof Error ? e.message : String(e)
|
|
115
125
|
});
|
|
116
126
|
}
|
|
117
|
-
const tools = [
|
|
127
|
+
const tools = [
|
|
128
|
+
...official,
|
|
129
|
+
...CUSTOM_TOOLS,
|
|
130
|
+
...exposeVueDevtools ? vueDevtoolsToolList() : [],
|
|
131
|
+
...buildServiceLogTools(logFiles)
|
|
132
|
+
];
|
|
118
133
|
sendMcpJson(res, 200, { jsonrpc: "2.0", id, result: { tools } }, mcp.sessionId);
|
|
119
134
|
}
|
|
120
|
-
function handleToolsCall(res, id, body, mcp, projectOrigins, operationsOrigins, includeExtensions, getPageContext, logFiles, projectRoot) {
|
|
135
|
+
function handleToolsCall(res, id, body, mcp, projectOrigins, operationsOrigins, includeExtensions, getPageContext, logFiles, projectRoot, exposeVueDevtools) {
|
|
121
136
|
const params = tryParseParams(body);
|
|
122
137
|
const toolName = params?.name;
|
|
123
138
|
const args = params?.arguments ?? {};
|
|
124
139
|
if (toolName === "chrome-devtools_current_page") {
|
|
125
140
|
return handleGetPageContext(res, id, mcp, operationsOrigins, includeExtensions, getPageContext);
|
|
126
141
|
}
|
|
127
|
-
if (toolName?.startsWith(
|
|
142
|
+
if (toolName?.startsWith(VUE_DEVTOOLS_PREFIX)) {
|
|
143
|
+
if (!exposeVueDevtools) {
|
|
144
|
+
return sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, mcp.sessionId);
|
|
145
|
+
}
|
|
128
146
|
return handleVueDevtoolsTool(res, id, mcp, projectOrigins, toolName, args);
|
|
129
147
|
}
|
|
130
|
-
if (toolName ===
|
|
148
|
+
if (toolName === VITE_LOGS_TOOL_NAME) {
|
|
131
149
|
return handleViteLogsTool(res, id, args, mcp.sessionId);
|
|
132
150
|
}
|
|
133
151
|
if (toolName && isServiceLogTool(toolName, logFiles)) {
|
|
@@ -388,23 +406,14 @@ async function handleDevTool(res, id, mcp, mapped, args, operationsOrigins, incl
|
|
|
388
406
|
sendMcpError(res, id, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
|
|
389
407
|
}
|
|
390
408
|
}
|
|
391
|
-
const VUE_DEVTOOLS_TOOL_ACTIONS = {
|
|
392
|
-
"vue-devtools_get_apps": VUE_DEVTOOLS_ACTIONS.GET_APPS,
|
|
393
|
-
"vue-devtools_set_active_app": VUE_DEVTOOLS_ACTIONS.TOGGLE_APP,
|
|
394
|
-
"vue-devtools_get_component_tree": VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_TREE,
|
|
395
|
-
"vue-devtools_get_component_state": VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_STATE,
|
|
396
|
-
"vue-devtools_get_component_render_code": VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_RENDER_CODE,
|
|
397
|
-
"vue-devtools_get_current_route": VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO,
|
|
398
|
-
"vue-devtools_get_routes": VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO
|
|
399
|
-
};
|
|
400
409
|
async function handleVueDevtoolsTool(res, id, mcp, projectOrigins, toolName, args) {
|
|
401
410
|
try {
|
|
402
|
-
const
|
|
403
|
-
if (!
|
|
411
|
+
const tool = findVueDevtoolsTool(toolName);
|
|
412
|
+
if (!tool) {
|
|
404
413
|
sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, mcp.sessionId);
|
|
405
414
|
return;
|
|
406
415
|
}
|
|
407
|
-
const result = await executeAction(action, args, mcp, projectOrigins);
|
|
416
|
+
const result = await executeAction(tool.action, args, mcp, projectOrigins);
|
|
408
417
|
switch (toolName) {
|
|
409
418
|
case "vue-devtools_set_active_app":
|
|
410
419
|
sendMcpResult(res, id, `\u5DF2\u5207\u6362\u5230\u5E94\u7528 ${args["appId"]}`, mcp.sessionId);
|
|
@@ -483,7 +492,7 @@ function parseProcessLevelFilter(level) {
|
|
|
483
492
|
}
|
|
484
493
|
function buildServiceLogTools(logFiles) {
|
|
485
494
|
return logFiles.map((cfg) => ({
|
|
486
|
-
name:
|
|
495
|
+
name: serviceLogToolName(cfg.name),
|
|
487
496
|
description: `\u83B7\u53D6 ${cfg.name} \u7684\u65E5\u5FD7\u3002
|
|
488
497
|
|
|
489
498
|
**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A
|
|
@@ -511,11 +520,11 @@ ${cfg.description}
|
|
|
511
520
|
}));
|
|
512
521
|
}
|
|
513
522
|
function isServiceLogTool(toolName, logFiles) {
|
|
514
|
-
return logFiles.some((cfg) =>
|
|
523
|
+
return logFiles.some((cfg) => serviceLogToolName(cfg.name) === toolName);
|
|
515
524
|
}
|
|
516
525
|
async function handleServiceLogsTool(res, id, toolName, args, logFiles, projectRoot, sessionId) {
|
|
517
526
|
try {
|
|
518
|
-
const cfg = logFiles.find((c) =>
|
|
527
|
+
const cfg = logFiles.find((c) => serviceLogToolName(c.name) === toolName);
|
|
519
528
|
if (!cfg) {
|
|
520
529
|
sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, sessionId);
|
|
521
530
|
return;
|