feat(chrome-qwen-bridge): 🔥 init chrome qwen code bridge

This commit is contained in:
yiliang114
2025-12-20 00:58:41 +08:00
parent a92be72e88
commit a60c5c6697
57 changed files with 9489 additions and 0 deletions

View File

@@ -0,0 +1,480 @@
/**
* Side Panel Script for Qwen CLI Bridge
* Handles UI interactions and communication with background script
*/
// UI Elements
const statusIndicator = document.getElementById('statusIndicator');
const statusText = statusIndicator.querySelector('.status-text');
const connectBtn = document.getElementById('connectBtn');
const startQwenBtn = document.getElementById('startQwenBtn');
const connectionError = document.getElementById('connectionError');
const responseSection = document.getElementById('responseSection');
const responseType = document.getElementById('responseType');
const responseContent = document.getElementById('responseContent');
const copyResponseBtn = document.getElementById('copyResponseBtn');
// Action buttons
const extractDataBtn = document.getElementById('extractDataBtn');
const captureScreenBtn = document.getElementById('captureScreenBtn');
const analyzePageBtn = document.getElementById('analyzePageBtn');
const getSelectedBtn = document.getElementById('getSelectedBtn');
const networkLogsBtn = document.getElementById('networkLogsBtn');
const consoleLogsBtn = document.getElementById('consoleLogsBtn');
// Settings
const mcpServersInput = document.getElementById('mcpServers');
const httpPortInput = document.getElementById('httpPort');
const autoConnectCheckbox = document.getElementById('autoConnect');
const saveSettingsBtn = document.getElementById('saveSettingsBtn');
// Footer links
const openOptionsBtn = document.getElementById('openOptionsBtn');
const helpBtn = document.getElementById('helpBtn');
// State
let isConnected = false;
let qwenStatus = 'disconnected';
// Initialize side panel
document.addEventListener('DOMContentLoaded', async () => {
await loadSettings();
await checkConnectionStatus();
// Auto-connect if enabled
const settings = await chrome.storage.local.get(['autoConnect']);
if (settings.autoConnect && !isConnected) {
connectToQwen();
}
});
// Load saved settings
async function loadSettings() {
const settings = await chrome.storage.local.get([
'mcpServers',
'httpPort',
'autoConnect'
]);
if (settings.mcpServers) {
mcpServersInput.value = settings.mcpServers;
}
if (settings.httpPort) {
httpPortInput.value = settings.httpPort;
}
if (settings.autoConnect !== undefined) {
autoConnectCheckbox.checked = settings.autoConnect;
}
}
// Save settings
saveSettingsBtn.addEventListener('click', async () => {
await chrome.storage.local.set({
mcpServers: mcpServersInput.value,
httpPort: parseInt(httpPortInput.value) || 8080,
autoConnect: autoConnectCheckbox.checked
});
saveSettingsBtn.textContent = 'Saved!';
setTimeout(() => {
saveSettingsBtn.textContent = 'Save Settings';
}, 2000);
});
// Check connection status
async function checkConnectionStatus() {
try {
const response = await chrome.runtime.sendMessage({ type: 'GET_STATUS' });
updateConnectionStatus(response.connected, response.status);
} catch (error) {
updateConnectionStatus(false, 'disconnected');
}
}
// Update UI based on connection status
function updateConnectionStatus(connected, status) {
isConnected = connected;
qwenStatus = status;
// Update status indicator
statusIndicator.classList.toggle('connected', connected);
statusIndicator.classList.toggle('connecting', status === 'connecting');
statusText.textContent = getStatusText(status);
// Update button states
connectBtn.textContent = connected ? 'Disconnect' : 'Connect to Qwen CLI';
connectBtn.classList.toggle('btn-danger', connected);
startQwenBtn.disabled = !connected || status === 'running';
// Enable/disable action buttons
const actionButtons = [
extractDataBtn,
captureScreenBtn,
analyzePageBtn,
getSelectedBtn,
networkLogsBtn,
consoleLogsBtn
];
actionButtons.forEach(btn => {
btn.disabled = !connected || status !== 'running';
});
}
// Get human-readable status text
function getStatusText(status) {
switch (status) {
case 'connected':
return 'Connected';
case 'running':
return 'Qwen CLI Running';
case 'connecting':
return 'Connecting...';
case 'disconnected':
return 'Disconnected';
case 'stopped':
return 'Qwen CLI Stopped';
default:
return 'Unknown';
}
}
// Connect button handler
connectBtn.addEventListener('click', () => {
if (isConnected) {
disconnectFromQwen();
} else {
connectToQwen();
}
});
// Connect to Qwen CLI
async function connectToQwen() {
updateConnectionStatus(false, 'connecting');
connectionError.style.display = 'none';
try {
const response = await chrome.runtime.sendMessage({ type: 'CONNECT' });
if (response.success) {
updateConnectionStatus(true, response.status);
} else {
throw new Error(response.error || 'Connection failed');
}
} catch (error) {
console.error('Connection error:', error);
connectionError.textContent = `Error: ${error.message}`;
connectionError.style.display = 'block';
updateConnectionStatus(false, 'disconnected');
}
}
// Disconnect from Qwen CLI
async function disconnectFromQwen() {
try {
await chrome.runtime.sendMessage({ type: 'DISCONNECT' });
} catch (error) {
console.error('Disconnect error:', error);
}
updateConnectionStatus(false, 'disconnected');
}
// Start Qwen CLI button handler
startQwenBtn.addEventListener('click', async () => {
startQwenBtn.disabled = true;
startQwenBtn.textContent = 'Starting...';
try {
const settings = await chrome.storage.local.get(['mcpServers', 'httpPort']);
const response = await chrome.runtime.sendMessage({
type: 'START_QWEN_CLI',
config: {
mcpServers: settings.mcpServers ? settings.mcpServers.split(',').map(s => s.trim()) : [],
httpPort: settings.httpPort || 8080
}
});
if (response.success) {
updateConnectionStatus(true, 'running');
showResponse('Qwen CLI Started', response.data || 'Successfully started');
} else {
throw new Error(response.error || 'Failed to start Qwen CLI');
}
} catch (error) {
console.error('Start error:', error);
connectionError.textContent = `Error: ${error.message}`;
connectionError.style.display = 'block';
} finally {
startQwenBtn.textContent = 'Start Qwen CLI';
}
});
// Extract page data button handler
extractDataBtn.addEventListener('click', async () => {
try {
showLoading('Extracting page data...');
const response = await chrome.runtime.sendMessage({
type: 'EXTRACT_PAGE_DATA'
});
if (response.success) {
// Send to Qwen CLI
const qwenResponse = await chrome.runtime.sendMessage({
type: 'SEND_TO_QWEN',
action: 'analyze_page',
data: response.data
});
if (qwenResponse.success) {
showResponse('Page Analysis', qwenResponse.data);
} else {
throw new Error(qwenResponse.error);
}
} else {
throw new Error(response.error);
}
} catch (error) {
showError(`Failed to extract data: ${error.message}`);
}
});
// Capture screenshot button handler
captureScreenBtn.addEventListener('click', async () => {
try {
showLoading('Capturing screenshot...');
const response = await chrome.runtime.sendMessage({
type: 'CAPTURE_SCREENSHOT'
});
if (response.success) {
// Send to Qwen CLI
const qwenResponse = await chrome.runtime.sendMessage({
type: 'SEND_TO_QWEN',
action: 'analyze_screenshot',
data: {
screenshot: response.data,
url: (await chrome.tabs.query({ active: true, currentWindow: true }))[0].url
}
});
if (qwenResponse.success) {
showResponse('Screenshot Analysis', qwenResponse.data);
} else {
throw new Error(qwenResponse.error);
}
} else {
throw new Error(response.error);
}
} catch (error) {
showError(`Failed to capture screenshot: ${error.message}`);
}
});
// Analyze page with AI button handler
analyzePageBtn.addEventListener('click', async () => {
try {
showLoading('Analyzing page with AI...');
// First extract page data
const extractResponse = await chrome.runtime.sendMessage({
type: 'EXTRACT_PAGE_DATA'
});
if (!extractResponse.success) {
throw new Error(extractResponse.error);
}
// Send to Qwen for AI analysis
const qwenResponse = await chrome.runtime.sendMessage({
type: 'SEND_TO_QWEN',
action: 'ai_analyze',
data: {
pageData: extractResponse.data,
prompt: 'Please analyze this webpage and provide insights about its content, purpose, and any notable features.'
}
});
if (qwenResponse.success) {
showResponse('AI Analysis', qwenResponse.data);
} else {
throw new Error(qwenResponse.error);
}
} catch (error) {
showError(`Analysis failed: ${error.message}`);
}
});
// Get selected text button handler
getSelectedBtn.addEventListener('click', async () => {
try {
showLoading('Getting selected text...');
// Get active tab
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];
if (!tab) {
throw new Error('No active tab found');
}
// Get selected text from content script
const response = await chrome.tabs.sendMessage(tab.id, {
type: 'GET_SELECTED_TEXT'
});
if (response.success && response.data) {
// Send to Qwen CLI
const qwenResponse = await chrome.runtime.sendMessage({
type: 'SEND_TO_QWEN',
action: 'process_text',
data: {
text: response.data,
context: 'selected_text'
}
});
if (qwenResponse.success) {
showResponse('Selected Text Processed', qwenResponse.data);
} else {
throw new Error(qwenResponse.error);
}
} else {
showError('No text selected. Please select some text on the page first.');
}
} catch (error) {
showError(`Failed to process selected text: ${error.message}`);
}
});
// Network logs button handler
networkLogsBtn.addEventListener('click', async () => {
try {
showLoading('Getting network logs...');
const response = await chrome.runtime.sendMessage({
type: 'GET_NETWORK_LOGS'
});
if (response.success) {
showResponse('Network Logs', JSON.stringify(response.data, null, 2));
} else {
throw new Error(response.error);
}
} catch (error) {
showError(`Failed to get network logs: ${error.message}`);
}
});
// Console logs button handler
consoleLogsBtn.addEventListener('click', async () => {
try {
showLoading('Getting console logs...');
// Get active tab
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];
if (!tab) {
throw new Error('No active tab found');
}
// Get console logs from content script
const response = await chrome.tabs.sendMessage(tab.id, {
type: 'EXTRACT_DATA'
});
if (response.success) {
const consoleLogs = response.data.consoleLogs || [];
if (consoleLogs.length > 0) {
showResponse('Console Logs', JSON.stringify(consoleLogs, null, 2));
} else {
showResponse('Console Logs', 'No console logs captured');
}
} else {
throw new Error(response.error);
}
} catch (error) {
showError(`Failed to get console logs: ${error.message}`);
}
});
// Copy response button handler
copyResponseBtn.addEventListener('click', () => {
const text = responseContent.textContent;
navigator.clipboard.writeText(text).then(() => {
const originalTitle = copyResponseBtn.title;
copyResponseBtn.title = 'Copied!';
setTimeout(() => {
copyResponseBtn.title = originalTitle;
}, 2000);
});
});
// Footer link handlers
openOptionsBtn.addEventListener('click', (e) => {
e.preventDefault();
// Use try-catch to handle potential errors
try {
chrome.runtime.openOptionsPage(() => {
if (chrome.runtime.lastError) {
// If opening options page fails, open it in a new tab as fallback
console.error('Error opening options page:', chrome.runtime.lastError);
chrome.tabs.create({
url: chrome.runtime.getURL('options/options.html')
});
}
});
} catch (error) {
console.error('Failed to open options page:', error);
// Fallback: open in new tab
chrome.tabs.create({
url: chrome.runtime.getURL('options/options.html')
});
}
});
helpBtn.addEventListener('click', (e) => {
e.preventDefault();
chrome.tabs.create({
url: 'https://github.com/QwenLM/qwen-code/tree/main/packages/chrome-qwen-bridge'
});
});
// Helper functions
function showLoading(message) {
responseSection.style.display = 'block';
responseType.textContent = 'Loading';
responseContent.textContent = message;
responseSection.classList.add('loading');
}
function showResponse(type, content) {
responseSection.style.display = 'block';
responseType.textContent = type;
responseType.style.color = '#666';
responseContent.textContent = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
responseSection.classList.remove('loading');
responseSection.classList.add('fade-in');
}
function showError(message) {
responseSection.style.display = 'block';
responseType.textContent = 'Error';
responseType.style.color = '#c00';
responseContent.textContent = message;
responseSection.classList.remove('loading');
}
// Listen for status updates from background
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'STATUS_UPDATE') {
updateConnectionStatus(message.status !== 'disconnected', message.status);
} else if (message.type === 'QWEN_EVENT') {
// Handle events from Qwen CLI
console.log('Qwen event received:', message.event);
// Could update UI based on event
}
});