mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-22 09:47:47 +00:00
306 lines
10 KiB
Bash
Executable File
306 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Qwen CLI Bridge - 智能 Native Host 安装器
|
||
# 自动检测 Chrome 插件并配置 Native Host
|
||
|
||
set -e
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||
HOST_NAME="com.qwen.cli.bridge"
|
||
|
||
echo -e "${CYAN}╔════════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${CYAN}║ ║${NC}"
|
||
echo -e "${CYAN}║ 🔧 Qwen CLI Bridge - Native Host 安装器 ║${NC}"
|
||
echo -e "${CYAN}║ ║${NC}"
|
||
echo -e "${CYAN}╚════════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
|
||
# 检测操作系统
|
||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||
OS="macOS"
|
||
MANIFEST_DIR="$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
||
EXTENSIONS_DIR="$HOME/Library/Application Support/Google/Chrome/Default/Extensions"
|
||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||
OS="Linux"
|
||
MANIFEST_DIR="$HOME/.config/google-chrome/NativeMessagingHosts"
|
||
EXTENSIONS_DIR="$HOME/.config/google-chrome/Default/Extensions"
|
||
else
|
||
echo -e "${RED}✗ 不支持的操作系统${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo -e "${BLUE}检测到系统:${NC} $OS"
|
||
echo ""
|
||
|
||
# 检查 Node.js
|
||
echo -e "${BLUE}检查依赖...${NC}"
|
||
if ! command -v node &> /dev/null; then
|
||
echo -e "${RED}✗ Node.js 未安装${NC}"
|
||
echo -e " 请访问 https://nodejs.org 安装 Node.js"
|
||
exit 1
|
||
fi
|
||
echo -e "${GREEN}✓${NC} Node.js $(node --version)"
|
||
|
||
# 尝试自动检测扩展 ID
|
||
echo -e "\n${BLUE}查找已安装的 Qwen CLI Bridge 扩展...${NC}"
|
||
|
||
EXTENSION_ID=""
|
||
AUTO_DETECTED=false
|
||
|
||
# 方法1: 从 Chrome 扩展目录查找
|
||
if [[ -d "$EXTENSIONS_DIR" ]]; then
|
||
for ext_id in "$EXTENSIONS_DIR"/*; do
|
||
if [[ -d "$ext_id" ]]; then
|
||
ext_id_name=$(basename "$ext_id")
|
||
# 检查最新版本目录
|
||
for version_dir in "$ext_id"/*; do
|
||
if [[ -f "$version_dir/manifest.json" ]]; then
|
||
# 检查是否是我们的扩展
|
||
if grep -q "Qwen CLI Bridge" "$version_dir/manifest.json" 2>/dev/null; then
|
||
EXTENSION_ID="$ext_id_name"
|
||
AUTO_DETECTED=true
|
||
echo -e "${GREEN}✓${NC} 自动检测到扩展 ID: ${CYAN}$EXTENSION_ID${NC}"
|
||
break 2
|
||
fi
|
||
fi
|
||
done
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# 方法2: 检查之前保存的 ID
|
||
if [[ -z "$EXTENSION_ID" && -f "$SCRIPT_DIR/../.extension-id" ]]; then
|
||
EXTENSION_ID=$(cat "$SCRIPT_DIR/../.extension-id")
|
||
echo -e "${GREEN}✓${NC} 使用保存的扩展 ID: ${CYAN}$EXTENSION_ID${NC}"
|
||
AUTO_DETECTED=true
|
||
fi
|
||
|
||
# 如果自动检测失败,提供选项
|
||
if [[ -z "$EXTENSION_ID" ]]; then
|
||
echo -e "${YELLOW}⚠️ 未能自动检测到扩展${NC}"
|
||
echo ""
|
||
echo -e "请选择:"
|
||
echo -e " ${CYAN}1)${NC} 我已经安装了扩展(输入扩展 ID)"
|
||
echo -e " ${CYAN}2)${NC} 我还没有安装扩展(通用配置)"
|
||
echo -e " ${CYAN}3)${NC} 打开 Chrome 扩展页面查看"
|
||
echo ""
|
||
read -p "选择 (1/2/3): " CHOICE
|
||
|
||
case $CHOICE in
|
||
1)
|
||
echo ""
|
||
echo -e "${YELLOW}请输入扩展 ID:${NC}"
|
||
echo -e "${CYAN}提示: 在 chrome://extensions 页面找到 Qwen CLI Bridge,ID 在扩展卡片上${NC}"
|
||
read -p "> " EXTENSION_ID
|
||
if [[ -n "$EXTENSION_ID" ]]; then
|
||
# 保存 ID 供以后使用
|
||
echo "$EXTENSION_ID" > "$SCRIPT_DIR/../.extension-id"
|
||
echo -e "${GREEN}✓${NC} 扩展 ID 已保存"
|
||
fi
|
||
;;
|
||
2)
|
||
echo -e "\n${CYAN}将使用通用配置(允许所有开发扩展)${NC}"
|
||
EXTENSION_ID="*"
|
||
;;
|
||
3)
|
||
echo -e "\n${CYAN}正在打开 Chrome 扩展页面...${NC}"
|
||
open "chrome://extensions" 2>/dev/null || xdg-open "chrome://extensions" 2>/dev/null || echo "请手动打开 chrome://extensions"
|
||
echo ""
|
||
echo -e "${YELLOW}找到 Qwen CLI Bridge 扩展后,输入其 ID:${NC}"
|
||
read -p "> " EXTENSION_ID
|
||
if [[ -n "$EXTENSION_ID" && "$EXTENSION_ID" != "*" ]]; then
|
||
echo "$EXTENSION_ID" > "$SCRIPT_DIR/../.extension-id"
|
||
fi
|
||
;;
|
||
*)
|
||
echo -e "${RED}无效的选择${NC}"
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
# 创建 Native Host 目录
|
||
echo -e "\n${BLUE}配置 Native Host...${NC}"
|
||
mkdir -p "$MANIFEST_DIR"
|
||
|
||
# 创建 manifest 文件
|
||
MANIFEST_FILE="$MANIFEST_DIR/$HOST_NAME.json"
|
||
|
||
if [[ "$EXTENSION_ID" == "*" ]]; then
|
||
# 通用配置
|
||
cat > "$MANIFEST_FILE" << EOF
|
||
{
|
||
"name": "$HOST_NAME",
|
||
"description": "Native messaging host for Qwen CLI Bridge",
|
||
"path": "$SCRIPT_DIR/host.js",
|
||
"type": "stdio",
|
||
"allowed_origins": [
|
||
"chrome-extension://*/"
|
||
]
|
||
}
|
||
EOF
|
||
echo -e "${GREEN}✓${NC} Native Host 已配置(通用模式)"
|
||
else
|
||
# 特定扩展 ID 配置
|
||
cat > "$MANIFEST_FILE" << EOF
|
||
{
|
||
"name": "$HOST_NAME",
|
||
"description": "Native messaging host for Qwen CLI Bridge",
|
||
"path": "$SCRIPT_DIR/host.js",
|
||
"type": "stdio",
|
||
"allowed_origins": [
|
||
"chrome-extension://$EXTENSION_ID/",
|
||
"chrome-extension://*/"
|
||
]
|
||
}
|
||
EOF
|
||
echo -e "${GREEN}✓${NC} Native Host 已配置(扩展 ID: $EXTENSION_ID)"
|
||
fi
|
||
|
||
# 验证配置
|
||
echo -e "\n${BLUE}验证配置...${NC}"
|
||
|
||
# 检查 host.js 是否存在
|
||
if [[ ! -f "$SCRIPT_DIR/host.js" ]]; then
|
||
echo -e "${RED}✗ host.js 文件不存在${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
# 确保 host.js 可执行
|
||
chmod +x "$SCRIPT_DIR/host.js"
|
||
echo -e "${GREEN}✓${NC} host.js 已设置为可执行"
|
||
|
||
# 检查 manifest 文件
|
||
if [[ -f "$MANIFEST_FILE" ]]; then
|
||
echo -e "${GREEN}✓${NC} Manifest 文件已创建: $MANIFEST_FILE"
|
||
else
|
||
echo -e "${RED}✗ Manifest 文件创建失败${NC}"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo -e "${GREEN}╔════════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${GREEN}║ ║${NC}"
|
||
echo -e "${GREEN}║ ✅ Native Host 安装成功! ║${NC}"
|
||
echo -e "${GREEN}║ ║${NC}"
|
||
echo -e "${GREEN}╚════════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
|
||
# 显示下一步
|
||
if [[ "$AUTO_DETECTED" == true ]]; then
|
||
echo -e "${CYAN}检测到扩展已安装,你可以直接使用了!${NC}"
|
||
echo ""
|
||
echo -e "使用方法:"
|
||
echo -e " 1. 点击 Chrome 工具栏的扩展图标"
|
||
echo -e " 2. 点击 'Connect to Qwen CLI'"
|
||
echo -e " 3. 开始使用各项功能"
|
||
else
|
||
echo -e "${YELLOW}下一步:${NC}"
|
||
echo -e " 1. 在 Chrome 中打开 ${CYAN}chrome://extensions/${NC}"
|
||
echo -e " 2. 开启${CYAN}「开发者模式」${NC}(右上角)"
|
||
echo -e " 3. 点击${CYAN}「加载已解压的扩展程序」${NC}"
|
||
echo -e " 4. 选择目录: ${CYAN}$SCRIPT_DIR/../extension${NC}"
|
||
echo -e " 5. 安装完成后,重新运行此脚本以更新配置"
|
||
fi
|
||
|
||
echo ""
|
||
echo -e "${CYAN}提示:${NC}"
|
||
echo -e " • 如需重新配置,随时可以重新运行此脚本"
|
||
echo -e " • 日志文件位置: /tmp/qwen-bridge-host.log"
|
||
echo -e " • 如遇问题,请查看: $SCRIPT_DIR/../docs/debugging.md"
|
||
echo ""
|
||
|
||
# 询问是否测试连接
|
||
if [[ "$AUTO_DETECTED" == true ]]; then
|
||
echo -e "${CYAN}是否测试 Native Host 连接?(y/n)${NC}"
|
||
read -p "> " TEST_CONNECTION
|
||
|
||
if [[ "$TEST_CONNECTION" == "y" ]] || [[ "$TEST_CONNECTION" == "Y" ]]; then
|
||
echo -e "\n${BLUE}测试连接...${NC}"
|
||
|
||
# 创建测试脚本
|
||
cat > /tmp/test-native-host.js << 'EOF'
|
||
const chrome = {
|
||
runtime: {
|
||
connectNative: () => {
|
||
console.log("Chrome API not available in Node.js environment");
|
||
console.log("请在 Chrome 扩展中测试连接");
|
||
}
|
||
}
|
||
};
|
||
|
||
// 直接测试 host.js
|
||
const { spawn } = require('child_process');
|
||
const path = require('path');
|
||
|
||
const hostPath = process.argv[2];
|
||
if (!hostPath) {
|
||
console.error("Missing host path");
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log("Testing host at:", hostPath);
|
||
|
||
const host = spawn('node', [hostPath], {
|
||
stdio: ['pipe', 'pipe', 'pipe']
|
||
});
|
||
|
||
// 发送测试消息
|
||
const testMessage = JSON.stringify({ type: 'handshake', version: '1.0.0' });
|
||
const length = Buffer.allocUnsafe(4);
|
||
length.writeUInt32LE(Buffer.byteLength(testMessage), 0);
|
||
|
||
host.stdin.write(length);
|
||
host.stdin.write(testMessage);
|
||
|
||
// 读取响应
|
||
let responseBuffer = Buffer.alloc(0);
|
||
let messageLength = null;
|
||
|
||
host.stdout.on('data', (data) => {
|
||
responseBuffer = Buffer.concat([responseBuffer, data]);
|
||
|
||
if (messageLength === null && responseBuffer.length >= 4) {
|
||
messageLength = responseBuffer.readUInt32LE(0);
|
||
responseBuffer = responseBuffer.slice(4);
|
||
}
|
||
|
||
if (messageLength !== null && responseBuffer.length >= messageLength) {
|
||
const message = JSON.parse(responseBuffer.slice(0, messageLength).toString());
|
||
console.log("Response received:", message);
|
||
|
||
if (message.type === 'handshake_response') {
|
||
console.log("✅ Native Host 响应正常");
|
||
}
|
||
|
||
host.kill();
|
||
process.exit(0);
|
||
}
|
||
});
|
||
|
||
host.on('error', (error) => {
|
||
console.error("❌ Host error:", error.message);
|
||
process.exit(1);
|
||
});
|
||
|
||
setTimeout(() => {
|
||
console.error("❌ 测试超时");
|
||
host.kill();
|
||
process.exit(1);
|
||
}, 5000);
|
||
EOF
|
||
|
||
node /tmp/test-native-host.js "$SCRIPT_DIR/host.js"
|
||
rm /tmp/test-native-host.js
|
||
fi
|
||
fi
|
||
|
||
echo -e "${GREEN}安装完成!${NC}" |