-
-
- ~130MB
-
-
+
+
+ ~130MB
` : `
-
-
-
- bge-small-en-v1.5
-
-
+
+
+ bge-small-en-v1.5
`}
@@ -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 '
';
- }).join('');
-
- const fallbackOptions = '
' + availableTools.map(function(tool) {
- return '
';
- }).join('');
-
- const disabled = !llmEnhancementSettings.enabled ? 'disabled' : '';
- const opacityClass = !llmEnhancementSettings.enabled ? 'opacity-50' : '';
-
- modal.innerHTML =
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '
' +
- '
' +
- '
' + t('semantic.settings') + '
' +
- '
' + t('semantic.configDesc') + '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' + t('semantic.llmEnhancement') + '
' +
- '
' + t('semantic.llmDesc') + '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '' +
- '
' +
- '
' +
- '' +
- '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '' +
- '
' +
- '
' +
- '' +
- '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' + t('semantic.enhanceInfo') + '
' +
- '
' + t('semantic.enhanceCommand') + ' codex-lens enhance ' + t('semantic.enhanceAfterEnable') + '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' + t('semantic.testSearch') + '
' +
- '
' +
- '
' +
- '' +
- '
' +
- '
' +
- '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' + t('codexlens.results') + ':
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '' +
- '
' +
- '
';
-
- 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 = '
' + t('codexlens.searching') + '';
- 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 = '
' + 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 = '
' + 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 =
- '
' +
- '' +
- '
' +
- '
' +
- '
' +
- '' +
- '
' +
- '
';
-
- 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 =
- '
' +
- '
' +
- '
Loading metadata...' +
- '
';
- }
-
- 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 =
- '
' +
- '
' +
- '
Error loading metadata: ' + (data.error || 'Unknown error') + '
' +
- '
';
- if (window.lucide) lucide.createIcons();
- }
- } catch (err) {
- container.innerHTML =
- '
' +
- '
' +
- '
Error: ' + err.message + '
' +
- '
';
- 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 =
- '
' +
- '
' +
- '
No semantic metadata found
' +
- '
Run \'codex-lens enhance\' to generate metadata for indexed files.
' +
- '
' +
- '
';
- if (window.lucide) lucide.createIcons();
- return;
- }
-
- var rows = entries.map(function(entry, idx) {
- var keywordsHtml = (entry.keywords || []).slice(0, 4).map(function(k) {
- return '
' + escapeHtmlSemantic(k) + '';
- }).join('');
- if ((entry.keywords || []).length > 4) {
- keywordsHtml += '
+' + (entry.keywords.length - 4) + '';
- }
-
- var date = entry.generated_at ? new Date(entry.generated_at * 1000).toLocaleDateString() : '-';
-
- return (
- '
' +
- '| ' +
- ' ' +
- '' +
- '' + escapeHtmlSemantic(entry.file_name || '-') + '' +
- ' ' +
- '' +
- escapeHtmlSemantic(entry.full_path || '-') +
- ' ' +
- ' | ' +
- '' + escapeHtmlSemantic(entry.language || '-') + ' | ' +
- '' + escapeHtmlSemantic((entry.purpose || '-').substring(0, 50)) +
- ((entry.purpose || '').length > 50 ? '...' : '') + ' | ' +
- '' + (keywordsHtml || '-') + ' | ' +
- '' +
- '' +
- escapeHtmlSemantic(entry.llm_tool || '-') +
- '' +
- ' | ' +
- '' + date + ' | ' +
- '
' +
- '
' +
- '' +
- '' +
- ' ' +
- ' Summary' +
- ' ' + escapeHtmlSemantic(entry.summary || 'No summary available') + ' ' +
- ' ' +
- ' ' +
- ' All Keywords' +
- ' ' +
- (entry.keywords || []).map(function(k) {
- return '' + escapeHtmlSemantic(k) + '';
- }).join('') +
- ' ' +
- ' ' +
- ' ' +
- ' ' + (entry.line_count || 0) + ' lines' +
- ' ' + escapeHtmlSemantic(entry.llm_tool || 'Unknown') + '' +
- ' ' + date + '' +
- ' ' +
- ' ' +
- ' | ' +
- '
'
- );
- }).join('');
-
- container.innerHTML =
- '
' +
- '' +
- '' +
- '| File | ' +
- 'Language | ' +
- 'Purpose | ' +
- 'Keywords | ' +
- 'Tool | ' +
- 'Date | ' +
- '
' +
- '' +
- '' + rows + '' +
- '
';
-
- 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);
-}
diff --git a/ccw/src/templates/dashboard-js/i18n.js b/ccw/src/templates/dashboard-js/i18n.js
index d11ad4a8..f3fbb28e 100644
--- a/ccw/src/templates/dashboard-js/i18n.js
+++ b/ccw/src/templates/dashboard-js/i18n.js
@@ -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': '提示词格式',
diff --git a/ccw/src/templates/dashboard-js/views/cli-manager.js b/ccw/src/templates/dashboard-js/views/cli-manager.js
index 6905b042..4180a21c 100644
--- a/ccw/src/templates/dashboard-js/views/cli-manager.js
+++ b/ccw/src/templates/dashboard-js/views/cli-manager.js
@@ -397,13 +397,11 @@ function renderToolsSection() {
// Semantic Search item (only show if CodexLens is installed)
var semanticHtml = '';
if (codexLensStatus.ready) {
- semanticHtml = '