Remove LLM enhancement features and related components as per user request. This includes the deletion of source code files, CLI commands, front-end components, tests, scripts, and documentation associated with LLM functionality. Simplified dependencies and reduced complexity while retaining core vector search capabilities. Validation of changes confirmed successful removal and functionality.

This commit is contained in:
catlog22
2025-12-16 21:38:27 +08:00
parent d21066c282
commit b702791c2c
21 changed files with 375 additions and 7193 deletions

View File

@@ -18,15 +18,6 @@ let nativeResumeEnabled = localStorage.getItem('ccw-native-resume') !== 'false';
// Recursive Query settings (for hierarchical storage aggregation)
let recursiveQueryEnabled = localStorage.getItem('ccw-recursive-query') !== 'false'; // default true
// LLM Enhancement settings for Semantic Search
let llmEnhancementSettings = {
enabled: localStorage.getItem('ccw-llm-enhancement-enabled') === 'true',
tool: localStorage.getItem('ccw-llm-enhancement-tool') || 'gemini',
fallbackTool: localStorage.getItem('ccw-llm-enhancement-fallback') || 'qwen',
batchSize: parseInt(localStorage.getItem('ccw-llm-enhancement-batch-size') || '5', 10),
timeoutMs: parseInt(localStorage.getItem('ccw-llm-enhancement-timeout') || '300000', 10)
};
// ========== Initialization ==========
function initCliStatus() {
// Load all statuses in one call using aggregated endpoint
@@ -242,17 +233,12 @@ function renderCliStatus() {
`;
// Semantic Search card (only show if CodexLens is installed)
const llmStatusBadge = llmEnhancementSettings.enabled
? `<span class="badge px-1.5 py-0.5 text-xs rounded bg-success/20 text-success">LLM</span>`
: '';
const semanticHtml = codexLensStatus.ready ? `
<div class="cli-tool-card tool-semantic clickable ${semanticStatus.available ? 'available' : 'unavailable'}"
onclick="openSemanticSettingsModal()">
<div class="cli-tool-card tool-semantic ${semanticStatus.available ? 'available' : 'unavailable'}">
<div class="cli-tool-header">
<span class="cli-tool-status ${semanticStatus.available ? 'status-available' : 'status-unavailable'}"></span>
<span class="cli-tool-name">Semantic Search</span>
<span class="badge px-1.5 py-0.5 text-xs rounded ${semanticStatus.available ? 'bg-primary/20 text-primary' : 'bg-muted text-muted-foreground'}">AI</span>
${llmStatusBadge}
</div>
<div class="cli-tool-desc text-xs text-muted-foreground mt-1">
${semanticStatus.available ? 'AI-powered code understanding' : 'Natural language code search'}
@@ -265,27 +251,17 @@ function renderCliStatus() {
</div>
<div class="cli-tool-actions flex flex-col gap-2 mt-3">
${!semanticStatus.available ? `
<button class="btn-sm btn-primary w-full flex items-center justify-center gap-1" onclick="event.stopPropagation(); openSemanticInstallWizard()">
<button class="btn-sm btn-primary w-full flex items-center justify-center gap-1" onclick="openSemanticInstallWizard()">
<i data-lucide="brain" class="w-3 h-3"></i> Install AI Model
</button>
<div class="flex items-center justify-between w-full mt-1">
<div class="flex items-center gap-1 text-xs text-muted-foreground">
<i data-lucide="hard-drive" class="w-3 h-3"></i>
<span>~130MB</span>
</div>
<button class="btn-sm btn-outline flex items-center gap-1" onclick="event.stopPropagation(); openSemanticSettingsModal()">
<i data-lucide="settings" class="w-3 h-3"></i>
</button>
<div class="flex items-center gap-1 text-xs text-muted-foreground mt-1">
<i data-lucide="hard-drive" class="w-3 h-3"></i>
<span>~130MB</span>
</div>
` : `
<div class="flex items-center justify-between w-full">
<div class="flex items-center gap-1 text-xs text-muted-foreground">
<i data-lucide="cpu" class="w-3 h-3"></i>
<span>bge-small-en-v1.5</span>
</div>
<button class="btn-sm btn-outline flex items-center gap-1" onclick="event.stopPropagation(); openSemanticSettingsModal()">
<i data-lucide="settings" class="w-3 h-3"></i>
</button>
<div class="flex items-center gap-1 text-xs text-muted-foreground">
<i data-lucide="cpu" class="w-3 h-3"></i>
<span>bge-small-en-v1.5</span>
</div>
`}
</div>
@@ -991,618 +967,3 @@ async function startSemanticInstall() {
}
}
// ========== Semantic Search Settings Modal ==========
function openSemanticSettingsModal() {
const availableTools = Object.entries(cliToolStatus)
.filter(function(entry) { return entry[1].available; })
.map(function(entry) { return entry[0]; });
const modal = document.createElement('div');
modal.id = 'semanticSettingsModal';
modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50';
modal.onclick = function(e) { if (e.target === modal) closeSemanticSettingsModal(); };
const toolOptions = availableTools.map(function(tool) {
return '<option value="' + tool + '"' + (llmEnhancementSettings.tool === tool ? ' selected' : '') + '>' +
tool.charAt(0).toUpperCase() + tool.slice(1) + '</option>';
}).join('');
const fallbackOptions = '<option value="">' + t('semantic.none') + '</option>' + availableTools.map(function(tool) {
return '<option value="' + tool + '"' + (llmEnhancementSettings.fallbackTool === tool ? ' selected' : '') + '>' +
tool.charAt(0).toUpperCase() + tool.slice(1) + '</option>';
}).join('');
const disabled = !llmEnhancementSettings.enabled ? 'disabled' : '';
const opacityClass = !llmEnhancementSettings.enabled ? 'opacity-50' : '';
modal.innerHTML =
'<div class="bg-card rounded-lg shadow-xl w-full max-w-lg mx-4 overflow-hidden" onclick="event.stopPropagation()">' +
'<div class="p-6">' +
'<div class="flex items-center gap-3 mb-4">' +
'<div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">' +
'<i data-lucide="sparkles" class="w-5 h-5 text-primary"></i>' +
'</div>' +
'<div>' +
'<h3 class="text-lg font-semibold">' + t('semantic.settings') + '</h3>' +
'<p class="text-sm text-muted-foreground">' + t('semantic.configDesc') + '</p>' +
'</div>' +
'</div>' +
'<div class="space-y-4">' +
'<div class="flex items-center justify-between p-4 bg-muted/50 rounded-lg">' +
'<div>' +
'<h4 class="font-medium flex items-center gap-2">' +
'<i data-lucide="brain" class="w-4 h-4"></i>' + t('semantic.llmEnhancement') + '</h4>' +
'<p class="text-sm text-muted-foreground mt-1">' + t('semantic.llmDesc') + '</p>' +
'</div>' +
'<label class="cli-toggle">' +
'<input type="checkbox" id="llmEnhancementToggle" ' + (llmEnhancementSettings.enabled ? 'checked' : '') +
' onchange="toggleLlmEnhancement(this.checked)">' +
'<span class="cli-toggle-slider"></span>' +
'</label>' +
'</div>' +
'<div class="p-4 bg-muted/30 rounded-lg space-y-4 ' + opacityClass + '" id="llmSettingsSection">' +
'<div class="grid grid-cols-2 gap-4">' +
'<div>' +
'<label class="block text-sm font-medium mb-2">' +
'<i data-lucide="cpu" class="w-3 h-3 inline mr-1"></i>' + t('semantic.primaryTool') + '</label>' +
'<select class="cli-setting-select w-full" id="llmToolSelect" onchange="updateLlmTool(this.value)" ' + disabled + '>' + toolOptions + '</select>' +
'</div>' +
'<div>' +
'<label class="block text-sm font-medium mb-2">' +
'<i data-lucide="refresh-cw" class="w-3 h-3 inline mr-1"></i>' + t('semantic.fallbackTool') + '</label>' +
'<select class="cli-setting-select w-full" id="llmFallbackSelect" onchange="updateLlmFallback(this.value)" ' + disabled + '>' + fallbackOptions + '</select>' +
'</div>' +
'</div>' +
'<div class="grid grid-cols-2 gap-4">' +
'<div>' +
'<label class="block text-sm font-medium mb-2">' +
'<i data-lucide="layers" class="w-3 h-3 inline mr-1"></i>' + t('semantic.batchSize') + '</label>' +
'<select class="cli-setting-select w-full" id="llmBatchSelect" onchange="updateLlmBatchSize(this.value)" ' + disabled + '>' +
'<option value="1"' + (llmEnhancementSettings.batchSize === 1 ? ' selected' : '') + '>1 ' + t('semantic.file') + '</option>' +
'<option value="3"' + (llmEnhancementSettings.batchSize === 3 ? ' selected' : '') + '>3 ' + t('semantic.files') + '</option>' +
'<option value="5"' + (llmEnhancementSettings.batchSize === 5 ? ' selected' : '') + '>5 ' + t('semantic.files') + '</option>' +
'<option value="10"' + (llmEnhancementSettings.batchSize === 10 ? ' selected' : '') + '>10 ' + t('semantic.files') + '</option>' +
'</select>' +
'</div>' +
'<div>' +
'<label class="block text-sm font-medium mb-2">' +
'<i data-lucide="clock" class="w-3 h-3 inline mr-1"></i>' + t('semantic.timeout') + '</label>' +
'<select class="cli-setting-select w-full" id="llmTimeoutSelect" onchange="updateLlmTimeout(this.value)" ' + disabled + '>' +
'<option value="60000"' + (llmEnhancementSettings.timeoutMs === 60000 ? ' selected' : '') + '>1 min</option>' +
'<option value="180000"' + (llmEnhancementSettings.timeoutMs === 180000 ? ' selected' : '') + '>3 min</option>' +
'<option value="300000"' + (llmEnhancementSettings.timeoutMs === 300000 ? ' selected' : '') + '>5 min</option>' +
'<option value="600000"' + (llmEnhancementSettings.timeoutMs === 600000 ? ' selected' : '') + '>10 min</option>' +
'</select>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="bg-primary/5 border border-primary/20 rounded-lg p-3">' +
'<div class="flex items-start gap-2">' +
'<i data-lucide="info" class="w-4 h-4 text-primary mt-0.5"></i>' +
'<div class="text-sm text-muted-foreground">' +
'<p>' + t('semantic.enhanceInfo') + '</p>' +
'<p class="mt-1">' + t('semantic.enhanceCommand') + ' <code class="bg-muted px-1 rounded">codex-lens enhance</code> ' + t('semantic.enhanceAfterEnable') + '</p>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="flex gap-2 pt-2">' +
'<button class="btn-sm btn-outline flex items-center gap-1 flex-1" onclick="runEnhanceCommand()" ' + disabled + '>' +
'<i data-lucide="zap" class="w-3 h-3"></i>' + t('semantic.runEnhanceNow') + '</button>' +
'<button class="btn-sm btn-outline flex items-center gap-1 flex-1" onclick="viewEnhanceStatus()">' +
'<i data-lucide="bar-chart-2" class="w-3 h-3"></i>' + t('semantic.viewStatus') + '</button>' +
'</div>' +
'<div class="border-t border-border my-4"></div>' +
'<div>' +
'<h4 class="font-medium mb-3 flex items-center gap-2">' +
'<i data-lucide="search" class="w-4 h-4"></i>' + t('semantic.testSearch') + '</h4>' +
'<div class="space-y-3">' +
'<div>' +
'<input type="text" id="semanticSearchInput" class="tool-config-input w-full" ' +
'placeholder="' + t('semantic.searchPlaceholder') + '" />' +
'</div>' +
'<div>' +
'<button class="btn-sm btn-primary w-full" id="runSemanticSearchBtn">' +
'<i data-lucide="search" class="w-3 h-3"></i> ' + t('semantic.runSearch') +
'</button>' +
'</div>' +
'<div id="semanticSearchResults" class="hidden">' +
'<div class="bg-muted/30 rounded-lg p-3 max-h-64 overflow-y-auto">' +
'<div class="flex items-center justify-between mb-2">' +
'<p class="text-sm font-medium">' + t('codexlens.results') + ':</p>' +
'<span id="semanticResultCount" class="text-xs text-muted-foreground"></span>' +
'</div>' +
'<pre id="semanticResultContent" class="text-xs font-mono whitespace-pre-wrap break-all"></pre>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="border-t border-border p-4 flex justify-end gap-3 bg-muted/30">' +
'<button class="btn-outline px-4 py-2" onclick="closeSemanticSettingsModal()">' + t('semantic.close') + '</button>' +
'</div>' +
'</div>';
document.body.appendChild(modal);
// Add semantic search button handler
setTimeout(function() {
var runSemanticSearchBtn = document.getElementById('runSemanticSearchBtn');
if (runSemanticSearchBtn) {
runSemanticSearchBtn.onclick = async function() {
var query = document.getElementById('semanticSearchInput').value.trim();
var resultsDiv = document.getElementById('semanticSearchResults');
var resultCount = document.getElementById('semanticResultCount');
var resultContent = document.getElementById('semanticResultContent');
if (!query) {
showRefreshToast(t('codexlens.enterQuery'), 'warning');
return;
}
runSemanticSearchBtn.disabled = true;
runSemanticSearchBtn.innerHTML = '<span class="animate-pulse">' + t('codexlens.searching') + '</span>';
resultsDiv.classList.add('hidden');
try {
var params = new URLSearchParams({
query: query,
mode: 'semantic',
limit: '10'
});
var response = await fetch('/api/codexlens/search?' + params.toString());
var result = await response.json();
console.log('[Semantic Search Test] Result:', result);
if (result.success) {
var results = result.results || [];
resultCount.textContent = results.length + ' ' + t('codexlens.resultsCount');
resultContent.textContent = JSON.stringify(results, null, 2);
resultsDiv.classList.remove('hidden');
showRefreshToast(t('codexlens.searchCompleted') + ': ' + results.length + ' ' + t('codexlens.resultsCount'), 'success');
} else {
resultContent.textContent = t('common.error') + ': ' + (result.error || t('common.unknownError'));
resultsDiv.classList.remove('hidden');
showRefreshToast(t('codexlens.searchFailed') + ': ' + result.error, 'error');
}
runSemanticSearchBtn.disabled = false;
runSemanticSearchBtn.innerHTML = '<i data-lucide="search" class="w-3 h-3"></i> ' + t('semantic.runSearch');
if (window.lucide) lucide.createIcons();
} catch (err) {
console.error('[Semantic Search Test] Error:', err);
resultContent.textContent = t('common.exception') + ': ' + err.message;
resultsDiv.classList.remove('hidden');
showRefreshToast(t('common.error') + ': ' + err.message, 'error');
runSemanticSearchBtn.disabled = false;
runSemanticSearchBtn.innerHTML = '<i data-lucide="search" class="w-3 h-3"></i> ' + t('semantic.runSearch');
if (window.lucide) lucide.createIcons();
}
};
}
}, 100);
var handleEscape = function(e) {
if (e.key === 'Escape') {
closeSemanticSettingsModal();
document.removeEventListener('keydown', handleEscape);
}
};
document.addEventListener('keydown', handleEscape);
if (window.lucide) {
lucide.createIcons();
}
}
function closeSemanticSettingsModal() {
var modal = document.getElementById('semanticSettingsModal');
if (modal) modal.remove();
}
function toggleLlmEnhancement(enabled) {
llmEnhancementSettings.enabled = enabled;
localStorage.setItem('ccw-llm-enhancement-enabled', enabled.toString());
var settingsSection = document.getElementById('llmSettingsSection');
if (settingsSection) {
settingsSection.classList.toggle('opacity-50', !enabled);
settingsSection.querySelectorAll('select').forEach(function(el) { el.disabled = !enabled; });
}
renderCliStatus();
showRefreshToast(t('semantic.llmEnhancement') + ' ' + (enabled ? t('semantic.enabled') : t('semantic.disabled')), 'success');
}
function updateLlmTool(tool) {
llmEnhancementSettings.tool = tool;
localStorage.setItem('ccw-llm-enhancement-tool', tool);
showRefreshToast(t('semantic.toolSetTo') + ' ' + tool, 'success');
}
function updateLlmFallback(tool) {
llmEnhancementSettings.fallbackTool = tool;
localStorage.setItem('ccw-llm-enhancement-fallback', tool);
showRefreshToast(t('semantic.fallbackSetTo') + ' ' + (tool || t('semantic.none')), 'success');
}
function updateLlmBatchSize(size) {
llmEnhancementSettings.batchSize = parseInt(size, 10);
localStorage.setItem('ccw-llm-enhancement-batch-size', size);
showRefreshToast(t('semantic.batchSetTo') + ' ' + size + ' ' + t('semantic.files'), 'success');
}
function updateLlmTimeout(ms) {
llmEnhancementSettings.timeoutMs = parseInt(ms, 10);
localStorage.setItem('ccw-llm-enhancement-timeout', ms);
var mins = parseInt(ms, 10) / 60000;
showRefreshToast(t('semantic.timeoutSetTo') + ' ' + mins + ' ' + (mins > 1 ? t('semantic.minutes') : t('semantic.minute')), 'success');
}
async function runEnhanceCommand() {
if (!llmEnhancementSettings.enabled) {
showRefreshToast(t('semantic.enableFirst'), 'warning');
return;
}
showRefreshToast('Starting LLM enhancement...', 'info');
closeSemanticSettingsModal();
try {
var response = await fetch('/api/codexlens/enhance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
path: projectPath,
tool: llmEnhancementSettings.tool,
batchSize: llmEnhancementSettings.batchSize,
timeoutMs: llmEnhancementSettings.timeoutMs
})
});
var result = await response.json();
if (result.success) {
var enhanced = result.result?.enhanced || 0;
showRefreshToast('Enhanced ' + enhanced + ' files with LLM', 'success');
} else {
showRefreshToast('Enhance failed: ' + result.error, 'error');
}
} catch (err) {
showRefreshToast('Enhance error: ' + err.message, 'error');
}
}
function viewEnhanceStatus() {
openSemanticMetadataViewer();
}
// ========== Semantic Metadata Viewer ==========
var semanticMetadataCache = {
entries: [],
total: 0,
offset: 0,
limit: 50,
loading: false
};
async function openSemanticMetadataViewer() {
closeSemanticSettingsModal();
var modal = document.createElement('div');
modal.id = 'semanticMetadataModal';
modal.className = 'generic-modal-overlay';
modal.onclick = function(e) { if (e.target === modal) closeSemanticMetadataViewer(); };
modal.innerHTML =
'<div class="generic-modal large" onclick="event.stopPropagation()">' +
'<div class="generic-modal-header">' +
'<div class="flex items-center gap-3">' +
'<i data-lucide="database" class="w-5 h-5 text-primary"></i>' +
'<h3 class="generic-modal-title">Semantic Metadata Browser</h3>' +
'<span id="semanticMetadataCount" class="badge bg-muted text-muted-foreground px-2 py-0.5 text-xs rounded">Loading...</span>' +
'</div>' +
'<button class="generic-modal-close" onclick="closeSemanticMetadataViewer()">' +
'<i data-lucide="x" class="w-4 h-4"></i>' +
'</button>' +
'</div>' +
'<div class="generic-modal-body p-0">' +
'<div class="semantic-viewer-toolbar">' +
'<div class="flex items-center gap-3">' +
'<select id="semanticToolFilter" class="cli-setting-select" onchange="filterSemanticByTool(this.value)">' +
'<option value="">All Tools</option>' +
'<option value="gemini">Gemini</option>' +
'<option value="qwen">Qwen</option>' +
'</select>' +
'<button class="btn-sm btn-outline flex items-center gap-1" onclick="refreshSemanticMetadata()">' +
'<i data-lucide="refresh-cw" class="w-3 h-3"></i> Refresh' +
'</button>' +
'</div>' +
'<div class="flex items-center gap-2 text-sm text-muted-foreground">' +
'<span id="semanticPaginationInfo">-</span>' +
'</div>' +
'</div>' +
'<div id="semanticMetadataTableContainer" class="semantic-table-container">' +
'<div class="semantic-loading">' +
'<div class="animate-spin w-6 h-6 border-2 border-primary border-t-transparent rounded-full"></div>' +
'<span>Loading metadata...</span>' +
'</div>' +
'</div>' +
'<div class="semantic-viewer-footer">' +
'<button id="semanticPrevBtn" class="btn-sm btn-outline" onclick="semanticPrevPage()" disabled>' +
'<i data-lucide="chevron-left" class="w-4 h-4"></i> Previous' +
'</button>' +
'<div class="flex items-center gap-2">' +
'<span class="text-sm text-muted-foreground">Page</span>' +
'<select id="semanticPageSelect" class="cli-setting-select" onchange="semanticGoToPage(this.value)">' +
'<option value="0">1</option>' +
'</select>' +
'</div>' +
'<button id="semanticNextBtn" class="btn-sm btn-outline" onclick="semanticNextPage()" disabled>' +
'Next <i data-lucide="chevron-right" class="w-4 h-4"></i>' +
'</button>' +
'</div>' +
'</div>' +
'</div>';
document.body.appendChild(modal);
requestAnimationFrame(function() {
modal.classList.add('active');
});
var handleEscape = function(e) {
if (e.key === 'Escape') {
closeSemanticMetadataViewer();
document.removeEventListener('keydown', handleEscape);
}
};
document.addEventListener('keydown', handleEscape);
if (window.lucide) {
lucide.createIcons();
}
await loadSemanticMetadata();
}
function closeSemanticMetadataViewer() {
var modal = document.getElementById('semanticMetadataModal');
if (modal) {
modal.classList.remove('active');
setTimeout(function() { modal.remove(); }, 200);
}
}
async function loadSemanticMetadata(offset, toolFilter) {
offset = typeof offset === 'number' ? offset : semanticMetadataCache.offset;
toolFilter = toolFilter !== undefined ? toolFilter : (document.getElementById('semanticToolFilter')?.value || '');
semanticMetadataCache.loading = true;
var container = document.getElementById('semanticMetadataTableContainer');
if (container) {
container.innerHTML =
'<div class="semantic-loading">' +
'<div class="animate-spin w-6 h-6 border-2 border-primary border-t-transparent rounded-full"></div>' +
'<span>Loading metadata...</span>' +
'</div>';
}
try {
var url = '/api/codexlens/semantic/metadata?offset=' + offset + '&limit=' + semanticMetadataCache.limit;
if (toolFilter) {
url += '&tool=' + encodeURIComponent(toolFilter);
}
var response = await fetch(url);
var data = await response.json();
if (data.success && data.result) {
semanticMetadataCache.entries = data.result.entries || [];
semanticMetadataCache.total = data.result.total || 0;
semanticMetadataCache.offset = offset;
renderSemanticMetadataTable();
updateSemanticPagination();
} else {
container.innerHTML =
'<div class="semantic-empty">' +
'<i data-lucide="alert-circle" class="w-8 h-8 text-muted-foreground"></i>' +
'<p>Error loading metadata: ' + (data.error || 'Unknown error') + '</p>' +
'</div>';
if (window.lucide) lucide.createIcons();
}
} catch (err) {
container.innerHTML =
'<div class="semantic-empty">' +
'<i data-lucide="alert-circle" class="w-8 h-8 text-muted-foreground"></i>' +
'<p>Error: ' + err.message + '</p>' +
'</div>';
if (window.lucide) lucide.createIcons();
}
semanticMetadataCache.loading = false;
}
function escapeHtmlSemantic(text) {
if (!text) return '';
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function renderSemanticMetadataTable() {
var container = document.getElementById('semanticMetadataTableContainer');
if (!container) return;
var entries = semanticMetadataCache.entries;
if (!entries.length) {
container.innerHTML =
'<div class="semantic-empty">' +
'<i data-lucide="database" class="w-12 h-12 text-muted-foreground mb-3"></i>' +
'<p class="text-lg font-medium">No semantic metadata found</p>' +
'<p class="text-sm text-muted-foreground mt-1">Run \'codex-lens enhance\' to generate metadata for indexed files.</p>' +
'<button class="btn-sm btn-primary mt-4" onclick="closeSemanticMetadataViewer(); runEnhanceCommand();">' +
'<i data-lucide="zap" class="w-3 h-3 mr-1"></i> Run Enhance' +
'</button>' +
'</div>';
if (window.lucide) lucide.createIcons();
return;
}
var rows = entries.map(function(entry, idx) {
var keywordsHtml = (entry.keywords || []).slice(0, 4).map(function(k) {
return '<span class="semantic-keyword">' + escapeHtmlSemantic(k) + '</span>';
}).join('');
if ((entry.keywords || []).length > 4) {
keywordsHtml += '<span class="semantic-keyword-more">+' + (entry.keywords.length - 4) + '</span>';
}
var date = entry.generated_at ? new Date(entry.generated_at * 1000).toLocaleDateString() : '-';
return (
'<tr class="semantic-row" onclick="toggleSemanticDetail(' + idx + ')">' +
'<td class="semantic-cell-file">' +
'<div class="flex items-center gap-2">' +
'<i data-lucide="file-code" class="w-4 h-4 text-muted-foreground"></i>' +
'<span class="font-medium">' + escapeHtmlSemantic(entry.file_name || '-') + '</span>' +
'</div>' +
'<div class="text-xs text-muted-foreground truncate" title="' + escapeHtmlSemantic(entry.full_path || '') + '">' +
escapeHtmlSemantic(entry.full_path || '-') +
'</div>' +
'</td>' +
'<td class="semantic-cell-lang">' + escapeHtmlSemantic(entry.language || '-') + '</td>' +
'<td class="semantic-cell-purpose">' + escapeHtmlSemantic((entry.purpose || '-').substring(0, 50)) +
((entry.purpose || '').length > 50 ? '...' : '') + '</td>' +
'<td class="semantic-cell-keywords">' + (keywordsHtml || '-') + '</td>' +
'<td class="semantic-cell-tool">' +
'<span class="tool-badge tool-' + (entry.llm_tool || 'unknown') + '">' +
escapeHtmlSemantic(entry.llm_tool || '-') +
'</span>' +
'</td>' +
'<td class="semantic-cell-date">' + date + '</td>' +
'</tr>' +
'<tr id="semanticDetail' + idx + '" class="semantic-detail-row hidden">' +
'<td colspan="6">' +
'<div class="semantic-detail-content">' +
'<div class="semantic-detail-section">' +
'<h4><i data-lucide="file-text" class="w-3 h-3"></i> Summary</h4>' +
'<p>' + escapeHtmlSemantic(entry.summary || 'No summary available') + '</p>' +
'</div>' +
'<div class="semantic-detail-section">' +
'<h4><i data-lucide="tag" class="w-3 h-3"></i> All Keywords</h4>' +
'<div class="semantic-keywords-full">' +
(entry.keywords || []).map(function(k) {
return '<span class="semantic-keyword">' + escapeHtmlSemantic(k) + '</span>';
}).join('') +
'</div>' +
'</div>' +
'<div class="semantic-detail-meta">' +
'<span><i data-lucide="hash" class="w-3 h-3"></i> ' + (entry.line_count || 0) + ' lines</span>' +
'<span><i data-lucide="cpu" class="w-3 h-3"></i> ' + escapeHtmlSemantic(entry.llm_tool || 'Unknown') + '</span>' +
'<span><i data-lucide="calendar" class="w-3 h-3"></i> ' + date + '</span>' +
'</div>' +
'</div>' +
'</td>' +
'</tr>'
);
}).join('');
container.innerHTML =
'<table class="semantic-table">' +
'<thead>' +
'<tr>' +
'<th>File</th>' +
'<th>Language</th>' +
'<th>Purpose</th>' +
'<th>Keywords</th>' +
'<th>Tool</th>' +
'<th>Date</th>' +
'</tr>' +
'</thead>' +
'<tbody>' + rows + '</tbody>' +
'</table>';
if (window.lucide) lucide.createIcons();
}
function toggleSemanticDetail(idx) {
var detailRow = document.getElementById('semanticDetail' + idx);
if (detailRow) {
detailRow.classList.toggle('hidden');
if (window.lucide) lucide.createIcons();
}
}
function updateSemanticPagination() {
var total = semanticMetadataCache.total;
var offset = semanticMetadataCache.offset;
var limit = semanticMetadataCache.limit;
var entries = semanticMetadataCache.entries;
var countBadge = document.getElementById('semanticMetadataCount');
if (countBadge) {
countBadge.textContent = total + ' entries';
}
var paginationInfo = document.getElementById('semanticPaginationInfo');
if (paginationInfo) {
if (total > 0) {
paginationInfo.textContent = (offset + 1) + '-' + (offset + entries.length) + ' of ' + total;
} else {
paginationInfo.textContent = 'No entries';
}
}
var pageSelect = document.getElementById('semanticPageSelect');
if (pageSelect) {
var totalPages = Math.ceil(total / limit) || 1;
var currentPage = Math.floor(offset / limit);
pageSelect.innerHTML = '';
for (var i = 0; i < totalPages; i++) {
var opt = document.createElement('option');
opt.value = i;
opt.textContent = i + 1;
if (i === currentPage) opt.selected = true;
pageSelect.appendChild(opt);
}
}
var prevBtn = document.getElementById('semanticPrevBtn');
var nextBtn = document.getElementById('semanticNextBtn');
if (prevBtn) prevBtn.disabled = offset === 0;
if (nextBtn) nextBtn.disabled = offset + limit >= total;
}
function semanticPrevPage() {
if (semanticMetadataCache.offset > 0) {
loadSemanticMetadata(Math.max(0, semanticMetadataCache.offset - semanticMetadataCache.limit));
}
}
function semanticNextPage() {
if (semanticMetadataCache.offset + semanticMetadataCache.limit < semanticMetadataCache.total) {
loadSemanticMetadata(semanticMetadataCache.offset + semanticMetadataCache.limit);
}
}
function semanticGoToPage(pageIndex) {
var offset = parseInt(pageIndex, 10) * semanticMetadataCache.limit;
loadSemanticMetadata(offset);
}
function filterSemanticByTool(tool) {
loadSemanticMetadata(0, tool);
}
function refreshSemanticMetadata() {
loadSemanticMetadata(semanticMetadataCache.offset);
}
function getLlmEnhancementSettings() {
return Object.assign({}, llmEnhancementSettings);
}

View File

@@ -277,35 +277,10 @@ const i18n = {
// Semantic Search Configuration
'semantic.settings': 'Semantic Search Settings',
'semantic.configDesc': 'Configure LLM enhancement for semantic indexing',
'semantic.llmEnhancement': 'LLM Enhancement',
'semantic.llmDesc': 'Use LLM to generate code summaries for better semantic search',
'semantic.primaryTool': 'Primary LLM Tool',
'semantic.fallbackTool': 'Fallback Tool',
'semantic.batchSize': 'Batch Size',
'semantic.timeout': 'Timeout',
'semantic.file': 'file',
'semantic.files': 'files',
'semantic.enhanceInfo': 'LLM enhancement generates code summaries and keywords for each file, improving semantic search accuracy.',
'semantic.enhanceCommand': 'Run',
'semantic.enhanceAfterEnable': 'after enabling to process existing files.',
'semantic.runEnhanceNow': 'Run Enhance Now',
'semantic.viewStatus': 'View Status',
'semantic.testSearch': 'Test Semantic Search',
'semantic.searchPlaceholder': 'Enter semantic query (e.g., authentication logic, error handling)',
'semantic.runSearch': 'Run Semantic Search',
'semantic.close': 'Close',
'semantic.enabled': 'enabled',
'semantic.disabled': 'disabled',
'semantic.toolSetTo': 'Primary LLM tool set to',
'semantic.fallbackSetTo': 'Fallback tool set to',
'semantic.none': 'none',
'semantic.llmEnhancement': 'LLM Enhancement',
'semantic.batchSetTo': 'Batch size set to',
'semantic.timeoutSetTo': 'Timeout set to',
'semantic.minute': 'minute',
'semantic.minutes': 'minutes',
'semantic.enableFirst': 'Please enable LLM Enhancement first',
'cli.settings': 'CLI Execution Settings',
'cli.promptFormat': 'Prompt Format',
@@ -1407,35 +1382,10 @@ const i18n = {
// Semantic Search 配置
'semantic.settings': '语义搜索设置',
'semantic.configDesc': '配置语义索引的 LLM 增强功能',
'semantic.llmEnhancement': 'LLM 增强',
'semantic.llmDesc': '使用 LLM 生成代码摘要以改进语义搜索',
'semantic.primaryTool': '主 LLM 工具',
'semantic.fallbackTool': '备用工具',
'semantic.batchSize': '批处理大小',
'semantic.timeout': '超时时间',
'semantic.file': '个文件',
'semantic.files': '个文件',
'semantic.enhanceInfo': 'LLM 增强为每个文件生成代码摘要和关键词,提高语义搜索准确度。',
'semantic.enhanceCommand': '运行',
'semantic.enhanceAfterEnable': '启用后处理现有文件。',
'semantic.runEnhanceNow': '立即运行增强',
'semantic.viewStatus': '查看状态',
'semantic.testSearch': '测试语义搜索',
'semantic.searchPlaceholder': '输入语义查询(例如:身份验证逻辑、错误处理)',
'semantic.runSearch': '运行语义搜索',
'semantic.close': '关闭',
'semantic.enabled': '已启用',
'semantic.disabled': '已禁用',
'semantic.toolSetTo': '主 LLM 工具已设置为',
'semantic.fallbackSetTo': '备用工具已设置为',
'semantic.none': '无',
'semantic.llmEnhancement': 'LLM 增强',
'semantic.batchSetTo': '批量大小已设置为',
'semantic.timeoutSetTo': '超时已设置为',
'semantic.minute': '分钟',
'semantic.minutes': '分钟',
'semantic.enableFirst': '请先启用 LLM 增强',
'cli.settings': 'CLI 调用设置',
'cli.promptFormat': '提示词格式',

View File

@@ -397,13 +397,11 @@ function renderToolsSection() {
// Semantic Search item (only show if CodexLens is installed)
var semanticHtml = '';
if (codexLensStatus.ready) {
semanticHtml = '<div class="tool-item clickable ' + (semanticStatus.available ? 'available' : 'unavailable') + '" onclick="openSemanticSettingsModal()">' +
semanticHtml = '<div class="tool-item ' + (semanticStatus.available ? 'available' : 'unavailable') + '">' +
'<div class="tool-item-left">' +
'<span class="tool-status-dot ' + (semanticStatus.available ? 'status-available' : 'status-unavailable') + '"></span>' +
'<div class="tool-item-info">' +
'<div class="tool-item-name">Semantic Search <span class="tool-type-badge ai">AI</span>' +
(llmEnhancementSettings.enabled ? '<span class="tool-type-badge llm">LLM</span>' : '') +
'<i data-lucide="settings" class="w-3 h-3 tool-config-icon"></i></div>' +
'<div class="tool-item-name">Semantic Search <span class="tool-type-badge ai">AI</span></div>' +
'<div class="tool-item-desc">' + (semanticStatus.available ? 'AI-powered code understanding' : 'Natural language code search') + '</div>' +
'</div>' +
'</div>' +