5 Commits

Author SHA1 Message Date
1a91513031 Merge branch 'feat/codeToChat' into feat/Knowledge-Base 2026-03-20 15:19:32 +08:00
69f86dbc0d fix:修复启用/禁用个人规则失效的bug 2026-03-20 15:19:24 +08:00
24512c61e6 style:解决不同主题下颜色变化的bug
- AI询问用户组件
2026-03-20 14:05:08 +08:00
1207d2b91a feat:实现携带路径发送信息的优化
- 将路径通过doc包裹起来便于后端读取
2026-03-20 11:45:01 +08:00
cc4583e2cc style:修改代码高亮的margin 2026-03-19 16:18:01 +08:00
12 changed files with 212 additions and 78 deletions

View File

@ -34,7 +34,7 @@ export function getCodeHighlightStyles(): string {
border-radius: 6px; border-radius: 6px;
padding: 12px; padding: 12px;
overflow-x: auto; overflow-x: auto;
margin: 12px 0; margin: 52px 0 12px 0;
position: relative; position: relative;
white-space: pre; white-space: pre;
} }

View File

@ -8,7 +8,7 @@ import * as vscode from "vscode";
type Environment = "dev" | "test" | "prod"; type Environment = "dev" | "test" | "prod";
/** 当前环境 - 修改这里切换环境 */ /** 当前环境 - 修改这里切换环境 */
const CURRENT_ENV: Environment = "prod"; const CURRENT_ENV: Environment = "test";
/** 服务等级类型 */ /** 服务等级类型 */
export type ServiceTier = "lite" | "syntaxic" | "max" | "auto"; export type ServiceTier = "lite" | "syntaxic" | "max" | "auto";
@ -42,9 +42,9 @@ const ENV_CONFIG: Record<Environment, IccoderConfig> = {
}, },
/** 测试服务器环境 - 通过 Gateway 路由 */ /** 测试服务器环境 - 通过 Gateway 路由 */
test: { test: {
backendUrl: "http://192.168.1.108:2029/iccoder", backendUrl: "http://192.168.1.134:2233",
backendUrlStrongeLoop: "http://192.168.1.108:2029", backendUrlStrongeLoop: "http://192.168.1.134:2233",
loginUrl: "http://192.168.1.108:2005/login", loginUrl: "http://192.168.1.134/login",
timeout: 60000, timeout: 60000,
userId: "default-user", userId: "default-user",
serviceTier: "max", serviceTier: "max",

View File

@ -7,6 +7,20 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
let globalContext: vscode.ExtensionContext; let globalContext: vscode.ExtensionContext;
const DOCUMENT_SETS_KEY = "iccoder.documentSets";
export interface DocumentFile {
name: string;
absolutePath: string;
size: number;
}
export interface DocumentSet {
id: string;
name: string;
files: DocumentFile[];
updatedAt: number;
}
export function initializeContextHelper(context: vscode.ExtensionContext) { export function initializeContextHelper(context: vscode.ExtensionContext) {
globalContext = context; globalContext = context;
@ -138,26 +152,26 @@ export async function handleGetDocumentSetList(panel: vscode.WebviewPanel) {
}); });
} }
let documentSet: Array<{ path: string; relativePath: string }> = []; let documentSet: DocumentFile[] = [];
export function getDocumentSet() { export function getDocumentSet() {
return documentSet; return documentSet;
} }
export function addToDocumentSet(docs: Array<{ path: string; relativePath: string }>) { export function addToDocumentSet(docs: DocumentFile[]) {
documentSet = [...documentSet, ...docs]; documentSet = [...documentSet, ...docs];
} }
export function saveDocumentSet( export function saveDocumentSet(
docs: Array<{ path: string; relativePath: string }>, docs: DocumentFile[],
name: string, name: string,
panel: vscode.WebviewPanel panel: vscode.WebviewPanel
) { ) {
const newDocSet = { const newDocSet: DocumentSet = {
id: Date.now().toString(), id: Date.now().toString(),
name, name,
documents: docs, files: docs,
updatedAt: new Date().toISOString(), updatedAt: Date.now(),
}; };
documentSets.push(newDocSet); documentSets.push(newDocSet);
persistDocumentSets(); persistDocumentSets();
@ -167,22 +181,44 @@ export function saveDocumentSet(
}); });
} }
let documentSets: Array<{ let documentSets: DocumentSet[] = [];
id: string;
name: string;
documents: Array<{ path: string; relativePath: string }>;
updatedAt: string;
}> = [];
function loadDocumentSets() { function loadDocumentSets() {
const saved = globalContext.globalState.get<typeof documentSets>("documentSets"); const saved =
globalContext.globalState.get<Array<any>>(DOCUMENT_SETS_KEY) ||
globalContext.globalState.get<Array<any>>("documentSets", []);
if (saved) { if (saved) {
documentSets = saved; documentSets = saved.map((item: any) => ({
id: String(item.id),
name: String(item.name || ""),
files: Array.isArray(item.files)
? item.files.map((file: any) => ({
name: String(file.name || ""),
absolutePath: String(file.absolutePath || file.path || ""),
size: Number(file.size || 0),
}))
: Array.isArray(item.documents)
? item.documents.map((file: any) => ({
name: String(
file.name ||
file.relativePath?.split(/[\\/]/).pop() ||
file.path?.split(/[\\/]/).pop() ||
"",
),
absolutePath: String(file.absolutePath || file.path || ""),
size: Number(file.size || 0),
}))
: [],
updatedAt:
typeof item.updatedAt === "number"
? item.updatedAt
: new Date(item.updatedAt || Date.now()).getTime(),
}));
} }
} }
function persistDocumentSets() { function persistDocumentSets() {
globalContext.globalState.update("documentSets", documentSets); globalContext.globalState.update(DOCUMENT_SETS_KEY, documentSets);
} }
export function getDocumentSets() { export function getDocumentSets() {
@ -202,7 +238,7 @@ export function changeDocumentSetName(id: string, newName: string, panel: vscode
const docSet = documentSets.find(ds => ds.id === id); const docSet = documentSets.find(ds => ds.id === id);
if (docSet) { if (docSet) {
docSet.name = newName; docSet.name = newName;
docSet.updatedAt = new Date().toISOString(); docSet.updatedAt = Date.now();
persistDocumentSets(); persistDocumentSets();
panel.webview.postMessage({ panel.webview.postMessage({
command: "documentSetSaved", command: "documentSetSaved",

View File

@ -27,11 +27,15 @@ import {
savePersonalRule, savePersonalRule,
updatePersonalRule, updatePersonalRule,
deletePersonalRule, deletePersonalRule,
updatePersonalRulesEnabled,
} from "../../utils/personalRulesManager"; } from "../../utils/personalRulesManager";
import { compactDialog } from "../../services/apiClient"; import { compactDialog } from "../../services/apiClient";
import { ChatHistoryManager } from "../../utils/chatHistoryManager"; import { ChatHistoryManager } from "../../utils/chatHistoryManager";
import { getCachedUserInfo } from "../../services/userService"; import { getCachedUserInfo } from "../../services/userService";
import { loadConversationHistory, selectConversation } from "./conversationHelper"; import {
loadConversationHistory,
selectConversation,
} from "./conversationHelper";
import { getVCDFileInfo } from "./vcdHelper"; import { getVCDFileInfo } from "./vcdHelper";
import { import {
handleAddContextFile, handleAddContextFile,
@ -138,16 +142,16 @@ export async function handleWebviewMessage(
break; break;
case "loadConversationHistory": case "loadConversationHistory":
loadConversationHistory( loadConversationHistory(panel, message.offset || 0, message.limit || 10);
panel,
message.offset || 0,
message.limit || 10,
);
break; break;
case "selectConversation": case "selectConversation":
if (message.conversationId) { if (message.conversationId) {
selectConversation(panel, message.conversationId, context.extensionPath); selectConversation(
panel,
message.conversationId,
context.extensionPath,
);
} }
break; break;
@ -261,7 +265,9 @@ export async function handleWebviewMessage(
verified: true, verified: true,
}); });
} else { } else {
const { InvitationService } = require("../../services/invitationService"); const {
InvitationService,
} = require("../../services/invitationService");
const isVerified = await InvitationService.isVerified(context); const isVerified = await InvitationService.isVerified(context);
panel.webview.postMessage({ panel.webview.postMessage({
command: "invitationCodeStatus", command: "invitationCodeStatus",
@ -292,7 +298,9 @@ export async function handleWebviewMessage(
case "checkTrialExpiration": case "checkTrialExpiration":
{ {
const { TrialExpirationService } = require("../../services/trialExpirationService"); const {
TrialExpirationService,
} = require("../../services/trialExpirationService");
const trialService = new TrialExpirationService(context, panel); const trialService = new TrialExpirationService(context, panel);
await trialService.checkExpiration(); await trialService.checkExpiration();
} }
@ -300,7 +308,9 @@ export async function handleWebviewMessage(
case "verifyInvitationCode": case "verifyInvitationCode":
{ {
const { InvitationService } = require("../../services/invitationService"); const {
InvitationService,
} = require("../../services/invitationService");
const result = await InvitationService.verifyCode(message.code); const result = await InvitationService.verifyCode(message.code);
if (result.success) { if (result.success) {
@ -390,7 +400,7 @@ export async function handleWebviewMessage(
case "openContextSettings": case "openContextSettings":
panel.webview.postMessage({ panel.webview.postMessage({
command: "openSettingsTab", command: "openSettingsTab",
tab: "context" tab: "context",
}); });
break; break;
@ -401,14 +411,18 @@ export async function handleWebviewMessage(
canSelectFolders: false, canSelectFolders: false,
openLabel: "选择文件", openLabel: "选择文件",
filters: { filters: {
"支持的文件": ["md", "txt", "v", "sv", "pdf"], : ["md", "txt", "v", "sv", "pdf"],
}, },
}); });
if (uris && uris.length > 0) { if (uris && uris.length > 0) {
const fs = require("fs"); const fs = require("fs");
const path = require("path"); const path = require("path");
const selectedFiles: Array<{ path: string; relativePath: string; size: number }> = []; const selectedFiles: Array<{
name: string;
absolutePath: string;
size: number;
}> = [];
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
const MAX_TOTAL_SIZE = 50 * 1024 * 1024; // 50 MB const MAX_TOTAL_SIZE = 50 * 1024 * 1024; // 50 MB
const MAX_FILES = 1000; const MAX_FILES = 1000;
@ -440,8 +454,8 @@ export async function handleWebviewMessage(
} }
selectedFiles.push({ selectedFiles.push({
path: filePath, name: path.basename(filePath),
relativePath: vscode.workspace.asRelativePath(filePath), absolutePath: filePath,
size: stat.size, size: stat.size,
}); });
totalSize += stat.size; totalSize += stat.size;
@ -553,6 +567,19 @@ export async function handleWebviewMessage(
} }
break; break;
case "updatePersonalRulesEnabled":
{
const success = await updatePersonalRulesEnabled(message.enabled);
if (success) {
const data = loadPersonalRules();
panel.webview.postMessage({
command: "personalRulesLoaded",
data: data,
});
}
}
break;
case "loadDocumentSets": case "loadDocumentSets":
const { getDocumentSets } = await import("./contextHelper"); const { getDocumentSets } = await import("./contextHelper");
panel.webview.postMessage({ panel.webview.postMessage({

View File

@ -162,6 +162,8 @@ export async function startStreamDialog(
const body = JSON.stringify(request); const body = JSON.stringify(request);
console.log(`[SSE] 开始流式对话: taskId=${request.taskId}, mode=${request.mode}, url=${urlString}`); console.log(`[SSE] 开始流式对话: taskId=${request.taskId}, mode=${request.mode}, url=${urlString}`);
console.log("[SSE] 完整请求体:", request);
console.log("[SSE] 请求体 JSON:", body);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const options: http.RequestOptions = { const options: http.RequestOptions = {

View File

@ -268,8 +268,19 @@ async function handleUserMessageWithBackend(
let enhancedText = text; let enhancedText = text;
if (contextItems && contextItems.length > 0) { if (contextItems && contextItems.length > 0) {
console.log("[MessageHandler] 处理上下文项:", contextItems.length); console.log("[MessageHandler] 处理上下文项:", contextItems.length);
const paths = contextItems.map((item) => item.path).join("\n"); const docTypes = new Set(["file", "document", "docset"]);
enhancedText = `${paths}\n\n${text}`; const regularPaths = contextItems
.filter((item) => !docTypes.has(item.type))
.map((item) => item.path);
const docTags = contextItems
.filter((item) => docTypes.has(item.type))
.map((item) => `<doc>${item.path}</doc>`);
if (regularPaths.length > 0) {
enhancedText = `${regularPaths.join("\n")}\n\n${enhancedText}`;
}
if (docTags.length > 0) {
enhancedText = `${enhancedText}\n\n${docTags.join("\n")}`;
}
} }
// 获取 historyManager 中的 taskId由 ICHelperPanel 创建) // 获取 historyManager 中的 taskId由 ICHelperPanel 创建)

View File

@ -5,16 +5,16 @@
* 使用场景:保存和加载用户的个人规则 * 使用场景:保存和加载用户的个人规则
*/ */
import * as vscode from 'vscode'; import * as vscode from "vscode";
import * as fs from 'fs'; import * as fs from "fs";
import * as path from 'path'; import * as path from "path";
import * as os from 'os'; import * as os from "os";
/** /**
* 获取规则目录路径 * 获取规则目录路径
*/ */
function getRulesDir(): string { function getRulesDir(): string {
return path.join(os.homedir(), '.iccoder', 'rules'); return path.join(os.homedir(), ".iccoder", "rules");
} }
/** /**
@ -31,18 +31,22 @@ function ensureRulesDir(): void {
* 从文件内容中提取规则名称 * 从文件内容中提取规则名称
*/ */
function extractRuleName(content: string): string { function extractRuleName(content: string): string {
const lines = content.split('\n'); const lines = content.split("\n");
const firstLine = lines[0]?.trim(); const firstLine = lines[0]?.trim();
if (firstLine && firstLine.startsWith('# ')) { if (firstLine && firstLine.startsWith("# ")) {
return firstLine.substring(2).trim(); return firstLine.substring(2).trim();
} }
return content.substring(0, 30) + (content.length > 30 ? '...' : ''); return content.substring(0, 30) + (content.length > 30 ? "..." : "");
} }
/** /**
* 保存新规则 * 保存新规则
*/ */
export async function savePersonalRule(name: string, content: string, enabled: boolean): Promise<boolean> { export async function savePersonalRule(
name: string,
content: string,
enabled: boolean,
): Promise<boolean> {
try { try {
ensureRulesDir(); ensureRulesDir();
@ -51,11 +55,17 @@ export async function savePersonalRule(name: string, content: string, enabled: b
const filePath = path.join(getRulesDir(), filename); const filePath = path.join(getRulesDir(), filename);
const fileContent = `# ${name}\n\n${content}`; const fileContent = `# ${name}\n\n${content}`;
fs.writeFileSync(filePath, fileContent, 'utf-8'); fs.writeFileSync(filePath, fileContent, "utf-8");
await vscode.workspace.getConfiguration('ic-coder').update('personalRulesEnabled', enabled, vscode.ConfigurationTarget.Global); await vscode.workspace
.getConfiguration("ic-coder")
.update(
"personalRulesEnabled",
enabled,
vscode.ConfigurationTarget.Global,
);
vscode.window.showInformationMessage('规则已保存'); vscode.window.showInformationMessage("规则已保存");
return true; return true;
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`保存规则失败: ${error}`); vscode.window.showErrorMessage(`保存规则失败: ${error}`);
@ -66,15 +76,26 @@ export async function savePersonalRule(name: string, content: string, enabled: b
/** /**
* 更新规则 * 更新规则
*/ */
export async function updatePersonalRule(filename: string, name: string, content: string, enabled: boolean): Promise<boolean> { export async function updatePersonalRule(
filename: string,
name: string,
content: string,
enabled: boolean,
): Promise<boolean> {
try { try {
const filePath = path.join(getRulesDir(), filename); const filePath = path.join(getRulesDir(), filename);
const fileContent = `# ${name}\n\n${content}`; const fileContent = `# ${name}\n\n${content}`;
fs.writeFileSync(filePath, fileContent, 'utf-8'); fs.writeFileSync(filePath, fileContent, "utf-8");
await vscode.workspace.getConfiguration('ic-coder').update('personalRulesEnabled', enabled, vscode.ConfigurationTarget.Global); await vscode.workspace
.getConfiguration("ic-coder")
.update(
"personalRulesEnabled",
enabled,
vscode.ConfigurationTarget.Global,
);
vscode.window.showInformationMessage('规则已更新'); vscode.window.showInformationMessage("规则已更新");
return true; return true;
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`更新规则失败: ${error}`); vscode.window.showErrorMessage(`更新规则失败: ${error}`);
@ -90,7 +111,7 @@ export async function deletePersonalRule(filename: string): Promise<boolean> {
const filePath = path.join(getRulesDir(), filename); const filePath = path.join(getRulesDir(), filename);
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
vscode.window.showInformationMessage('规则已删除'); vscode.window.showInformationMessage("规则已删除");
return true; return true;
} }
return false; return false;
@ -103,8 +124,13 @@ export async function deletePersonalRule(filename: string): Promise<boolean> {
/** /**
* 加载所有规则 * 加载所有规则
*/ */
export function loadPersonalRules(): { rules: Array<{ filename: string; name: string; content: string }>; enabled: boolean } { export function loadPersonalRules(): {
const enabled = vscode.workspace.getConfiguration('ic-coder').get<boolean>('personalRulesEnabled', true); rules: Array<{ filename: string; name: string; content: string }>;
enabled: boolean;
} {
const enabled = vscode.workspace
.getConfiguration("ic-coder")
.get<boolean>("personalRulesEnabled", true);
const dir = getRulesDir(); const dir = getRulesDir();
if (!fs.existsSync(dir)) { if (!fs.existsSync(dir)) {
@ -112,16 +138,16 @@ export function loadPersonalRules(): { rules: Array<{ filename: string; name: st
} }
try { try {
const files = fs.readdirSync(dir).filter(f => f.endsWith('.md')); const files = fs.readdirSync(dir).filter((f) => f.endsWith(".md"));
const rules = files.map(filename => { const rules = files.map((filename) => {
const content = fs.readFileSync(path.join(dir, filename), 'utf-8'); const content = fs.readFileSync(path.join(dir, filename), "utf-8");
const lines = content.split('\n'); const lines = content.split("\n");
let name = ''; let name = "";
let actualContent = content; let actualContent = content;
if (lines[0]?.trim().startsWith('# ')) { if (lines[0]?.trim().startsWith("# ")) {
name = lines[0].substring(2).trim(); name = lines[0].substring(2).trim();
actualContent = lines.slice(2).join('\n').trim(); actualContent = lines.slice(2).join("\n").trim();
} else { } else {
name = extractRuleName(content); name = extractRuleName(content);
} }
@ -130,11 +156,32 @@ export function loadPersonalRules(): { rules: Array<{ filename: string; name: st
}); });
return { rules, enabled }; return { rules, enabled };
} catch (error) { } catch (error) {
console.error('读取规则失败:', error); console.error("读取规则失败:", error);
return { rules: [], enabled }; return { rules: [], enabled };
} }
} }
/**
* 更新个人规则启用状态
*/
export async function updatePersonalRulesEnabled(
enabled: boolean,
): Promise<boolean> {
try {
await vscode.workspace
.getConfiguration("ic-coder")
.update(
"personalRulesEnabled",
enabled,
vscode.ConfigurationTarget.Global,
);
return true;
} catch (error) {
console.error("更新规则启用状态失败:", error);
return false;
}
}
/** /**
* 获取当前生效的所有规则内容 * 获取当前生效的所有规则内容
*/ */
@ -143,5 +190,5 @@ export function getActiveRules(): string | null {
if (!enabled || rules.length === 0) { if (!enabled || rules.length === 0) {
return null; return null;
} }
return rules.map(r => r.content).join('\n\n'); return rules.map((r) => r.content).join("\n\n");
} }

View File

@ -554,8 +554,8 @@ export function getContextButtonScript(): string {
if (currentListType === 'documentSetItem') { if (currentListType === 'documentSetItem') {
const selected = currentListData.filter(item => selectedItems.has(item.id)); const selected = currentListData.filter(item => selectedItems.has(item.id));
selected.forEach(docSet => { selected.forEach(docSet => {
docSet.documents.forEach(doc => { (docSet.files || []).forEach(doc => {
addContextItem('file', doc.path, doc.relativePath || doc.path); addContextItem('docset', doc.absolutePath, doc.name || doc.absolutePath);
}); });
}); });
} else { } else {
@ -609,9 +609,13 @@ export function getContextButtonScript(): string {
searchInput.addEventListener('input', function(e) { searchInput.addEventListener('input', function(e) {
const keyword = (e.target.value || '').toLowerCase().trim(); const keyword = (e.target.value || '').toLowerCase().trim();
const filtered = currentListData.filter(item => const filtered = currentListData.filter(item =>
(item.relativePath || item.path || '').toLowerCase().includes(keyword) (item.name || item.relativePath || item.path || '').toLowerCase().includes(keyword)
); );
if (currentListType === 'documentSetItem') {
renderDocumentSetList(filtered);
} else {
renderList(filtered); renderList(filtered);
}
}); });
} }

View File

@ -181,6 +181,7 @@ export function getContextDisplayScript(): string {
case 'folder': icon = getFolderIcon(); break; case 'folder': icon = getFolderIcon(); break;
case 'image': icon = getImageIcon(); break; case 'image': icon = getImageIcon(); break;
case 'document': icon = getDocumentIcon(); break; case 'document': icon = getDocumentIcon(); break;
case 'docset': icon = getDocumentIcon(); break;
case 'code': icon = getCodeIcon(); break; case 'code': icon = getCodeIcon(); break;
} }

View File

@ -409,7 +409,7 @@ export function getDocsetDialogScript(): string {
listEl.innerHTML = docsetFiles.map((file, index) => \` listEl.innerHTML = docsetFiles.map((file, index) => \`
<div style="display: flex; justify-content: space-between; align-items: center; font-size: 12px; padding: 4px 0; color: var(--vscode-foreground);"> <div style="display: flex; justify-content: space-between; align-items: center; font-size: 12px; padding: 4px 0; color: var(--vscode-foreground);">
<span>\${file.relativePath || file.path}</span> <span>\${file.name || file.absolutePath}</span>
<button onclick="removeDocsetFile(\${index})" style="background: transparent; border: none; color: var(--vscode-foreground); cursor: pointer; padding: 0 4px; opacity: 0.7;"> <button onclick="removeDocsetFile(\${index})" style="background: transparent; border: none; color: var(--vscode-foreground); cursor: pointer; padding: 0 4px; opacity: 0.7;">
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"> <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
<path d="M10 3h3v1h-1v9l-1 1H4l-1-1V4H2V3h3V2a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zM9 2H6v1h3V2zM4 13h7V4H4v9zm2-8H5v7h1V5zm1 0h1v7H7V5zm2 0h1v7H9V5z"/> <path d="M10 3h3v1h-1v9l-1 1H4l-1-1V4H2V3h3V2a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v1zM9 2H6v1h3V2zM4 13h7V4H4v9zm2-8H5v7h1V5zm1 0h1v7H7V5zm2 0h1v7H9V5z"/>
@ -538,7 +538,7 @@ export function getDocsetDialogScript(): string {
for (const file of message.files) { for (const file of message.files) {
if (file.size > MAX_FILE_SIZE) { if (file.size > MAX_FILE_SIZE) {
errors.push(\`\${file.path} 超过单个文件大小限制(\${formatFileSize(MAX_FILE_SIZE)}\`); errors.push(\`\${file.name || file.absolutePath} 超过单个文件大小限制(\${formatFileSize(MAX_FILE_SIZE)}\`);
} else { } else {
vaildFiles.push(file); vaildFiles.push(file);
} }

View File

@ -553,7 +553,7 @@ export function getMessageAreaStyles(): string {
} }
.segment-question .question-option { .segment-question .question-option {
padding: 8px 16px; padding: 8px 16px;
background: #3d3f41; background: var(--vscode-textBlockQuote-background);
color: var(--vscode-foreground); color: var(--vscode-foreground);
border: 1px solid #474747; border: 1px solid #474747;
border-radius: 6px; border-radius: 6px;
@ -563,13 +563,13 @@ export function getMessageAreaStyles(): string {
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
.segment-question .question-option:hover { .segment-question .question-option:hover {
background: #005a9e; background: var(--vscode-button-hoverBackground);
border-color: #005a9e; border-color: var(--vscode-button-hoverBackground);
} }
.segment-question .question-option.selected { .segment-question .question-option.selected {
background: #007ACC; background: var(--vscode-button-background);
color: #ffffff; color: var(--vscode-button-foreground);
border-color: #007ACC; border-color: var(--vscode-button-background);
} }
.segment-question.answered .question-option:not(.selected) { .segment-question.answered .question-option:not(.selected) {
opacity: 0.5; opacity: 0.5;

View File

@ -400,6 +400,12 @@ export function getRulesSettingsComponentScript(): string {
} }
} }
//监听启用个人规则开关变化
document.getElementById('enablePersonalRulesCheckbox').addEventListener('change', function() {
const enabled = this.checked;
vscode.postMessage({ command: 'updatePersonalRulesEnabled', enabled: enabled });
});
// 页面加载时请求规则数据 // 页面加载时请求规则数据
vscode.postMessage({ command: 'loadPersonalRules' }); vscode.postMessage({ command: 'loadPersonalRules' });
`; `;