Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 53 additions & 67 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions template/tinyvue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"dependencies": {
"@babel/core": "^7.25.2",
"@gaonengwww/mock-server": "^1.0.5",
"@mcp-b/webmcp-polyfill":"^2.0.0",
"@mcp-b/webmcp-types":"^2.0.0",
"@opentiny/icons": "^0.1.3",
"@opentiny/next-remoter": "0.2.7",
"@opentiny/next-sdk": "0.2.7",
Expand Down
68 changes: 30 additions & 38 deletions template/tinyvue/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
<script lang="ts" setup>
import { WebMcpClient } from '@opentiny/next-sdk'
import { TinyRemoter } from '@opentiny/next-remoter'
import { TinyConfigProvider } from '@opentiny/vue'
import TinyThemeTool from '@opentiny/vue-theme/theme-tool'
import { onMounted, ref } from 'vue'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
import GlobalSetting from '@/components/global-setting/index.vue'
import { tinyProOperatorSkillText } from '@/skills'
import { sleep } from '@/utils/base-utils'
import { useTheme } from './hooks/useTheme'
import { clientTransport, createMcpServer } from './mcp-servers'
import { skills } from './skills'
import '@opentiny/next-remoter/dist/style.css'

const theme = new TinyThemeTool()
useTheme(theme)

const router = useRouter()
const design = {
name: 'x-design', // 设计规范名称
version: '1.0.0', // 设计规范版本号
Expand All @@ -25,35 +24,33 @@ const design = {
},
},
}

// 将本地 MCP Server 注册到 TinyRemoter
// key 为服务器名称(自定义),type: 'local' 表示浏览器本地运行
const mcpServers = {
'my-mcp-server': {
type: 'local',
transport: clientTransport,
},
}

const AGENT_URL = 'https://agent.opentiny.design/api/v1/webmcp-trial/'
const sessionID = ref('')

// 启动 MCP Server(注册工具 + 建立通信通道)
onMounted(async () => {
await createMcpServer()

// 远程连接
const client = new WebMcpClient()
await client.connect(clientTransport)
// 这个 sessionId 是 Web 应用与 WebAgent 服务建立连接后,由 WebAgent 服务生成的,用来唯一标识被操控的 Web 应用(被控端)
const { sessionId } = await client.connect({
agent: true,
url: `${AGENT_URL}mcp`,
sessionId: '5343d3ee-47c6-49a3-9052-c68eed6f5b50'
onMounted(() => {
navigator.modelContext.registerTool({
name: 'navigate_url',
title: '导航到指定URL',
description: '当需要的工具在当前页面不可用时,使用此工具跳转到特定页面。例如:要跳转到 "/vue-pro/order/allOrder",要创建价保时跳转到 "/vue-pro/price-protection/allPriceProtection"。',
inputSchema: {
type: 'object',
properties: {
url: { type: 'string', description: 'URL' },
},
required: ['url'],
},
execute: async ({ url }) => {
router.push(url)
await sleep(1000)
return { content: [{ type: 'text', text: `收到: ${url}` }] }
Comment thread
wuyiping0628 marked this conversation as resolved.
},
})
console.log('sessionId', sessionId);

sessionID.value = sessionId
navigator.modelContext.registerTool({
name: 'system-overview',
title: '系统概览',
description: '整体介绍网站的模块、路由、页面工具、使用规范等等内容',
execute: async () => {
return { content: [{ type: 'text', text: tinyProOperatorSkillText }] }
},
})
})
</script>

Expand All @@ -65,11 +62,6 @@ onMounted(async () => {

<GlobalSetting />
</div>
<TinyRemoter
:skills="skills"
:agent-root="AGENT_URL"
:session-id="sessionID"
/>
</template>

<style lang="less" scoped>
Expand Down
7 changes: 3 additions & 4 deletions template/tinyvue/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { initializeWebMCPPolyfill } from '@mcp-b/webmcp-polyfill';
import TinySearchBox from '@opentiny/vue-search-box'
import { createApp } from 'vue'
import { setNavigator } from '@opentiny/next-sdk'
import globalComponents from '@/components'
import App from './App.vue'
import directive from './directive'
Expand All @@ -13,6 +13,8 @@ import '@opentiny/vue-search-box/dist/index.css'
import 'virtual:uno.css'
import '@opentiny/icons/style/all.css'

initializeWebMCPPolyfill();

const app = createApp(App)

app.use(router)
Expand All @@ -23,6 +25,3 @@ app.use(directive)
app.use(TinySearchBox)

app.mount('#app')

// 必须在 router 注册后调用,让 SDK 持有 router.push 的引用
setNavigator((route) => router.push(route))
7 changes: 3 additions & 4 deletions template/tinyvue/src/router/guard/permission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ export default function setupPermissionGuard(router: Router) {
} as LocationQueryRaw,
})
NProgress.done()
return
}
else {
next()
NProgress.done()
}
next()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
NProgress.done()
})
}
2 changes: 2 additions & 0 deletions template/tinyvue/src/skills/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export const skills = import.meta.glob('./**/*', {
import: 'default', // 取模块的 default 导出(即文件内容字符串)
eager: true // 同步加载,避免异步等待
}) as Record<string, string>

export const tinyProOperatorSkillText = skills['./tiny-pro-operator/SKILL.md'] ?? ''
213 changes: 180 additions & 33 deletions template/tinyvue/src/skills/tiny-pro-operator/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,183 @@
# TinyPro 操作指南

## 这是一个 [TinyPro](http://localhost:3031/vue-pro/) 后台管理系统,使用 `navigate_url` 进行路由菜单跳转

## 系统管理功能一览

| 模块 | 路由 | 可用 WebMCP 工具 | 描述 |
| ---------- | ----------------------------------- | -------------------------------- | ------------------------ |
| 菜单管理 | `/vue-pro/menu/allMenu` | `add-menu` | 添加菜单 |
| 权限管理 | `/vue-pro/permission/allPermission` | `add-permission` | 添加权限 |
| 角色管理 | `/vue-pro/role/allRole` | `add-role`、`bind-menu-for-role` | 添加角色、为角色绑定菜单 |
| 用户管理 | `/vue-pro/userManager/allInfo` | `add-user` | 添加用户 |
| 国际化词条 | `/vue-pro/locale` | `add-i18n-entry` | 添加国际化词条 |

## WebMCP 工具详细说明

### 1. `add-i18n-entry` — 添加国际化词条

**路由**:`/vue-pro/locale`

| 参数 | 类型 | 必填 | 说明 |
| --------- | ------ | ---- | ----------------------------------------------- |
| `key` | string | ✅ | 词条关键字,Agent 自行创建,**不要询问用户** |
| `content` | string | ✅ | 词条内容 |
| `lang` | 1 \| 2 | ✅ | 语言 ID:`1` = enUS(英文),`2` = zhCN(中文) |

**命名规范**:词条 Key 建议使用 `模块::页面::元素` 格式,如 `test::page::title`。

**示例**:

```
用户需求:添加国际化词条:key 为 test::page::title,内容为「测试页面」,语言为中文
工具调用:add-i18n-entry({ key: "test::page::title", content: "测试页面", lang: 2 })
```
Comment thread
wuyiping0628 marked this conversation as resolved.

---

### 2. `add-menu` — 添加菜单

**路由**:`/vue-pro/menu/allMenu`

| 参数 | 类型 | 必填 | 说明 |
| ------------ | ------ | ---- | ------------------------------------------------------------- |
| `name` | string | ✅ | 菜单名称(英文,对应路由 id) |
| `component` | string | ✅ | 组件路径,**不含** `src/views` 前缀,如 `test-page/index.vue` |
| `path` | string | ✅ | 路由路径 |
| `locale` | string | ✅ | 国际化词条 Key(须已存在于 i18n 中) |
| `order` | number | — | 优先级,默认 `0`,数值越大越靠上 |
| `parentMenu` | string | — | 父菜单名称(通过 label 匹配 ID) |
| `icon` | string | — | 菜单图标 |

**执行流程**:打开添加菜单弹窗 → 填充表单(`menuType` 固定为 `/`)→ 提交创建 → 刷新菜单树与路由。

**示例**:

```
用户需求:添加名称 test-page,组件 test-page/index.vue,路径 /test-page,国际化 test::page::title 的菜单
→ 调用 add-menu({ name: "test-page", component: "test-page/index.vue", path: "/test-page", locale: "test::page::title" })
```

---
name: tiny-pro-operator
description: TinyPro 项目的前端页面操作指南。当用户需要新建页面、配置菜单、设置权限(v-permission)、国际化(i18n)管理或进行 TinyPro 相关页面的操作时触发。该技能提供从菜单管理、词条管理、用户管理、权限管理的完整指引。

### 3. `add-permission` — 添加权限

**路由**:`/vue-pro/permission/allPermission`

| 参数 | 类型 | 必填 | 说明 |
| ------ | ------ | ---- | ------------------------ |
| `name` | string | ✅ | 权限名称,如 `good::add` |
| `desc` | string | ✅ | 权限描述 |

**命名规范**:权限名建议使用 `模块::操作` 格式,与 `v-permission` 指令值一致。

**示例**:

```
用户需求: 帮我添加权限为good::add,描述是:创建商品
→ 调用 add-permission({ name: "good::add", desc: "创建商品" })
```

**页面权限指令对照**:

| 页面 | v-permission 值 |
| --------------------------- | ------------------------------------------------------------------------------------ |
| 菜单添加 | `menu::add` |
| 权限添加/删除 | `permission::add` / `permission::remove` |
| 角色添加 | `role::add` |
| 用户添加/删除/改密/批量删除 | `user::add` / `user::remove` / `user::password::force-update` / `user::batch-remove` |
| 词条批量删除 | `i18n::batch-remove` |
| 语言添加/更新 | `lang::add` / `lang::update` |

---

# TinyPro 操作指南 (tiny-pro-operator)

本技能旨在帮助开发者在 TinyPro 框架下高效地完成页面操作,比如:菜单管理、权限管理和国际化配置。

以下是系统管理包含的功能,每个功能都有对应的路由和 MCP 工具。

- 菜单管理(路由:`menu/allMenu`):
- ✅️创建菜单 `add-menu`
- ❌修改菜单
- ❌删除菜单
- 权限管理(路由:`permission/allPermission`):
- ✅️添加权限 `add-permission`
- ❌编辑权限
- ❌删除权限
- 角色管理(路由:`role/allRole`):
- ✅️添加角色 `add-role`
- ❌编辑角色(名称、权限)
- ❌删除角色
- ✅️绑定目录 bind-menu-for-role
- 用户管理(路由:`userManager/allInfo`):
- ✅️添加用户 `add-user`
- ❌编辑用户
- ❌修改密码
- ❌删除用户(包含批量删除用户)
- 国际化词条管理(路由:`locale`):
- ✅️添加词条 `add-i18n-entry`
- ❌删除词条(包含批量删除词条)

当用户询问相关操作时,需要跳转到对应的路由,调用对应的 MCP 工具。

例如:“帮我添加权限:good::add,描述是:创建商品”,则需要调用 MCP 工具 `add-permission`。
### 4. `add-role` — 添加角色

**路由**:`/vue-pro/role/allRole`

| 参数 | 类型 | 必填 | 说明 |
| ------------- | -------- | ---- | -------------------------- |
| `name` | string | ✅ | 角色名称 |
| `permissions` | number[] | ✅ | 权限 ID 数组(非权限名称) |

**注意**:直接调用工具添加,**不要**生成角色卡片 UI。

**示例**:

```
用户需求:添加角色 admin,权限 ID 为 [1, 2, 3]
→ 调用 add-role({ name: "admin", permissions: [1, 2, 3] })
```

---

### 5. `bind-menu-for-role` — 为角色绑定菜单

**路由**:`/vue-pro/role/allRole`
**源文件**:`src/views/role/info/components/info-tab.vue`

| 参数 | 类型 | 必填 | 说明 |
| ------ | ------ | ---- | ----------------------------------- |
| `role` | string | ✅ | 角色名称(精确匹配) |
| `menu` | string | ✅ | 菜单名称(通过 i18n label 匹配 ID) |

**执行流程**:查找角色 → 打开菜单绑定抽屉 → 勾选目标菜单 → 确认提交 → 刷新路由与 Tab。

**示例**:

```
用户需求:给 admin 角色绑定「测试页面」菜单
→ 调用 bind-menu-for-role({ role: "admin", menu: "测试页面" })
```

---

### 6. `add-user` — 添加用户

**路由**:`/vue-pro/userManager/allInfo`
**源文件**:`src/views/userManager/info/components/info-tab.vue`

| 参数 | 类型 | 必填 | 说明 |
| ------------------- | -------- | ---- | ---------------- |
| `email` | string | ✅ | 邮箱 |
| `password` | string | ✅ | 密码 |
| `name` | string | ✅ | 用户名 |
| `address` | string | — | 地址 |
| `department` | string | — | 所属部门 |
| `roleIds` | number[] | — | 角色 ID 数组 |
| `employeeType` | string | — | 招聘类型 |
| `probationDate` | string[] | — | 试用期起止时间 |
| `probationDuration` | string | — | 试用期时长 |
| `protocolStart` | string | — | 劳动合同开始日期 |
| `protocolEnd` | string | — | 劳动合同结束日期 |
| `status` | string | — | 状态 |

**注意**:可选参数无需用户提供;**不要**创建表单卡片,直接根据已有信息调用工具。

**示例**:

```
用户需求:添加用户,邮箱 test@example.com,密码 123456,用户名 test
→ 调用 add-user({ email: "test@example.com", password: "123456", name: "test" })
```

---

### 7. `navigate_url` — 导航到指定URL

| 参数 | 类型 | 必填 | 说明 |
| ----- | ------ | ---- | --------- |
| `url` | string | ✅ | 跳转的url |

**示例**:

```
用户需求:跳转到添加用户页面
→ 调用 navigate_url({ url: "/vue-pro/userManager/allInfo" })
```

---

### 核心约束

1. **路由跳转规则:** 只使用 `navigate_url` 工具进行路由菜单跳转
Loading
Loading