mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-22 17:57:46 +00:00
feat(chrome-qwen-bridge): 🔥 init chrome qwen code bridge
This commit is contained in:
119
packages/chrome-qwen-bridge/docs/README.md
Normal file
119
packages/chrome-qwen-bridge/docs/README.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Chrome Qwen Bridge 文档
|
||||
|
||||
欢迎查阅 Chrome Qwen Bridge 的技术文档。本项目是一个 Chrome 扩展,用于连接浏览器与 Qwen CLI,实现 AI 增强的网页交互。
|
||||
|
||||
## 📚 文档目录
|
||||
|
||||
### 核心文档
|
||||
|
||||
1. **[架构设计文档](./architecture.md)**
|
||||
- 系统架构概览
|
||||
- 组件职责划分
|
||||
- 数据流设计
|
||||
- 安全设计
|
||||
- 性能优化策略
|
||||
|
||||
2. **[实施计划文档](./implementation-plan.md)**
|
||||
- 项目背景与需求
|
||||
- 分阶段实施计划
|
||||
- 技术栈选择
|
||||
- 测试与部署计划
|
||||
- 风险评估
|
||||
|
||||
3. **[技术细节文档](./technical-details.md)**
|
||||
- Native Messaging 协议详解
|
||||
- Chrome Extension API 使用
|
||||
- 数据提取算法
|
||||
- 进程管理
|
||||
- 调试技巧
|
||||
|
||||
4. **[API 参考文档](./api-reference.md)**
|
||||
- Chrome Extension APIs
|
||||
- Native Host APIs
|
||||
- Qwen CLI 集成
|
||||
- 错误代码
|
||||
- 使用示例
|
||||
|
||||
### 快速链接
|
||||
|
||||
- [主 README](../README.md) - 安装和使用指南
|
||||
- [GitHub 仓库](https://github.com/QwenLM/qwen-code) - 源代码
|
||||
- [问题反馈](https://github.com/QwenLM/qwen-code/issues) - 提交 Issue
|
||||
|
||||
## 🎯 项目特性
|
||||
|
||||
- ✅ **Native Messaging** - Chrome 官方推荐的安全通信方式
|
||||
- ✅ **MCP 服务器支持** - 集成多个 Model Context Protocol 服务器
|
||||
- ✅ **丰富的数据提取** - DOM、Console、网络请求等全方位数据
|
||||
- ✅ **AI 分析能力** - 利用 Qwen 的 AI 能力分析网页内容
|
||||
- ✅ **跨平台支持** - Windows、macOS、Linux 全平台
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
1. **安装扩展**
|
||||
```bash
|
||||
# 在 Chrome 中加载未打包的扩展
|
||||
chrome://extensions/ → 开发者模式 → 加载已解压的扩展程序
|
||||
选择: packages/chrome-qwen-bridge/extension
|
||||
```
|
||||
|
||||
2. **安装 Native Host**
|
||||
```bash
|
||||
cd packages/chrome-qwen-bridge/native-host
|
||||
./install.sh # macOS/Linux
|
||||
# 或
|
||||
install.bat # Windows
|
||||
```
|
||||
|
||||
3. **连接使用**
|
||||
- 点击扩展图标
|
||||
- 连接到 Qwen CLI
|
||||
- 开始分析网页!
|
||||
|
||||
## 📖 文档说明
|
||||
|
||||
### 架构设计文档
|
||||
详细描述了系统的整体架构,包括 Chrome Extension、Native Host 和 Qwen CLI 三层架构的设计理念、组件职责、数据流向等核心概念。
|
||||
|
||||
### 实施计划文档
|
||||
记录了项目从概念到实现的完整过程,包括各个开发阶段的任务分解、技术选型依据、测试计划和未来优化方向。
|
||||
|
||||
### 技术细节文档
|
||||
深入探讨了关键技术的实现细节,如 Native Messaging 协议的具体实现、数据提取算法、进程管理策略等。
|
||||
|
||||
### API 参考文档
|
||||
提供了所有 API 的完整参考,包括消息格式、参数说明、返回值、错误代码等,是开发和调试的重要参考。
|
||||
|
||||
## 🛠 技术架构
|
||||
|
||||
```
|
||||
Chrome Browser
|
||||
↓
|
||||
Chrome Extension (Content Script + Service Worker + Popup)
|
||||
↓
|
||||
Native Messaging API
|
||||
↓
|
||||
Native Host (Node.js)
|
||||
↓
|
||||
Qwen CLI + MCP Servers
|
||||
```
|
||||
|
||||
## 📝 版本历史
|
||||
|
||||
- **v1.0.0** (2024-12) - 初始版本
|
||||
- 实现基础架构
|
||||
- Native Messaging 通信
|
||||
- 页面数据提取
|
||||
- Qwen CLI 集成
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
欢迎贡献代码和文档!请查看主仓库的贡献指南。
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
Apache-2.0 License
|
||||
|
||||
---
|
||||
|
||||
*本文档集是 Chrome Qwen Bridge 项目的技术参考,持续更新中。*
|
||||
646
packages/chrome-qwen-bridge/docs/api-reference.md
Normal file
646
packages/chrome-qwen-bridge/docs/api-reference.md
Normal file
@@ -0,0 +1,646 @@
|
||||
# Chrome Qwen Bridge API 参考文档
|
||||
|
||||
## Chrome Extension APIs
|
||||
|
||||
### Background Service Worker
|
||||
|
||||
#### 消息类型
|
||||
|
||||
##### 连接管理
|
||||
|
||||
**CONNECT**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'CONNECT'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
status?: string, // 'connected' | 'running' | 'stopped'
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**GET_STATUS**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'GET_STATUS'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
connected: boolean,
|
||||
status: string // 'disconnected' | 'connecting' | 'connected' | 'running'
|
||||
}
|
||||
```
|
||||
|
||||
##### Qwen CLI 控制
|
||||
|
||||
**START_QWEN_CLI**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'START_QWEN_CLI',
|
||||
config?: {
|
||||
mcpServers?: string[], // MCP 服务器列表
|
||||
httpPort?: number // HTTP 端口,默认 8080
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: {
|
||||
status: string,
|
||||
pid: number,
|
||||
port: number
|
||||
},
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**STOP_QWEN_CLI**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'STOP_QWEN_CLI'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: string,
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
##### 数据操作
|
||||
|
||||
**EXTRACT_PAGE_DATA**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'EXTRACT_PAGE_DATA'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: {
|
||||
url: string,
|
||||
title: string,
|
||||
domain: string,
|
||||
path: string,
|
||||
timestamp: string,
|
||||
meta: object,
|
||||
content: {
|
||||
text: string,
|
||||
html: string,
|
||||
markdown: string
|
||||
},
|
||||
links: Array<{
|
||||
text: string,
|
||||
href: string,
|
||||
target: string,
|
||||
isExternal: boolean
|
||||
}>,
|
||||
images: Array<{
|
||||
src: string,
|
||||
alt: string,
|
||||
title: string,
|
||||
width: number,
|
||||
height: number
|
||||
}>,
|
||||
forms: Array<{
|
||||
action: string,
|
||||
method: string,
|
||||
fields: Array<object>
|
||||
}>,
|
||||
consoleLogs: Array<{
|
||||
type: string,
|
||||
message: string,
|
||||
timestamp: string,
|
||||
stack: string
|
||||
}>,
|
||||
performance: {
|
||||
loadTime: number,
|
||||
domReady: number,
|
||||
firstPaint: number
|
||||
}
|
||||
},
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**CAPTURE_SCREENSHOT**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'CAPTURE_SCREENSHOT'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: string, // Base64 编码的图片
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**GET_NETWORK_LOGS**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'GET_NETWORK_LOGS'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: Array<{
|
||||
method: string,
|
||||
params: object,
|
||||
timestamp: number
|
||||
}>,
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**SEND_TO_QWEN**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'SEND_TO_QWEN',
|
||||
action: string, // 'analyze_page' | 'analyze_screenshot' | 'ai_analyze' | 'process_text'
|
||||
data: any
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: any, // Qwen CLI 返回的数据
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
### Content Script APIs
|
||||
|
||||
#### 消息类型
|
||||
|
||||
**EXTRACT_DATA**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'EXTRACT_DATA'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data: {
|
||||
// 同 EXTRACT_PAGE_DATA 的 data 字段
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GET_SELECTED_TEXT**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'GET_SELECTED_TEXT'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data: string // 选中的文本
|
||||
}
|
||||
```
|
||||
|
||||
**HIGHLIGHT_ELEMENT**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'HIGHLIGHT_ELEMENT',
|
||||
selector: string // CSS 选择器
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean
|
||||
}
|
||||
```
|
||||
|
||||
**EXECUTE_CODE**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'EXECUTE_CODE',
|
||||
code: string // JavaScript 代码
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
data?: any, // 执行结果
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**SCROLL_TO**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'SCROLL_TO',
|
||||
x?: number,
|
||||
y?: number,
|
||||
smooth?: boolean
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean
|
||||
}
|
||||
```
|
||||
|
||||
#### 工具函数
|
||||
|
||||
**extractPageData()**
|
||||
```javascript
|
||||
function extractPageData(): PageData
|
||||
|
||||
interface PageData {
|
||||
url: string;
|
||||
title: string;
|
||||
domain: string;
|
||||
path: string;
|
||||
timestamp: string;
|
||||
meta: Record<string, string>;
|
||||
content: {
|
||||
text: string;
|
||||
html: string;
|
||||
markdown: string;
|
||||
};
|
||||
links: Link[];
|
||||
images: Image[];
|
||||
forms: Form[];
|
||||
consoleLogs: ConsoleLog[];
|
||||
performance: PerformanceMetrics;
|
||||
}
|
||||
```
|
||||
|
||||
**extractTextContent(element)**
|
||||
```javascript
|
||||
function extractTextContent(element: HTMLElement): string
|
||||
// 提取元素的纯文本内容,移除脚本和样式
|
||||
```
|
||||
|
||||
**htmlToMarkdown(element)**
|
||||
```javascript
|
||||
function htmlToMarkdown(element: HTMLElement): string
|
||||
// 将 HTML 转换为 Markdown 格式
|
||||
```
|
||||
|
||||
**getSelectedText()**
|
||||
```javascript
|
||||
function getSelectedText(): string
|
||||
// 获取用户选中的文本
|
||||
```
|
||||
|
||||
**highlightElement(selector)**
|
||||
```javascript
|
||||
function highlightElement(selector: string): boolean
|
||||
// 高亮指定的元素,3秒后自动移除
|
||||
```
|
||||
|
||||
**executeInPageContext(code)**
|
||||
```javascript
|
||||
async function executeInPageContext(code: string): Promise<any>
|
||||
// 在页面上下文中执行 JavaScript 代码
|
||||
```
|
||||
|
||||
## Native Host APIs
|
||||
|
||||
### 消息协议
|
||||
|
||||
#### 请求消息格式
|
||||
|
||||
```typescript
|
||||
interface RequestMessage {
|
||||
id?: number; // 请求 ID,用于匹配响应
|
||||
type: string; // 消息类型
|
||||
action?: string; // 具体动作
|
||||
data?: any; // 携带的数据
|
||||
config?: object; // 配置选项
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应消息格式
|
||||
|
||||
```typescript
|
||||
interface ResponseMessage {
|
||||
id?: number; // 对应的请求 ID
|
||||
type: 'response' | 'event' | 'handshake_response';
|
||||
data?: any; // 响应数据
|
||||
error?: string; // 错误信息
|
||||
success?: boolean; // 操作是否成功
|
||||
}
|
||||
```
|
||||
|
||||
### 消息类型
|
||||
|
||||
**handshake**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'handshake',
|
||||
version: string // 扩展版本
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
type: 'handshake_response',
|
||||
version: string,
|
||||
qwenInstalled: boolean,
|
||||
qwenStatus: string,
|
||||
capabilities: string[]
|
||||
}
|
||||
```
|
||||
|
||||
**start_qwen**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'start_qwen',
|
||||
config?: {
|
||||
mcpServers?: string[],
|
||||
httpPort?: number
|
||||
}
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
type: 'response',
|
||||
id: number,
|
||||
success: boolean,
|
||||
data?: {
|
||||
status: string,
|
||||
pid: number,
|
||||
capabilities: string[]
|
||||
},
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**stop_qwen**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'stop_qwen'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
type: 'response',
|
||||
id: number,
|
||||
success: boolean,
|
||||
data?: string,
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**qwen_request**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'qwen_request',
|
||||
action: string,
|
||||
data: any,
|
||||
config?: object
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
type: 'response',
|
||||
id: number,
|
||||
data?: any,
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
**get_status**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
type: 'get_status'
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
type: 'response',
|
||||
id: number,
|
||||
data: {
|
||||
qwenInstalled: boolean,
|
||||
qwenStatus: string,
|
||||
qwenPid: number | null,
|
||||
capabilities: string[]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 事件消息
|
||||
|
||||
**qwen_output**
|
||||
```javascript
|
||||
{
|
||||
type: 'event',
|
||||
data: {
|
||||
type: 'qwen_output',
|
||||
content: string // stdout 输出
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**qwen_error**
|
||||
```javascript
|
||||
{
|
||||
type: 'event',
|
||||
data: {
|
||||
type: 'qwen_error',
|
||||
content: string // stderr 输出
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**qwen_stopped**
|
||||
```javascript
|
||||
{
|
||||
type: 'event',
|
||||
data: {
|
||||
type: 'qwen_stopped',
|
||||
code: number // 退出码
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Qwen CLI 集成
|
||||
|
||||
### HTTP API 端点
|
||||
|
||||
**POST /api/process**
|
||||
```javascript
|
||||
// 请求
|
||||
{
|
||||
action: string,
|
||||
data: any
|
||||
}
|
||||
|
||||
// 响应
|
||||
{
|
||||
success: boolean,
|
||||
result?: any,
|
||||
error?: string
|
||||
}
|
||||
```
|
||||
|
||||
### 支持的动作
|
||||
|
||||
| 动作 | 描述 | 输入数据 | 返回数据 |
|
||||
|------|------|---------|---------|
|
||||
| `analyze_page` | 分析网页内容 | PageData | 分析结果 |
|
||||
| `analyze_screenshot` | 分析截图 | { screenshot: string, url: string } | 图片分析结果 |
|
||||
| `ai_analyze` | AI 深度分析 | { pageData: PageData, prompt: string } | AI 分析结果 |
|
||||
| `process_text` | 处理文本 | { text: string, context: string } | 处理后的文本 |
|
||||
|
||||
## Chrome Storage API
|
||||
|
||||
### 配置存储
|
||||
|
||||
```javascript
|
||||
// 保存配置
|
||||
await chrome.storage.local.set({
|
||||
mcpServers: 'chrome-devtools,playwright',
|
||||
httpPort: 8080,
|
||||
autoConnect: true
|
||||
});
|
||||
|
||||
// 读取配置
|
||||
const settings = await chrome.storage.local.get([
|
||||
'mcpServers',
|
||||
'httpPort',
|
||||
'autoConnect'
|
||||
]);
|
||||
```
|
||||
|
||||
### 存储结构
|
||||
|
||||
```typescript
|
||||
interface StorageSchema {
|
||||
mcpServers?: string; // 逗号分隔的服务器列表
|
||||
httpPort?: number; // HTTP 端口
|
||||
autoConnect?: boolean; // 是否自动连接
|
||||
lastConnected?: string; // 最后连接时间
|
||||
extensionVersion?: string; // 扩展版本
|
||||
}
|
||||
```
|
||||
|
||||
## 错误代码
|
||||
|
||||
| 错误代码 | 描述 | 处理建议 |
|
||||
|----------|------|----------|
|
||||
| `NATIVE_HOST_NOT_FOUND` | Native Host 未安装 | 运行安装脚本 |
|
||||
| `QWEN_NOT_INSTALLED` | Qwen CLI 未安装 | 安装 Qwen CLI |
|
||||
| `CONNECTION_FAILED` | 连接失败 | 检查 Native Host |
|
||||
| `PROCESS_START_FAILED` | 进程启动失败 | 检查 Qwen CLI 配置 |
|
||||
| `REQUEST_TIMEOUT` | 请求超时 | 重试请求 |
|
||||
| `INVALID_MESSAGE` | 消息格式错误 | 检查消息格式 |
|
||||
| `PERMISSION_DENIED` | 权限不足 | 检查扩展权限 |
|
||||
| `PORT_IN_USE` | 端口被占用 | 更换端口 |
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基本使用流程
|
||||
|
||||
```javascript
|
||||
// 1. 连接到 Native Host
|
||||
const connectResponse = await chrome.runtime.sendMessage({
|
||||
type: 'CONNECT'
|
||||
});
|
||||
|
||||
if (!connectResponse.success) {
|
||||
console.error('连接失败:', connectResponse.error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 启动 Qwen CLI
|
||||
const startResponse = await chrome.runtime.sendMessage({
|
||||
type: 'START_QWEN_CLI',
|
||||
config: {
|
||||
mcpServers: ['chrome-devtools-mcp'],
|
||||
httpPort: 8080
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 提取页面数据
|
||||
const pageDataResponse = await chrome.runtime.sendMessage({
|
||||
type: 'EXTRACT_PAGE_DATA'
|
||||
});
|
||||
|
||||
// 4. 发送给 Qwen 分析
|
||||
const analysisResponse = await chrome.runtime.sendMessage({
|
||||
type: 'SEND_TO_QWEN',
|
||||
action: 'analyze_page',
|
||||
data: pageDataResponse.data
|
||||
});
|
||||
|
||||
console.log('分析结果:', analysisResponse.data);
|
||||
```
|
||||
|
||||
### 高级功能示例
|
||||
|
||||
```javascript
|
||||
// 监听 Qwen 事件
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'QWEN_EVENT') {
|
||||
console.log('Qwen 事件:', message.event);
|
||||
|
||||
switch (message.event.type) {
|
||||
case 'qwen_output':
|
||||
// 处理输出
|
||||
updateUI(message.event.content);
|
||||
break;
|
||||
case 'qwen_error':
|
||||
// 处理错误
|
||||
showError(message.event.content);
|
||||
break;
|
||||
case 'qwen_stopped':
|
||||
// 处理停止
|
||||
handleStop(message.event.code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 版本兼容性
|
||||
|
||||
| 组件 | 最低版本 | 推荐版本 |
|
||||
|------|---------|---------|
|
||||
| Chrome | 88 | 最新稳定版 |
|
||||
| Node.js | 14.0.0 | 18+ |
|
||||
| Qwen CLI | 1.0.0 | 最新版 |
|
||||
| Manifest | V3 | V3 |
|
||||
|
||||
## 性能指标
|
||||
|
||||
| 操作 | 预期延迟 | 超时时间 |
|
||||
|------|---------|---------|
|
||||
| Native Host 连接 | <100ms | 5s |
|
||||
| Qwen CLI 启动 | <2s | 10s |
|
||||
| 页面数据提取 | <500ms | 5s |
|
||||
| 截图捕获 | <1s | 5s |
|
||||
| AI 分析请求 | <5s | 30s |
|
||||
| 消息往返 | <50ms | 1s |
|
||||
361
packages/chrome-qwen-bridge/docs/architecture.md
Normal file
361
packages/chrome-qwen-bridge/docs/architecture.md
Normal file
@@ -0,0 +1,361 @@
|
||||
# Chrome Qwen Bridge 架构设计文档
|
||||
|
||||
## 1. 项目概述
|
||||
|
||||
### 1.1 背景与需求
|
||||
|
||||
基于与 Kimi 的技术讨论,我们需要实现一个 Chrome 插件,能够:
|
||||
- 将浏览器中的数据(DOM、网络请求、Console日志等)透传给 Qwen CLI
|
||||
- 让 Qwen CLI 能够利用 AI 能力分析网页内容
|
||||
- 支持 MCP(Model Context Protocol)服务器集成
|
||||
- 实现浏览器与本地 CLI 的双向通信
|
||||
|
||||
### 1.2 技术约束
|
||||
|
||||
根据浏览器安全模型的限制:
|
||||
- **浏览器无法直接启动本地进程**:Chrome 插件运行在沙箱环境中
|
||||
- **无法直接调用 Node.js API**:插件无法访问文件系统或执行系统命令
|
||||
- **跨域限制**:需要遵守 CORS 策略
|
||||
|
||||
### 1.3 解决方案选择
|
||||
|
||||
经过评估,我们选择了 **Native Messaging** 方案:
|
||||
|
||||
| 方案 | 优点 | 缺点 | 选择理由 |
|
||||
|------|------|------|----------|
|
||||
| Native Messaging | - Chrome 官方推荐<br>- 无需开放端口<br>- 安全性高<br>- 可自动启动进程 | - 需要首次手动安装<br>- 平台相关配置 | ✅ 官方标准,安全可靠 |
|
||||
| HTTP Server | - 安装简单<br>- 跨平台统一 | - 需要占用端口<br>- 无法自动启动<br>- CORS 问题 | ❌ 用户体验较差 |
|
||||
| 文件轮询 | - 实现简单 | - 性能差<br>- 实时性差<br>- 不适合生产 | ❌ 仅适合调试 |
|
||||
|
||||
## 2. 系统架构
|
||||
|
||||
### 2.1 整体架构图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Chrome Browser │
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────────────────┐ │
|
||||
│ │ Chrome Extension │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
|
||||
│ │ │Content Script│ │Service Worker│ │ Popup UI │ │ │
|
||||
│ │ │ │◄─►│ │◄─►│ │ │ │
|
||||
│ │ │ - DOM提取 │ │ - 消息路由 │ │ - 用户交互 │ │ │
|
||||
│ │ │ - 事件监听 │ │ - 连接管理 │ │ - 状态显示 │ │ │
|
||||
│ │ │ - JS执行 │ │ - 请求处理 │ │ - 配置管理 │ │ │
|
||||
│ │ └─────────────┘ └──────┬───────┘ └──────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ └───────────────────────────┼────────────────────────────┘ │
|
||||
│ │ │
|
||||
└──────────────────────────────┼───────────────────────────────┘
|
||||
│
|
||||
Native Messaging API
|
||||
│
|
||||
▼
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Native Host (Node.js) │
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────┐ ┌────────────────┐ │
|
||||
│ │ Message Handler │ │Process Manager│ │ HTTP Client │ │
|
||||
│ │ │◄─►│ │◄─►│ │ │
|
||||
│ │ - JSON-RPC │ │ - spawn() │ │ - REST API │ │
|
||||
│ │ - 协议转换 │ │ - 生命周期 │ │ - WebSocket │ │
|
||||
│ │ - 错误处理 │ │ - 日志管理 │ │ - 状态同步 │ │
|
||||
│ └──────────────────┘ └──────┬───────┘ └────────┬───────┘ │
|
||||
│ │ │ │
|
||||
└────────────────────────────────┼────────────────────┼─────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────────────────────────────────────────────────────┐
|
||||
│ Qwen CLI │
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────┐ ┌────────────────┐ │
|
||||
│ │ CLI Process │ │ MCP Manager │ │ AI Engine │ │
|
||||
│ │ │◄─►│ │◄─►│ │ │
|
||||
│ │ - 命令解析 │ │ - 服务注册 │ │ - 内容分析 │ │
|
||||
│ │ - HTTP Server │ │ - 协议适配 │ │ - 智能处理 │ │
|
||||
│ │ - WebSocket │ │ - 工具调用 │ │ - 结果返回 │ │
|
||||
│ └──────────────────┘ └──────────────┘ └────────────────┘ │
|
||||
│ │
|
||||
│ MCP Servers │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ chrome-devtools-mcp │ playwright-mcp │ custom-mcp ... │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 组件职责
|
||||
|
||||
#### 2.2.1 Chrome Extension 层
|
||||
|
||||
**Content Script (`content-script.js`)**
|
||||
- 注入到每个网页中运行
|
||||
- 提取 DOM 结构、文本内容
|
||||
- 监听 Console 日志
|
||||
- 执行页面内 JavaScript
|
||||
- 捕获用户选择的文本
|
||||
|
||||
**Service Worker (`service-worker.js`)**
|
||||
- 管理 Native Messaging 连接
|
||||
- 路由消息between组件
|
||||
- 管理扩展生命周期
|
||||
- 处理网络请求监控(通过 Debugger API)
|
||||
|
||||
**Popup UI (`popup.html/js/css`)**
|
||||
- 提供用户界面
|
||||
- 显示连接状态
|
||||
- 触发各种操作
|
||||
- 管理配置选项
|
||||
|
||||
#### 2.2.2 Native Host 层
|
||||
|
||||
**Message Handler**
|
||||
- 实现 Native Messaging 协议
|
||||
- 4字节长度前缀 + JSON 消息
|
||||
- 双向消息队列管理
|
||||
- 错误处理与重试机制
|
||||
|
||||
**Process Manager**
|
||||
- 使用 `child_process.spawn()` 启动 Qwen CLI
|
||||
- 管理进程生命周期
|
||||
- 监控进程输出
|
||||
- 优雅关闭处理
|
||||
|
||||
**HTTP Client**
|
||||
- 与 Qwen CLI HTTP 服务通信
|
||||
- 支持 REST API 调用
|
||||
- WebSocket 连接管理(预留)
|
||||
|
||||
#### 2.2.3 Qwen CLI 层
|
||||
|
||||
- 接收并处理来自插件的请求
|
||||
- 管理 MCP 服务器
|
||||
- 调用 AI 模型分析内容
|
||||
- 返回处理结果
|
||||
|
||||
## 3. 数据流设计
|
||||
|
||||
### 3.1 消息流向
|
||||
|
||||
```
|
||||
用户操作 → Popup UI → Service Worker → Native Host → Qwen CLI → AI/MCP
|
||||
↓
|
||||
用户界面 ← Popup UI ← Service Worker ← Native Host ← 响应结果
|
||||
```
|
||||
|
||||
### 3.2 消息格式
|
||||
|
||||
#### Chrome Extension ↔ Native Host
|
||||
|
||||
```typescript
|
||||
interface Message {
|
||||
id: number; // 请求ID,用于匹配响应
|
||||
type: string; // 消息类型
|
||||
action?: string; // 具体动作
|
||||
data?: any; // 携带数据
|
||||
error?: string; // 错误信息
|
||||
}
|
||||
```
|
||||
|
||||
示例消息:
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"type": "qwen_request",
|
||||
"action": "analyze_page",
|
||||
"data": {
|
||||
"url": "https://example.com",
|
||||
"content": "...",
|
||||
"metadata": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Native Host ↔ Qwen CLI
|
||||
|
||||
使用 HTTP POST 请求:
|
||||
```json
|
||||
{
|
||||
"action": "analyze",
|
||||
"data": {
|
||||
"type": "webpage",
|
||||
"content": "...",
|
||||
"prompt": "分析这个网页的主要内容"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 状态管理
|
||||
|
||||
```typescript
|
||||
enum ConnectionState {
|
||||
DISCONNECTED = 'disconnected',
|
||||
CONNECTING = 'connecting',
|
||||
CONNECTED = 'connected',
|
||||
RUNNING = 'running',
|
||||
ERROR = 'error'
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 安全设计
|
||||
|
||||
### 4.1 权限控制
|
||||
|
||||
**Chrome Extension 权限**:
|
||||
```json
|
||||
{
|
||||
"permissions": [
|
||||
"nativeMessaging", // Native Host 通信
|
||||
"activeTab", // 当前标签页访问
|
||||
"storage", // 配置存储
|
||||
"debugger" // 网络请求监控
|
||||
],
|
||||
"host_permissions": [
|
||||
"<all_urls>" // 所有网站(可根据需要限制)
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 安全措施
|
||||
|
||||
1. **Native Messaging 安全**
|
||||
- 只允许特定扩展 ID 访问
|
||||
- Manifest 文件明确指定路径
|
||||
- 系统级权限保护
|
||||
|
||||
2. **数据安全**
|
||||
- 所有通信都在本地进行
|
||||
- 不存储敏感信息
|
||||
- 内容大小限制(防止内存溢出)
|
||||
|
||||
3. **进程安全**
|
||||
- 子进程权限继承用户权限
|
||||
- 无法执行系统级操作
|
||||
- 自动清理僵尸进程
|
||||
|
||||
## 5. 性能优化
|
||||
|
||||
### 5.1 数据传输优化
|
||||
|
||||
- **内容截断**:限制提取内容大小(50KB文本,30KB Markdown)
|
||||
- **懒加载**:只在需要时提取数据
|
||||
- **缓存机制**:缓存 Console 日志(最多100条)
|
||||
|
||||
### 5.2 进程管理优化
|
||||
|
||||
- **连接池**:复用 Native Messaging 连接
|
||||
- **超时控制**:30秒请求超时
|
||||
- **批量处理**:合并多个小请求
|
||||
|
||||
## 6. 错误处理
|
||||
|
||||
### 6.1 错误类型
|
||||
|
||||
| 错误类型 | 处理策略 | 用户提示 |
|
||||
|---------|---------|---------|
|
||||
| Native Host 未安装 | 引导安装 | "请先安装 Native Host" |
|
||||
| Qwen CLI 未安装 | 继续运行,功能受限 | "Qwen CLI 未安装,部分功能不可用" |
|
||||
| 连接断开 | 自动重连(3次) | "连接断开,正在重连..." |
|
||||
| 请求超时 | 返回超时错误 | "请求超时,请重试" |
|
||||
| 进程崩溃 | 清理并重启 | "Qwen CLI 异常退出" |
|
||||
|
||||
### 6.2 日志记录
|
||||
|
||||
- **Chrome Extension**:使用 `console.log`,可在扩展背景页查看
|
||||
- **Native Host**:写入文件
|
||||
- macOS/Linux: `/tmp/qwen-bridge-host.log`
|
||||
- Windows: `%TEMP%\qwen-bridge-host.log`
|
||||
|
||||
## 7. 扩展性设计
|
||||
|
||||
### 7.1 MCP 服务器扩展
|
||||
|
||||
支持动态添加 MCP 服务器:
|
||||
```javascript
|
||||
// 配置新的 MCP 服务器
|
||||
const mcpServers = [
|
||||
'chrome-devtools-mcp',
|
||||
'playwright-mcp',
|
||||
'custom-mcp' // 自定义服务器
|
||||
];
|
||||
```
|
||||
|
||||
### 7.2 动作扩展
|
||||
|
||||
易于添加新的处理动作:
|
||||
```javascript
|
||||
const actions = {
|
||||
'analyze_page': analyzePageHandler,
|
||||
'process_text': processTextHandler,
|
||||
'custom_action': customHandler // 自定义动作
|
||||
};
|
||||
```
|
||||
|
||||
### 7.3 通信协议扩展
|
||||
|
||||
预留 WebSocket 支持:
|
||||
```javascript
|
||||
// 未来可以升级为 WebSocket
|
||||
if (config.useWebSocket) {
|
||||
return new WebSocketConnection(url);
|
||||
} else {
|
||||
return new HTTPConnection(url);
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 部署架构
|
||||
|
||||
### 8.1 开发环境
|
||||
|
||||
```
|
||||
开发者机器
|
||||
├── Chrome (Developer Mode)
|
||||
├── Node.js 环境
|
||||
├── Qwen CLI (本地安装)
|
||||
└── MCP 服务器(可选)
|
||||
```
|
||||
|
||||
### 8.2 用户环境
|
||||
|
||||
```
|
||||
用户机器
|
||||
├── Chrome 浏览器
|
||||
├── Chrome Extension (从商店或本地加载)
|
||||
├── Native Host (一次性安装)
|
||||
├── Node.js 运行时
|
||||
└── Qwen CLI (用户安装)
|
||||
```
|
||||
|
||||
## 9. 技术栈
|
||||
|
||||
- **前端**:原生 JavaScript (ES6+)
|
||||
- **UI**:HTML5 + CSS3 (渐变设计)
|
||||
- **后端**:Node.js (Native Host)
|
||||
- **通信**:Native Messaging + HTTP
|
||||
- **进程管理**:child_process
|
||||
- **协议**:JSON-RPC 风格
|
||||
|
||||
## 10. 未来展望
|
||||
|
||||
### 10.1 短期优化
|
||||
- 添加 TypeScript 支持
|
||||
- 实现 WebSocket 实时通信
|
||||
- 优化 UI/UX 设计
|
||||
- 添加单元测试
|
||||
|
||||
### 10.2 长期规划
|
||||
- 支持更多浏览器(Firefox、Edge)
|
||||
- 开发配套的 VS Code 插件
|
||||
- 实现云端同步功能
|
||||
- 支持批量网页处理
|
||||
|
||||
## 附录:关键决策记录
|
||||
|
||||
| 决策点 | 选择 | 理由 |
|
||||
|--------|------|------|
|
||||
| 通信方式 | Native Messaging | Chrome 官方推荐,安全可靠 |
|
||||
| 进程管理 | child_process.spawn | 灵活控制,支持流式输出 |
|
||||
| UI 框架 | 原生 JavaScript | 减少依赖,快速加载 |
|
||||
| 消息格式 | JSON | 通用性好,易于调试 |
|
||||
| MCP 集成 | HTTP Transport | 简单可靠,易于实现 |
|
||||
295
packages/chrome-qwen-bridge/docs/debugging.md
Normal file
295
packages/chrome-qwen-bridge/docs/debugging.md
Normal file
@@ -0,0 +1,295 @@
|
||||
# Chrome Qwen Bridge 调试指南
|
||||
|
||||
## 🚀 快速开始调试
|
||||
|
||||
### 一键启动(推荐)
|
||||
|
||||
最简单的方式是使用我们提供的一键启动脚本:
|
||||
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd packages/chrome-qwen-bridge
|
||||
|
||||
# 方式一:使用 npm 脚本(跨平台)
|
||||
npm run dev
|
||||
|
||||
# 方式二:使用 shell 脚本(macOS/Linux)
|
||||
npm run dev:quick
|
||||
# 或直接运行
|
||||
./start.sh
|
||||
```
|
||||
|
||||
**脚本会自动完成以下操作:**
|
||||
1. ✅ 检查并配置 Chrome
|
||||
2. ✅ 安装 Native Host
|
||||
3. ✅ 检查 Qwen CLI
|
||||
4. ✅ 启动 Qwen 服务器(端口 8080)
|
||||
5. ✅ 启动测试页面服务器(端口 3000)
|
||||
6. ✅ 启动 Chrome 并加载插件
|
||||
7. ✅ 自动打开 DevTools
|
||||
|
||||
## 📝 可用的 npm 命令
|
||||
|
||||
```bash
|
||||
# 开发调试
|
||||
npm run dev # 完整的开发环境启动(Node.js 脚本)
|
||||
npm run dev:quick # 快速启动(Shell 脚本)
|
||||
npm run dev:stop # 停止所有服务
|
||||
npm run dev:chrome # 仅启动 Chrome 加载插件
|
||||
npm run dev:server # 仅启动 Qwen 服务器
|
||||
|
||||
# 安装配置
|
||||
npm run install:host # 安装 Native Host 依赖
|
||||
npm run install:host:macos # macOS 安装 Native Host
|
||||
npm run install:host:windows # Windows 安装 Native Host
|
||||
|
||||
# 构建打包
|
||||
npm run build # 构建项目
|
||||
npm run package # 打包扩展为 zip
|
||||
npm run package:source # 打包源代码
|
||||
|
||||
# 日志查看
|
||||
npm run logs # 查看 Native Host 日志
|
||||
npm run logs:qwen # 查看 Qwen 服务器日志
|
||||
|
||||
# 清理
|
||||
npm run clean # 清理构建文件和日志
|
||||
```
|
||||
|
||||
## 🔧 手动调试步骤
|
||||
|
||||
如果自动脚本有问题,可以手动进行调试:
|
||||
|
||||
### 步骤 1:安装 Native Host
|
||||
|
||||
```bash
|
||||
# macOS/Linux
|
||||
cd native-host
|
||||
./install.sh
|
||||
|
||||
# Windows(管理员权限)
|
||||
cd native-host
|
||||
install.bat
|
||||
```
|
||||
|
||||
### 步骤 2:启动 Qwen 服务器(可选)
|
||||
|
||||
```bash
|
||||
# 如果安装了 Qwen CLI
|
||||
qwen server --port 8080
|
||||
```
|
||||
|
||||
### 步骤 3:加载插件到 Chrome
|
||||
|
||||
1. 打开 Chrome
|
||||
2. 访问 `chrome://extensions/`
|
||||
3. 开启「开发者模式」
|
||||
4. 点击「加载已解压的扩展程序」
|
||||
5. 选择 `packages/chrome-qwen-bridge/extension` 目录
|
||||
|
||||
### 步骤 4:测试插件
|
||||
|
||||
1. 打开任意网页(或访问 http://localhost:3000)
|
||||
2. 点击工具栏中的插件图标
|
||||
3. 点击「Connect to Qwen CLI」
|
||||
4. 测试各项功能
|
||||
|
||||
## 🐛 调试技巧
|
||||
|
||||
### 1. Chrome DevTools
|
||||
|
||||
#### Service Worker (Background Script)
|
||||
- 打开 `chrome://extensions/`
|
||||
- 找到 Qwen CLI Bridge
|
||||
- 点击「Service Worker」链接
|
||||
- 在打开的 DevTools 中查看日志
|
||||
|
||||
#### Content Script
|
||||
- 在任意网页上右键 → 检查
|
||||
- 在 Console 中查看 content script 的日志
|
||||
- 使用 Sources 面板设置断点
|
||||
|
||||
#### Popup
|
||||
- 右键点击插件图标
|
||||
- 选择「检查弹出内容」
|
||||
- 在 DevTools 中调试 popup 代码
|
||||
|
||||
### 2. Native Host 调试
|
||||
|
||||
查看 Native Host 日志:
|
||||
```bash
|
||||
# macOS/Linux
|
||||
tail -f /tmp/qwen-bridge-host.log
|
||||
|
||||
# 或使用 npm 命令
|
||||
npm run logs
|
||||
```
|
||||
|
||||
测试 Native Host 连接:
|
||||
```javascript
|
||||
// 在 Service Worker console 中执行
|
||||
chrome.runtime.sendNativeMessage('com.qwen.cli.bridge',
|
||||
{type: 'handshake', version: '1.0.0'},
|
||||
response => console.log('Native Host response:', response)
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 消息调试
|
||||
|
||||
在 Service Worker 中添加日志:
|
||||
```javascript
|
||||
// background/service-worker.js
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
console.log('Message received:', request, 'from:', sender);
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
### 4. 网络请求调试
|
||||
|
||||
使用 Chrome DevTools Network 面板:
|
||||
- 查看与 Qwen 服务器的 HTTP 通信
|
||||
- 检查请求/响应头和内容
|
||||
- 查看请求时间
|
||||
|
||||
## 🔍 常见问题排查
|
||||
|
||||
### 问题:Native Host 连接失败
|
||||
|
||||
**症状**:点击「Connect」后显示连接错误
|
||||
|
||||
**解决方案**:
|
||||
1. 检查 Native Host 是否正确安装:
|
||||
```bash
|
||||
# macOS
|
||||
ls ~/Library/Application\ Support/Google/Chrome/NativeMessagingHosts/
|
||||
|
||||
# Linux
|
||||
ls ~/.config/google-chrome/NativeMessagingHosts/
|
||||
```
|
||||
|
||||
2. 验证 manifest.json 中的路径是否正确
|
||||
3. 确保 host.js 有执行权限:
|
||||
```bash
|
||||
chmod +x native-host/host.js
|
||||
```
|
||||
|
||||
### 问题:Qwen CLI 未响应
|
||||
|
||||
**症状**:显示 Qwen CLI 未安装或无响应
|
||||
|
||||
**解决方案**:
|
||||
1. 确认 Qwen CLI 已安装:
|
||||
```bash
|
||||
qwen --version
|
||||
```
|
||||
|
||||
2. 手动启动 Qwen 服务器:
|
||||
```bash
|
||||
qwen server --port 8080
|
||||
```
|
||||
|
||||
3. 检查端口是否被占用:
|
||||
```bash
|
||||
lsof -i:8080
|
||||
```
|
||||
|
||||
### 问题:插件图标不显示
|
||||
|
||||
**症状**:加载插件后工具栏没有图标
|
||||
|
||||
**解决方案**:
|
||||
1. 点击 Chrome 扩展图标(拼图图标)
|
||||
2. 找到「Qwen CLI Bridge」
|
||||
3. 点击固定图标
|
||||
|
||||
### 问题:Content Script 未注入
|
||||
|
||||
**症状**:提取页面数据失败
|
||||
|
||||
**解决方案**:
|
||||
1. 刷新目标网页
|
||||
2. 检查 manifest.json 的 content_scripts 配置
|
||||
3. 确认网页不是 Chrome 内部页面(chrome://)
|
||||
|
||||
## 📊 性能分析
|
||||
|
||||
### Memory 分析
|
||||
1. 打开 Chrome Task Manager(Shift + Esc)
|
||||
2. 查看扩展的内存使用
|
||||
3. 使用 DevTools Memory Profiler
|
||||
|
||||
### Performance 分析
|
||||
1. 在 DevTools 中打开 Performance 面板
|
||||
2. 记录操作过程
|
||||
3. 分析瓶颈
|
||||
|
||||
## 🔄 热重载开发
|
||||
|
||||
虽然 Chrome Extension 不支持真正的热重载,但可以:
|
||||
|
||||
1. **快速重载扩展**:
|
||||
- 在 `chrome://extensions/` 点击重载按钮
|
||||
- 或使用快捷键:Cmd+R (macOS) / Ctrl+R (Windows/Linux)
|
||||
|
||||
2. **自动重载 Content Script**:
|
||||
修改代码后刷新网页即可
|
||||
|
||||
3. **保持 Qwen 服务器运行**:
|
||||
Qwen 服务器不需要重启,只需重载扩展
|
||||
|
||||
## 📱 远程调试
|
||||
|
||||
如果需要在其他设备上调试:
|
||||
|
||||
1. **启用远程调试**:
|
||||
```bash
|
||||
google-chrome --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
2. **访问调试界面**:
|
||||
```
|
||||
http://localhost:9222
|
||||
```
|
||||
|
||||
3. **使用 Chrome DevTools Protocol**:
|
||||
可以编程控制和调试
|
||||
|
||||
## 💡 开发建议
|
||||
|
||||
1. **使用 console.log 大量输出日志**
|
||||
- 在开发阶段多打日志
|
||||
- 生产环境再移除
|
||||
|
||||
2. **利用 Chrome Storage API 存储调试信息**
|
||||
```javascript
|
||||
chrome.storage.local.set({debug: data});
|
||||
```
|
||||
|
||||
3. **创建测试页面**
|
||||
- 包含各种测试场景
|
||||
- 方便重复测试
|
||||
|
||||
4. **使用 Postman 测试 API**
|
||||
- 测试与 Qwen 服务器的通信
|
||||
- 验证数据格式
|
||||
|
||||
## 📚 相关资源
|
||||
|
||||
- [Chrome Extension 开发文档](https://developer.chrome.com/docs/extensions/mv3/)
|
||||
- [Native Messaging 文档](https://developer.chrome.com/docs/apps/nativeMessaging/)
|
||||
- [Chrome DevTools 文档](https://developer.chrome.com/docs/devtools/)
|
||||
- [项目 API 参考](./api-reference.md)
|
||||
|
||||
## 🆘 获取帮助
|
||||
|
||||
如果遇到问题:
|
||||
|
||||
1. 查看 [技术细节文档](./technical-details.md)
|
||||
2. 检查 [API 参考文档](./api-reference.md)
|
||||
3. 提交 Issue 到 GitHub
|
||||
4. 查看日志文件寻找错误信息
|
||||
|
||||
---
|
||||
|
||||
祝调试愉快!🎉
|
||||
280
packages/chrome-qwen-bridge/docs/implementation-plan.md
Normal file
280
packages/chrome-qwen-bridge/docs/implementation-plan.md
Normal file
@@ -0,0 +1,280 @@
|
||||
# Chrome Qwen Bridge 实施计划
|
||||
|
||||
## 项目背景
|
||||
|
||||
基于用户需求和技术调研,需要开发一个 Chrome 插件,实现浏览器与 Qwen CLI 之间的数据桥接,让 AI 能够分析和处理网页内容。
|
||||
|
||||
## 实施阶段
|
||||
|
||||
### 第一阶段:基础架构搭建(已完成 ✅)
|
||||
|
||||
#### 1.1 Chrome 插件基础结构
|
||||
- ✅ 创建项目目录结构
|
||||
- ✅ 配置 manifest.json (Manifest V3)
|
||||
- ✅ 设置必要的权限和配置
|
||||
|
||||
#### 1.2 核心组件开发
|
||||
- ✅ **Background Service Worker**
|
||||
- 实现消息路由
|
||||
- 管理 Native Messaging 连接
|
||||
- 处理扩展生命周期
|
||||
|
||||
- ✅ **Content Script**
|
||||
- DOM 内容提取
|
||||
- Console 日志拦截
|
||||
- 页面事件监听
|
||||
- HTML 转 Markdown 转换器
|
||||
|
||||
- ✅ **Popup UI**
|
||||
- 用户界面设计(渐变主题)
|
||||
- 状态指示器
|
||||
- 操作按钮组
|
||||
- 响应结果展示
|
||||
- 设置管理
|
||||
|
||||
#### 1.3 功能实现清单
|
||||
|
||||
| 功能模块 | 具体功能 | 状态 |
|
||||
|---------|---------|------|
|
||||
| **数据提取** | | |
|
||||
| | 提取页面文本内容 | ✅ |
|
||||
| | 提取页面 HTML | ✅ |
|
||||
| | 转换为 Markdown | ✅ |
|
||||
| | 提取链接列表 | ✅ |
|
||||
| | 提取图片信息 | ✅ |
|
||||
| | 提取表单结构 | ✅ |
|
||||
| | 提取元数据 | ✅ |
|
||||
| **监控功能** | | |
|
||||
| | Console 日志捕获 | ✅ |
|
||||
| | 网络请求监控 | ✅ |
|
||||
| | 性能指标收集 | ✅ |
|
||||
| **交互功能** | | |
|
||||
| | 截图捕获 | ✅ |
|
||||
| | 选中文本获取 | ✅ |
|
||||
| | 元素高亮 | ✅ |
|
||||
| | 执行 JavaScript | ✅ |
|
||||
| | 页面滚动控制 | ✅ |
|
||||
|
||||
### 第二阶段:Native Messaging 实现(已完成 ✅)
|
||||
|
||||
#### 2.1 Native Host 开发
|
||||
- ✅ **host.js 核心脚本**
|
||||
- Native Messaging 协议实现
|
||||
- 4字节长度前缀处理
|
||||
- JSON 消息解析
|
||||
- 双向通信管道
|
||||
|
||||
#### 2.2 进程管理
|
||||
- ✅ Qwen CLI 进程启动/停止
|
||||
- ✅ 进程状态监控
|
||||
- ✅ 输出流捕获
|
||||
- ✅ 错误处理
|
||||
- ✅ 优雅退出机制
|
||||
|
||||
#### 2.3 安装脚本
|
||||
- ✅ macOS/Linux 安装脚本 (`install.sh`)
|
||||
- ✅ Windows 安装脚本 (`install.bat`)
|
||||
- ✅ Manifest 文件生成
|
||||
- ✅ 权限配置
|
||||
|
||||
### 第三阶段:Qwen CLI 集成(已完成 ✅)
|
||||
|
||||
#### 3.1 通信实现
|
||||
- ✅ HTTP 请求封装
|
||||
- ✅ MCP 服务器配置
|
||||
- ✅ 动态端口管理
|
||||
- ✅ 错误重试机制
|
||||
|
||||
#### 3.2 MCP 服务器支持
|
||||
```javascript
|
||||
// 支持的 MCP 服务器配置
|
||||
const mcpServers = [
|
||||
'chrome-devtools-mcp', // Chrome 开发工具
|
||||
'playwright-mcp', // 浏览器自动化
|
||||
'custom-mcp' // 自定义服务器
|
||||
];
|
||||
```
|
||||
|
||||
### 第四阶段:项目集成(已完成 ✅)
|
||||
|
||||
#### 4.1 Mono Repo 集成
|
||||
- ✅ 移动到 packages 目录
|
||||
- ✅ 配置 package.json
|
||||
- ✅ 添加 TypeScript 配置
|
||||
- ✅ 创建构建脚本
|
||||
- ✅ 配置 .gitignore
|
||||
|
||||
#### 4.2 文档编写
|
||||
- ✅ README 主文档
|
||||
- ✅ 架构设计文档
|
||||
- ✅ 实施计划文档(本文档)
|
||||
- 🔄 技术细节文档
|
||||
- 🔄 API 参考文档
|
||||
|
||||
## 技术栈选择
|
||||
|
||||
| 层次 | 技术选择 | 选择理由 |
|
||||
|------|---------|----------|
|
||||
| **Chrome Extension** | | |
|
||||
| 开发语言 | JavaScript (ES6+) | 原生支持,无需构建 |
|
||||
| UI 框架 | 原生 HTML/CSS | 轻量快速,无依赖 |
|
||||
| 消息传递 | Chrome Extension API | 官方标准 |
|
||||
| **Native Host** | | |
|
||||
| 运行时 | Node.js | 跨平台,生态丰富 |
|
||||
| 进程管理 | child_process | Node.js 内置 |
|
||||
| **通信协议** | | |
|
||||
| Extension ↔ Host | Native Messaging | Chrome 官方推荐 |
|
||||
| Host ↔ Qwen | HTTP/REST | 简单可靠 |
|
||||
| 数据格式 | JSON | 通用性好 |
|
||||
|
||||
## 实现细节
|
||||
|
||||
### Native Messaging 协议实现
|
||||
|
||||
```javascript
|
||||
// 发送消息(4字节长度前缀 + JSON)
|
||||
function sendMessage(message) {
|
||||
const buffer = Buffer.from(JSON.stringify(message));
|
||||
const length = Buffer.allocUnsafe(4);
|
||||
length.writeUInt32LE(buffer.length, 0);
|
||||
|
||||
process.stdout.write(length);
|
||||
process.stdout.write(buffer);
|
||||
}
|
||||
|
||||
// 接收消息
|
||||
function readMessages() {
|
||||
let messageLength = null;
|
||||
let chunks = [];
|
||||
|
||||
process.stdin.on('readable', () => {
|
||||
// 读取长度前缀
|
||||
// 读取消息内容
|
||||
// 处理消息
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 进程启动命令
|
||||
|
||||
```javascript
|
||||
// 启动 Qwen CLI 的完整命令
|
||||
const command = [
|
||||
// 添加 MCP 服务器
|
||||
'qwen mcp add --transport http chrome-devtools http://localhost:8080/mcp',
|
||||
'&&',
|
||||
// 启动 CLI 服务器
|
||||
'qwen server --port 8080'
|
||||
].join(' ');
|
||||
|
||||
spawn(command, { shell: true });
|
||||
```
|
||||
|
||||
## 测试计划
|
||||
|
||||
### 单元测试
|
||||
- [ ] Message Handler 测试
|
||||
- [ ] 数据提取功能测试
|
||||
- [ ] 进程管理测试
|
||||
|
||||
### 集成测试
|
||||
- [ ] Extension ↔ Native Host 通信
|
||||
- [ ] Native Host ↔ Qwen CLI 通信
|
||||
- [ ] 端到端数据流测试
|
||||
|
||||
### 用户测试
|
||||
- [ ] 安装流程测试
|
||||
- [ ] 功能完整性测试
|
||||
- [ ] 错误恢复测试
|
||||
- [ ] 性能测试
|
||||
|
||||
## 部署计划
|
||||
|
||||
### 开发环境部署
|
||||
1. Clone 代码库
|
||||
2. 加载未打包的扩展
|
||||
3. 运行安装脚本
|
||||
4. 测试功能
|
||||
|
||||
### 生产环境部署
|
||||
1. 构建扩展包
|
||||
2. 提交到 Chrome Web Store(可选)
|
||||
3. 提供安装指南
|
||||
4. 用户支持文档
|
||||
|
||||
## 时间线(已完成)
|
||||
|
||||
| 阶段 | 任务 | 预计时间 | 实际状态 |
|
||||
|------|------|---------|----------|
|
||||
| 第一阶段 | 基础架构 | 2小时 | ✅ 完成 |
|
||||
| 第二阶段 | Native Host | 2小时 | ✅ 完成 |
|
||||
| 第三阶段 | Qwen 集成 | 1小时 | ✅ 完成 |
|
||||
| 第四阶段 | 项目集成 | 1小时 | ✅ 完成 |
|
||||
| 第五阶段 | 测试优化 | 2小时 | 🔄 进行中 |
|
||||
|
||||
## 风险评估
|
||||
|
||||
| 风险项 | 可能性 | 影响 | 缓解措施 |
|
||||
|--------|-------|------|----------|
|
||||
| Native Host 安装失败 | 中 | 高 | 提供详细文档和脚本 |
|
||||
| Qwen CLI 未安装 | 高 | 中 | 优雅降级,提示用户 |
|
||||
| 权限不足 | 低 | 高 | 明确权限要求 |
|
||||
| 性能问题 | 中 | 中 | 数据大小限制 |
|
||||
| 兼容性问题 | 低 | 中 | 多平台测试 |
|
||||
|
||||
## 优化计划
|
||||
|
||||
### 短期优化(1-2周)
|
||||
- 添加 TypeScript 类型定义
|
||||
- 实现 WebSocket 通信
|
||||
- 优化错误提示
|
||||
- 添加更多 MCP 服务器
|
||||
|
||||
### 中期优化(1-2月)
|
||||
- 开发选项页面
|
||||
- 实现配置同步
|
||||
- 添加快捷键支持
|
||||
- 国际化支持
|
||||
|
||||
### 长期优化(3-6月)
|
||||
- 支持 Firefox/Edge
|
||||
- 云端配置同步
|
||||
- 批量处理模式
|
||||
- AI 模型选择
|
||||
|
||||
## 维护计划
|
||||
|
||||
### 日常维护
|
||||
- Bug 修复
|
||||
- 安全更新
|
||||
- 依赖升级
|
||||
|
||||
### 版本发布
|
||||
- 遵循语义化版本
|
||||
- 维护 CHANGELOG
|
||||
- 发布说明
|
||||
|
||||
### 用户支持
|
||||
- GitHub Issues
|
||||
- 文档更新
|
||||
- FAQ 维护
|
||||
|
||||
## 成功指标
|
||||
|
||||
- ✅ 成功实现浏览器与 Qwen CLI 通信
|
||||
- ✅ 支持主要数据提取功能
|
||||
- ✅ 稳定的进程管理
|
||||
- ✅ 良好的用户体验
|
||||
- 🔄 完善的文档
|
||||
- 🔄 社区反馈收集
|
||||
|
||||
## 总结
|
||||
|
||||
项目已成功完成核心功能开发,实现了:
|
||||
1. Chrome 插件与本地 Qwen CLI 的桥接
|
||||
2. 丰富的数据提取和监控功能
|
||||
3. 安全可靠的 Native Messaging 通信
|
||||
4. 灵活的 MCP 服务器集成
|
||||
5. 跨平台支持
|
||||
|
||||
下一步将重点优化用户体验和完善文档。
|
||||
534
packages/chrome-qwen-bridge/docs/technical-details.md
Normal file
534
packages/chrome-qwen-bridge/docs/technical-details.md
Normal file
@@ -0,0 +1,534 @@
|
||||
# Chrome Qwen Bridge 技术细节文档
|
||||
|
||||
## Native Messaging 协议详解
|
||||
|
||||
### 协议规范
|
||||
|
||||
Chrome 的 Native Messaging 使用简单的基于消息长度的协议:
|
||||
|
||||
```
|
||||
[4字节长度][JSON消息内容]
|
||||
```
|
||||
|
||||
- **长度前缀**:32位无符号整数,小端字节序
|
||||
- **消息内容**:UTF-8 编码的 JSON 字符串
|
||||
- **最大消息大小**:1MB (Chrome 限制)
|
||||
|
||||
### 实现细节
|
||||
|
||||
#### 消息发送实现
|
||||
|
||||
```javascript
|
||||
function sendMessage(message) {
|
||||
// 1. 将消息对象转换为 JSON 字符串
|
||||
const jsonString = JSON.stringify(message);
|
||||
|
||||
// 2. 转换为 Buffer
|
||||
const buffer = Buffer.from(jsonString, 'utf8');
|
||||
|
||||
// 3. 创建 4 字节的长度前缀
|
||||
const lengthBuffer = Buffer.allocUnsafe(4);
|
||||
lengthBuffer.writeUInt32LE(buffer.length, 0);
|
||||
|
||||
// 4. 写入 stdout
|
||||
process.stdout.write(lengthBuffer);
|
||||
process.stdout.write(buffer);
|
||||
}
|
||||
```
|
||||
|
||||
#### 消息接收实现
|
||||
|
||||
```javascript
|
||||
function readMessages() {
|
||||
let messageLength = null;
|
||||
let chunks = [];
|
||||
|
||||
process.stdin.on('readable', () => {
|
||||
let chunk;
|
||||
|
||||
while ((chunk = process.stdin.read()) !== null) {
|
||||
chunks.push(chunk);
|
||||
const buffer = Buffer.concat(chunks);
|
||||
|
||||
// 第一步:读取消息长度
|
||||
if (messageLength === null) {
|
||||
if (buffer.length >= 4) {
|
||||
messageLength = buffer.readUInt32LE(0);
|
||||
chunks = [buffer.slice(4)];
|
||||
}
|
||||
}
|
||||
|
||||
// 第二步:读取消息内容
|
||||
if (messageLength !== null) {
|
||||
const fullBuffer = Buffer.concat(chunks);
|
||||
|
||||
if (fullBuffer.length >= messageLength) {
|
||||
const messageBuffer = fullBuffer.slice(0, messageLength);
|
||||
const message = JSON.parse(messageBuffer.toString('utf8'));
|
||||
|
||||
// 重置状态,准备读取下一条消息
|
||||
chunks = [fullBuffer.slice(messageLength)];
|
||||
messageLength = null;
|
||||
|
||||
// 处理消息
|
||||
handleMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 错误处理
|
||||
|
||||
1. **JSON 解析错误**:发送错误响应
|
||||
2. **长度溢出**:拒绝超过 1MB 的消息
|
||||
3. **流关闭**:优雅退出进程
|
||||
|
||||
## Chrome Extension API 使用
|
||||
|
||||
### 权限说明
|
||||
|
||||
| 权限 | 用途 | 风险级别 |
|
||||
|------|------|---------|
|
||||
| `nativeMessaging` | 与 Native Host 通信 | 高 |
|
||||
| `activeTab` | 访问当前标签页 | 中 |
|
||||
| `tabs` | 管理标签页 | 中 |
|
||||
| `storage` | 存储配置 | 低 |
|
||||
| `debugger` | 网络监控 | 高 |
|
||||
| `scripting` | 注入脚本 | 高 |
|
||||
| `webNavigation` | 页面导航事件 | 中 |
|
||||
| `cookies` | Cookie 访问 | 中 |
|
||||
|
||||
### Content Script 注入
|
||||
|
||||
```javascript
|
||||
// manifest.json 配置
|
||||
{
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"], // 所有网页
|
||||
"js": ["content/content-script.js"],
|
||||
"run_at": "document_idle" // DOM 加载完成后
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Service Worker 生命周期
|
||||
|
||||
Service Worker 在 Manifest V3 中替代了 Background Page:
|
||||
|
||||
```javascript
|
||||
// 扩展安装/更新时
|
||||
chrome.runtime.onInstalled.addListener((details) => {
|
||||
if (details.reason === 'install') {
|
||||
// 首次安装
|
||||
} else if (details.reason === 'update') {
|
||||
// 更新
|
||||
}
|
||||
});
|
||||
|
||||
// Service Worker 可能会被系统终止
|
||||
// 使用 chrome.storage 持久化状态
|
||||
```
|
||||
|
||||
## 数据提取算法
|
||||
|
||||
### DOM 内容提取策略
|
||||
|
||||
```javascript
|
||||
function extractPageData() {
|
||||
// 1. 优先查找语义化标签
|
||||
const mainContent = document.querySelector(
|
||||
'article, main, [role="main"], #content, .content'
|
||||
) || document.body;
|
||||
|
||||
// 2. 克隆节点避免修改原始 DOM
|
||||
const clone = mainContent.cloneNode(true);
|
||||
|
||||
// 3. 移除干扰元素
|
||||
const removeSelectors = [
|
||||
'script', 'style', 'noscript', 'iframe',
|
||||
'nav', 'header', 'footer', '.ad', '#ads'
|
||||
];
|
||||
|
||||
removeSelectors.forEach(selector => {
|
||||
clone.querySelectorAll(selector).forEach(el => el.remove());
|
||||
});
|
||||
|
||||
// 4. 提取文本内容
|
||||
return clone.textContent.trim();
|
||||
}
|
||||
```
|
||||
|
||||
### HTML 转 Markdown 算法
|
||||
|
||||
```javascript
|
||||
function htmlToMarkdown(element) {
|
||||
const rules = {
|
||||
'h1': (node) => `# ${node.textContent}\n`,
|
||||
'h2': (node) => `## ${node.textContent}\n`,
|
||||
'h3': (node) => `### ${node.textContent}\n`,
|
||||
'p': (node) => `${node.textContent}\n\n`,
|
||||
'a': (node) => `[${node.textContent}](${node.href})`,
|
||||
'img': (node) => ``,
|
||||
'ul,ol': (node) => processLi",
|
||||
'code': (node) => `\`${node.textContent}\``,
|
||||
'pre': (node) => `\`\`\`\n${node.textContent}\n\`\`\``,
|
||||
'blockquote': (node) => `> ${node.textContent}`,
|
||||
'strong,b': (node) => `**${node.textContent}**`,
|
||||
'em,i': (node) => `*${node.textContent}*`
|
||||
};
|
||||
|
||||
// 递归遍历 DOM 树
|
||||
// 应用转换规则
|
||||
// 返回 Markdown 字符串
|
||||
}
|
||||
```
|
||||
|
||||
### Console 日志拦截
|
||||
|
||||
```javascript
|
||||
// 保存原始 console 方法
|
||||
const originalConsole = {
|
||||
log: console.log,
|
||||
error: console.error,
|
||||
warn: console.warn,
|
||||
info: console.info
|
||||
};
|
||||
|
||||
// 拦截并记录
|
||||
['log', 'error', 'warn', 'info'].forEach(method => {
|
||||
console[method] = function(...args) {
|
||||
// 记录日志
|
||||
consoleLogs.push({
|
||||
type: method,
|
||||
message: args.map(formatArg).join(' '),
|
||||
timestamp: Date.now(),
|
||||
stack: new Error().stack
|
||||
});
|
||||
|
||||
// 调用原始方法
|
||||
originalConsole[method].apply(console, args);
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
## 进程管理详解
|
||||
|
||||
### Qwen CLI 启动流程
|
||||
|
||||
```javascript
|
||||
async function startQwenCli(config) {
|
||||
// 1. 构建命令参数
|
||||
const commands = [];
|
||||
|
||||
// 2. 添加 MCP 服务器
|
||||
for (const server of config.mcpServers) {
|
||||
commands.push(
|
||||
`qwen mcp add --transport http ${server} ` +
|
||||
`http://localhost:${config.port}/mcp/${server}`
|
||||
);
|
||||
}
|
||||
|
||||
// 3. 启动服务器
|
||||
commands.push(`qwen server --port ${config.port}`);
|
||||
|
||||
// 4. 使用 shell 执行复合命令
|
||||
const process = spawn(commands.join(' && '), {
|
||||
shell: true, // 使用 shell 执行
|
||||
detached: false, // 不分离进程
|
||||
windowsHide: true, // Windows 下隐藏窗口
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
});
|
||||
|
||||
// 5. 监控输出
|
||||
process.stdout.on('data', handleOutput);
|
||||
process.stderr.on('data', handleError);
|
||||
process.on('exit', handleExit);
|
||||
|
||||
return process;
|
||||
}
|
||||
```
|
||||
|
||||
### 进程清理
|
||||
|
||||
```javascript
|
||||
// 优雅关闭
|
||||
function gracefulShutdown() {
|
||||
if (qwenProcess) {
|
||||
// 发送 SIGTERM
|
||||
qwenProcess.kill('SIGTERM');
|
||||
|
||||
// 等待进程退出
|
||||
setTimeout(() => {
|
||||
if (!qwenProcess.killed) {
|
||||
// 强制结束
|
||||
qwenProcess.kill('SIGKILL');
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// 注册清理处理器
|
||||
process.on('SIGINT', gracefulShutdown);
|
||||
process.on('SIGTERM', gracefulShutdown);
|
||||
process.on('exit', gracefulShutdown);
|
||||
```
|
||||
|
||||
## 性能优化技巧
|
||||
|
||||
### 内存管理
|
||||
|
||||
1. **内容大小限制**
|
||||
```javascript
|
||||
const MAX_TEXT_LENGTH = 50000; // 50KB
|
||||
const MAX_HTML_LENGTH = 100000; // 100KB
|
||||
const MAX_LOGS = 100; // 最多 100 条日志
|
||||
```
|
||||
|
||||
2. **防止内存泄漏**
|
||||
```javascript
|
||||
// 使用 WeakMap 存储 DOM 引用
|
||||
const elementCache = new WeakMap();
|
||||
|
||||
// 定期清理
|
||||
setInterval(() => {
|
||||
consoleLogs.splice(0, consoleLogs.length - MAX_LOGS);
|
||||
}, 60000);
|
||||
```
|
||||
|
||||
### 响应时间优化
|
||||
|
||||
1. **懒加载**
|
||||
```javascript
|
||||
// 只在需要时提取数据
|
||||
async function getPageData() {
|
||||
if (!pageDataCache) {
|
||||
pageDataCache = await extractPageData();
|
||||
}
|
||||
return pageDataCache;
|
||||
}
|
||||
```
|
||||
|
||||
2. **批处理**
|
||||
```javascript
|
||||
// 合并多个请求
|
||||
const requestQueue = [];
|
||||
const flushQueue = debounce(() => {
|
||||
sendBatchRequest(requestQueue);
|
||||
requestQueue.length = 0;
|
||||
}, 100);
|
||||
```
|
||||
|
||||
## 安全最佳实践
|
||||
|
||||
### 输入验证
|
||||
|
||||
```javascript
|
||||
function validateMessage(message) {
|
||||
// 类型检查
|
||||
if (typeof message !== 'object') {
|
||||
throw new Error('Invalid message type');
|
||||
}
|
||||
|
||||
// 必填字段
|
||||
if (!message.type) {
|
||||
throw new Error('Missing message type');
|
||||
}
|
||||
|
||||
// 大小限制
|
||||
const size = JSON.stringify(message).length;
|
||||
if (size > 1024 * 1024) { // 1MB
|
||||
throw new Error('Message too large');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### XSS 防护
|
||||
|
||||
```javascript
|
||||
// 避免直接插入 HTML
|
||||
function escapeHtml(text) {
|
||||
const map = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
return text.replace(/[&<>"']/g, m => map[m]);
|
||||
}
|
||||
|
||||
// 使用 textContent 而非 innerHTML
|
||||
element.textContent = userInput; // 安全
|
||||
// element.innerHTML = userInput; // 危险!
|
||||
```
|
||||
|
||||
### CSP (Content Security Policy)
|
||||
|
||||
```javascript
|
||||
// manifest.json
|
||||
{
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self'; object-src 'none'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### Chrome Extension 调试
|
||||
|
||||
1. **Background Service Worker**
|
||||
- 打开 `chrome://extensions/`
|
||||
- 点击 "Service Worker" 链接
|
||||
- 使用 Chrome DevTools
|
||||
|
||||
2. **Content Script**
|
||||
- 在网页中打开 DevTools
|
||||
- 在 Console 中查看日志
|
||||
|
||||
3. **Popup**
|
||||
- 右键点击插件图标
|
||||
- 选择 "检查弹出内容"
|
||||
|
||||
### Native Host 调试
|
||||
|
||||
```javascript
|
||||
// 日志文件
|
||||
const logFile = path.join(os.tmpdir(), 'qwen-bridge-host.log');
|
||||
|
||||
function log(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
fs.appendFileSync(logFile, `[${timestamp}] ${message}\n`);
|
||||
}
|
||||
|
||||
// 使用日志调试
|
||||
log(`Received message: ${JSON.stringify(message)}`);
|
||||
```
|
||||
|
||||
### 常见问题排查
|
||||
|
||||
| 问题 | 可能原因 | 解决方法 |
|
||||
|------|---------|---------|
|
||||
| Native Host 不响应 | 路径配置错误 | 检查 manifest.json 中的路径 |
|
||||
| 消息解析失败 | JSON 格式错误 | 验证消息格式 |
|
||||
| 权限错误 | 权限不足 | 检查 manifest 权限配置 |
|
||||
| 进程启动失败 | Qwen CLI 未安装 | 安装 Qwen CLI |
|
||||
| 内存溢出 | 数据量过大 | 添加大小限制 |
|
||||
|
||||
## 跨平台兼容性
|
||||
|
||||
### 平台差异处理
|
||||
|
||||
```javascript
|
||||
// 检测操作系统
|
||||
const platform = process.platform;
|
||||
|
||||
// 平台特定路径
|
||||
const paths = {
|
||||
darwin: { // macOS
|
||||
manifest: '~/Library/Application Support/Google/Chrome/NativeMessagingHosts/',
|
||||
log: '/tmp/'
|
||||
},
|
||||
win32: { // Windows
|
||||
manifest: 'HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\',
|
||||
log: process.env.TEMP
|
||||
},
|
||||
linux: {
|
||||
manifest: '~/.config/google-chrome/NativeMessagingHosts/',
|
||||
log: '/tmp/'
|
||||
}
|
||||
};
|
||||
|
||||
// 使用平台特定配置
|
||||
const config = paths[platform];
|
||||
```
|
||||
|
||||
### Shell 命令兼容性
|
||||
|
||||
```javascript
|
||||
// Windows 使用 .bat 文件
|
||||
if (platform === 'win32') {
|
||||
// host.bat 包装器
|
||||
spawn('cmd.exe', ['/c', 'host.bat']);
|
||||
} else {
|
||||
// 直接执行
|
||||
spawn('node', ['host.js']);
|
||||
}
|
||||
```
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 数据提取性能
|
||||
|
||||
| 操作 | 平均耗时 | 内存占用 |
|
||||
|------|---------|----------|
|
||||
| DOM 提取 | ~50ms | ~2MB |
|
||||
| Markdown 转换 | ~30ms | ~1MB |
|
||||
| 截图捕获 | ~100ms | ~5MB |
|
||||
| Console 日志 | <1ms | ~100KB |
|
||||
|
||||
### 通信延迟
|
||||
|
||||
| 通道 | 延迟 |
|
||||
|------|------|
|
||||
| Content ↔ Background | <1ms |
|
||||
| Extension ↔ Native Host | ~5ms |
|
||||
| Native Host ↔ Qwen CLI | ~10ms |
|
||||
| 端到端 | ~20ms |
|
||||
|
||||
## 未来技术方向
|
||||
|
||||
### WebSocket 支持
|
||||
|
||||
```javascript
|
||||
// 升级为 WebSocket 连接
|
||||
class WebSocketBridge {
|
||||
constructor(url) {
|
||||
this.ws = new WebSocket(url);
|
||||
this.setupEventHandlers();
|
||||
}
|
||||
|
||||
send(message) {
|
||||
this.ws.send(JSON.stringify(message));
|
||||
}
|
||||
|
||||
onMessage(callback) {
|
||||
this.ws.on('message', (data) => {
|
||||
callback(JSON.parse(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Service Worker 后台任务
|
||||
|
||||
```javascript
|
||||
// 使用 Alarm API 定期任务
|
||||
chrome.alarms.create('sync', { periodInMinutes: 5 });
|
||||
|
||||
chrome.alarms.onAlarm.addListener((alarm) => {
|
||||
if (alarm.name === 'sync') {
|
||||
syncData();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Web Workers 并行处理
|
||||
|
||||
```javascript
|
||||
// 在 Web Worker 中处理大量数据
|
||||
const worker = new Worker('processor.js');
|
||||
|
||||
worker.postMessage({ cmd: 'process', data: largeData });
|
||||
|
||||
worker.onmessage = (e) => {
|
||||
const result = e.data;
|
||||
// 处理结果
|
||||
};
|
||||
```
|
||||
Reference in New Issue
Block a user