Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions apps/web/client/src/components/store/editor/ide/ide-detection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Utility to detect if VS Code or Cursor is installed on the user's system.
* Used to warn users when "Open in Code" is clicked but no supported IDE is found.
*/

const VSCODE_COMMAND = 'code';
const CURSOR_COMMAND = 'cursor';

/**
* Check if a command is available in the system PATH.
* This only works in Node.js environment (server-side or Electron).
* In browser environment, this will always return false.
*/
async function isCommandAvailable(command: string): Promise<boolean> {
// Only run in Node.js environment
if (typeof window !== 'undefined') {
// Browser environment - cannot detect installed applications
// Return true to avoid false warnings (user might have IDE installed)
return true;
}

try {
const { execSync } = await import('child_process');
execSync(`which ${command}`, { stdio: 'ignore' });
Comment on lines +23 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make command detection cross-platform (Windows currently false-negatives).

Line 24 uses which, which is Unix-specific and will fail in typical Windows shells even when VS Code/Cursor is installed.

Proposed fix
-        const { execSync } = await import('child_process');
-        execSync(`which ${command}`, { stdio: 'ignore' });
+        const { execFileSync } = await import('child_process');
+        const lookupCmd = process.platform === 'win32' ? 'where' : 'which';
+        execFileSync(lookupCmd, [command], { stdio: 'ignore' });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { execSync } = await import('child_process');
execSync(`which ${command}`, { stdio: 'ignore' });
const { execFileSync } = await import('child_process');
const lookupCmd = process.platform === 'win32' ? 'where' : 'which';
execFileSync(lookupCmd, [command], { stdio: 'ignore' });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/client/src/components/store/editor/ide/ide-detection.ts` around
lines 23 - 24, The platform-specific check uses `which ${command}` which fails
on Windows; update the detection logic around the dynamic import of `execSync`
to pick the right tool based on platform (use `where ${command}` when
process.platform === 'win32`, and `which ${command}` otherwise), call execSync
with the same { stdio: 'ignore' } and catch errors to return false, and keep
referencing the existing `execSync` import and `command` variable so behavior is
unchanged on Unix but works on Windows too.

return true;
} catch {
return false;
}
}

/**
* Detect if VS Code is installed.
*/
export async function isVSCodeInstalled(): Promise<boolean> {
return isCommandAvailable(VSCODE_COMMAND);
}

/**
* Detect if Cursor is installed.
*/
export async function isCursorInstalled(): Promise<boolean> {
return isCommandAvailable(CURSOR_COMMAND);
}

/**
* Check if any supported IDE (VS Code or Cursor) is installed.
* Returns an object with detection results and a suggestion message if none is found.
*/
export async function detectSupportedIDE(): Promise<{
vsCodeInstalled: boolean;
cursorInstalled: boolean;
anyInstalled: boolean;
message: string | null;
}> {
const vsCodeInstalled = await isVSCodeInstalled();
const cursorInstalled = await isCursorInstalled();
const anyInstalled = vsCodeInstalled || cursorInstalled;

let message = null;
if (!anyInstalled) {
message = 'No supported IDE found. Please install VS Code or Cursor to use "Open in Code" feature.';
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

return {
vsCodeInstalled,
cursorInstalled,
anyInstalled,
message,
};
}
10 changes: 10 additions & 0 deletions apps/web/client/src/components/store/editor/ide/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { EditorMode, type CodeNavigationTarget } from "@onlook/models";
import { makeAutoObservable } from "mobx";
import type { EditorEngine } from "../engine";
import { detectSupportedIDE } from './ide-detection';
import { toast } from "@onlook/ui/sonner";

export class IdeManager {
private _codeNavigationOverride: CodeNavigationTarget | null = null;
Expand All @@ -15,6 +17,14 @@ export class IdeManager {

async openCodeBlock(oid: string) {
try {
// Check if a supported IDE is installed
const ideDetection = await detectSupportedIDE();
if (!ideDetection.anyInstalled) {
toast.warning(ideDetection.message || 'No supported IDE found. Please install VS Code or Cursor.');
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
console.warn('[IdeManager] No supported IDE found');
// Continue anyway - the code panel will still work
}

// Get the current branch data
const activeBranchId = this.editorEngine.branches.activeBranch?.id;
if (!activeBranchId) {
Expand Down