mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
✨ feat(settings): improve tool detector display layout (#12906)
* ✨ feat(settings): improve tool detector display layout - Move version to left side with Name, display as Tag - Right side: two lines (Available status + path), right-aligned - Unavailable: single line centered - Add runtime environment detectors (Node, Python, npm) - Add i18n for system tools settings Made-with: Cursor * 🔧 fix(toolDetectors): ensure successful version check for Python runtime - Update pythonDetector to enforce successful invocation of `--version` for confirming usable runtime. - Removed redundant version handling logic to streamline the detection process. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
@@ -18,6 +18,9 @@ import {
|
||||
browserAutomationDetectors,
|
||||
contentSearchDetectors,
|
||||
fileSearchDetectors,
|
||||
type IToolDetector,
|
||||
runtimeEnvironmentDetectors,
|
||||
type ToolCategory,
|
||||
} from '@/modules/toolDetectors';
|
||||
import type { IServiceModule } from '@/services';
|
||||
import { createLogger } from '@/utils/logger';
|
||||
@@ -187,24 +190,20 @@ export class App {
|
||||
private registerBuiltinToolDetectors() {
|
||||
logger.debug('Registering built-in tool detectors');
|
||||
|
||||
// Register content search tools (rg, ag, grep)
|
||||
for (const detector of contentSearchDetectors) {
|
||||
this.toolDetectorManager.register(detector, 'content-search');
|
||||
}
|
||||
const detectorCategories: Partial<Record<ToolCategory, IToolDetector[]>> = {
|
||||
'runtime-environment': runtimeEnvironmentDetectors,
|
||||
'ast-search': astSearchDetectors,
|
||||
'browser-automation': browserAutomationDetectors,
|
||||
'content-search': contentSearchDetectors,
|
||||
'file-search': fileSearchDetectors,
|
||||
};
|
||||
|
||||
// Register AST-based code search tools (ast-grep)
|
||||
for (const detector of astSearchDetectors) {
|
||||
this.toolDetectorManager.register(detector, 'ast-search');
|
||||
}
|
||||
|
||||
// Register file search tools (mdfind, fd, find)
|
||||
for (const detector of fileSearchDetectors) {
|
||||
this.toolDetectorManager.register(detector, 'file-search');
|
||||
}
|
||||
|
||||
// Register browser automation tools (agent-browser)
|
||||
for (const detector of browserAutomationDetectors) {
|
||||
this.toolDetectorManager.register(detector, 'browser-automation');
|
||||
for (const [category, detectors] of Object.entries(detectorCategories)) {
|
||||
if (detectors) {
|
||||
for (const detector of detectors) {
|
||||
this.toolDetectorManager.register(detector, category as ToolCategory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -40,6 +40,7 @@ export type ToolCategory =
|
||||
| 'ast-search'
|
||||
| 'file-search'
|
||||
| 'browser-automation'
|
||||
| 'runtime-environment'
|
||||
| 'system'
|
||||
| 'custom';
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
export { browserAutomationDetectors } from './agentBrowserDetectors';
|
||||
export { astSearchDetectors, contentSearchDetectors } from './contentSearchDetectors';
|
||||
export { fileSearchDetectors } from './fileSearchDetectors';
|
||||
export { runtimeEnvironmentDetectors } from './runtimeEnvironmentDetectors';
|
||||
|
||||
// Re-export types for convenience
|
||||
export type {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { exec } from 'node:child_process';
|
||||
import { platform } from 'node:os';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import type { IToolDetector, ToolStatus } from '@/core/infrastructure/ToolDetectorManager';
|
||||
import { createCommandDetector } from '@/core/infrastructure/ToolDetectorManager';
|
||||
|
||||
const execPromise = promisify(exec);
|
||||
|
||||
/**
|
||||
* Node.js runtime detector
|
||||
*/
|
||||
export const nodeDetector: IToolDetector = createCommandDetector('node', {
|
||||
description: 'Node.js - JavaScript runtime',
|
||||
priority: 1,
|
||||
});
|
||||
|
||||
/**
|
||||
* NPM package manager detector
|
||||
*/
|
||||
export const npmDetector: IToolDetector = createCommandDetector('npm', {
|
||||
description: 'npm - Node.js package manager',
|
||||
priority: 2,
|
||||
});
|
||||
|
||||
/**
|
||||
* Python runtime detector
|
||||
* Tries python3 (Unix) first, then python (cross-platform)
|
||||
*/
|
||||
export const pythonDetector: IToolDetector = {
|
||||
description: 'Python - programming language runtime',
|
||||
async detect(): Promise<ToolStatus> {
|
||||
const commands = platform() === 'win32' ? ['python', 'py'] : ['python3', 'python'];
|
||||
|
||||
for (const cmd of commands) {
|
||||
try {
|
||||
const whichCmd = platform() === 'win32' ? 'where' : 'which';
|
||||
const { stdout: pathOut } = await execPromise(`${whichCmd} ${cmd}`, { timeout: 3000 });
|
||||
const toolPath = pathOut.trim().split('\n')[0];
|
||||
|
||||
// Must successfully invoke --version to confirm usable runtime (e.g. avoid
|
||||
// Windows Microsoft Store alias which is found by where but fails to run)
|
||||
const { stdout: versionOut } = await execPromise(`${cmd} --version`, {
|
||||
timeout: 3000,
|
||||
});
|
||||
const version = versionOut.trim().split('\n')[0];
|
||||
|
||||
return {
|
||||
available: true,
|
||||
path: toolPath,
|
||||
version,
|
||||
};
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
available: false,
|
||||
};
|
||||
},
|
||||
name: 'python',
|
||||
priority: 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* All runtime environment detectors
|
||||
*/
|
||||
export const runtimeEnvironmentDetectors: IToolDetector[] = [
|
||||
nodeDetector,
|
||||
npmDetector,
|
||||
pythonDetector,
|
||||
];
|
||||
Reference in New Issue
Block a user