diff --git a/ccw/src/templates/dashboard-js/i18n.js b/ccw/src/templates/dashboard-js/i18n.js
index 517532b4..e77ae22c 100644
--- a/ccw/src/templates/dashboard-js/i18n.js
+++ b/ccw/src/templates/dashboard-js/i18n.js
@@ -1734,7 +1734,9 @@ const i18n = {
'discovery.title': 'Issue Discovery',
'discovery.description': 'Discover potential issues from multiple perspectives',
'discovery.noSessions': 'No discovery sessions',
+ 'discovery.noDiscoveries': 'No discoveries yet',
'discovery.runHint': 'Run /issue:discover to start discovering issues',
+ 'discovery.runCommand': 'Run /issue:discover to start discovering issues',
'discovery.sessions': 'Sessions',
'discovery.findings': 'Findings',
'discovery.phase': 'Phase',
@@ -1769,10 +1771,18 @@ const i18n = {
'discovery.confidence': 'Confidence',
'discovery.suggestedIssue': 'Suggested Issue',
'discovery.externalRef': 'External Reference',
- 'discovery.noFindings': 'No findings in this session',
+ 'discovery.noFindings': 'No findings match your filters',
'discovery.filterPerspective': 'Filter by Perspective',
'discovery.filterPriority': 'Filter by Priority',
'discovery.filterAll': 'All',
+ 'discovery.allPerspectives': 'All Perspectives',
+ 'discovery.allPriorities': 'All Priorities',
+ 'discovery.selectFinding': 'Select a finding to preview',
+ 'discovery.location': 'Location',
+ 'discovery.code': 'Code',
+ 'discovery.impact': 'Impact',
+ 'discovery.recommendation': 'Recommendation',
+ 'discovery.exportAsIssues': 'Export as Issues',
'discovery.deleteSession': 'Delete Session',
'discovery.confirmDelete': 'Are you sure you want to delete this discovery session?',
'discovery.deleted': 'Discovery session deleted',
@@ -3649,7 +3659,9 @@ const i18n = {
'discovery.title': '议题发现',
'discovery.description': '从多个视角发现潜在问题',
'discovery.noSessions': '暂无发现会话',
+ 'discovery.noDiscoveries': '暂无发现',
'discovery.runHint': '运行 /issue:discover 开始发现问题',
+ 'discovery.runCommand': '运行 /issue:discover 开始发现问题',
'discovery.sessions': '会话',
'discovery.findings': '发现',
'discovery.phase': '阶段',
@@ -3684,10 +3696,18 @@ const i18n = {
'discovery.confidence': '置信度',
'discovery.suggestedIssue': '建议议题',
'discovery.externalRef': '外部参考',
- 'discovery.noFindings': '此会话暂无发现',
+ 'discovery.noFindings': '没有匹配的发现',
'discovery.filterPerspective': '按视角筛选',
'discovery.filterPriority': '按优先级筛选',
'discovery.filterAll': '全部',
+ 'discovery.allPerspectives': '所有视角',
+ 'discovery.allPriorities': '所有优先级',
+ 'discovery.selectFinding': '选择一个发现以预览',
+ 'discovery.location': '位置',
+ 'discovery.code': '代码',
+ 'discovery.impact': '影响',
+ 'discovery.recommendation': '建议',
+ 'discovery.exportAsIssues': '导出为议题',
'discovery.deleteSession': '删除会话',
'discovery.confirmDelete': '确定要删除此发现会话吗?',
'discovery.deleted': '发现会话已删除',
diff --git a/ccw/src/templates/dashboard-js/views/codexlens-manager.js b/ccw/src/templates/dashboard-js/views/codexlens-manager.js
index c63c70f1..c62f0198 100644
--- a/ccw/src/templates/dashboard-js/views/codexlens-manager.js
+++ b/ccw/src/templates/dashboard-js/views/codexlens-manager.js
@@ -446,6 +446,12 @@ async function loadSemanticDepsStatus() {
* Build GPU mode selector HTML
*/
function buildGpuModeSelector(gpuInfo) {
+ // Check if DirectML is unavailable due to Python environment
+ var directmlUnavailableReason = null;
+ if (!gpuInfo.available.includes('directml') && gpuInfo.pythonEnv && gpuInfo.pythonEnv.error) {
+ directmlUnavailableReason = gpuInfo.pythonEnv.error;
+ }
+
var modes = [
{
id: 'cpu',
@@ -457,10 +463,13 @@ function buildGpuModeSelector(gpuInfo) {
{
id: 'directml',
label: 'DirectML',
- desc: t('codexlens.directmlModeDesc') || 'Windows GPU (NVIDIA/AMD/Intel)',
+ desc: directmlUnavailableReason
+ ? directmlUnavailableReason
+ : (t('codexlens.directmlModeDesc') || 'Windows GPU (NVIDIA/AMD/Intel)'),
icon: 'cpu',
available: gpuInfo.available.includes('directml'),
- recommended: gpuInfo.mode === 'directml'
+ recommended: gpuInfo.mode === 'directml',
+ warning: directmlUnavailableReason
},
{
id: 'cuda',
@@ -487,6 +496,7 @@ function buildGpuModeSelector(gpuInfo) {
var isDisabled = !mode.available;
var isRecommended = mode.recommended;
var isDefault = mode.id === gpuInfo.mode;
+ var hasWarning = mode.warning;
html +=
'';
});
diff --git a/ccw/src/tools/codex-lens.ts b/ccw/src/tools/codex-lens.ts
index 50ee6f68..19302542 100644
--- a/ccw/src/tools/codex-lens.ts
+++ b/ccw/src/tools/codex-lens.ts
@@ -379,11 +379,63 @@ async function ensureLiteLLMEmbedderReady(): Promise {
*/
type GpuMode = 'cpu' | 'cuda' | 'directml';
+/**
+ * Python environment info for compatibility checks
+ */
+interface PythonEnvInfo {
+ version: string; // e.g., "3.11.5"
+ majorMinor: string; // e.g., "3.11"
+ architecture: number; // 32 or 64
+ compatible: boolean; // true if 64-bit and Python 3.8-3.12
+ error?: string;
+}
+
+/**
+ * Check Python environment in venv for DirectML compatibility
+ * DirectML requires: 64-bit Python, version 3.8-3.12
+ */
+async function checkPythonEnvForDirectML(): Promise {
+ const pythonPath =
+ process.platform === 'win32'
+ ? join(CODEXLENS_VENV, 'Scripts', 'python.exe')
+ : join(CODEXLENS_VENV, 'bin', 'python');
+
+ if (!existsSync(pythonPath)) {
+ return { version: '', majorMinor: '', architecture: 0, compatible: false, error: 'Python not found in venv' };
+ }
+
+ try {
+ // Get Python version and architecture in one call
+ const checkScript = `import sys, struct; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}|{struct.calcsize('P') * 8}")`;
+ const result = execSync(`"${pythonPath}" -c "${checkScript}"`, { encoding: 'utf-8', timeout: 10000 }).trim();
+ const [version, archStr] = result.split('|');
+ const architecture = parseInt(archStr, 10);
+ const [major, minor] = version.split('.').map(Number);
+ const majorMinor = `${major}.${minor}`;
+
+ // DirectML wheels available for Python 3.8-3.12, 64-bit only
+ const versionCompatible = major === 3 && minor >= 8 && minor <= 12;
+ const archCompatible = architecture === 64;
+ const compatible = versionCompatible && archCompatible;
+
+ let error: string | undefined;
+ if (!archCompatible) {
+ error = `Python is ${architecture}-bit. onnxruntime-directml requires 64-bit Python. Please reinstall Python as 64-bit.`;
+ } else if (!versionCompatible) {
+ error = `Python ${majorMinor} is not supported. onnxruntime-directml requires Python 3.8-3.12.`;
+ }
+
+ return { version, majorMinor, architecture, compatible, error };
+ } catch (e) {
+ return { version: '', majorMinor: '', architecture: 0, compatible: false, error: `Failed to check Python: ${(e as Error).message}` };
+ }
+}
+
/**
* Detect available GPU acceleration
* @returns Detected GPU mode and info
*/
-async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]; info: string }> {
+async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]; info: string; pythonEnv?: PythonEnvInfo }> {
const available: GpuMode[] = ['cpu'];
let detectedInfo = 'CPU only';
@@ -402,19 +454,20 @@ async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]
// NVIDIA not available
}
- // On Windows, DirectML is always available if DirectX 12 is supported
+ // On Windows, DirectML requires 64-bit Python 3.8-3.12
+ let pythonEnv: PythonEnvInfo | undefined;
if (process.platform === 'win32') {
- try {
- // Check for DirectX 12 support via dxdiag or registry
- // DirectML works on most modern Windows 10/11 systems
+ pythonEnv = await checkPythonEnvForDirectML();
+ if (pythonEnv.compatible) {
available.push('directml');
if (available.includes('cuda')) {
detectedInfo = 'NVIDIA GPU detected (CUDA & DirectML available)';
} else {
detectedInfo = 'DirectML available (Windows GPU acceleration)';
}
- } catch {
- // DirectML check failed
+ } else if (pythonEnv.error) {
+ // DirectML not available due to Python environment
+ console.log(`[CodexLens] DirectML unavailable: ${pythonEnv.error}`);
}
}
@@ -426,7 +479,7 @@ async function detectGpuSupport(): Promise<{ mode: GpuMode; available: GpuMode[]
recommendedMode = 'cuda';
}
- return { mode: recommendedMode, available, info: detectedInfo };
+ return { mode: recommendedMode, available, info: detectedInfo, pythonEnv };
}
/**
@@ -441,6 +494,19 @@ async function installSemantic(gpuMode: GpuMode = 'cpu'): Promise