diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index ac80dac3..a6a997e1 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -6,6 +6,7 @@ import { Bus } from "../bus" const SUPPORTED_IDES = [ { name: "Windsurf" as const, cmd: "windsurf" }, + { name: "Visual Studio Code - Insiders" as const, cmd: "code-insiders" }, { name: "Visual Studio Code" as const, cmd: "code" }, { name: "Cursor" as const, cmd: "cursor" }, { name: "VSCodium" as const, cmd: "codium" }, @@ -43,7 +44,10 @@ export namespace Ide { } export function alreadyInstalled() { - return process.env["OPENCODE_CALLER"] === "vscode" + return ( + process.env["OPENCODE_CALLER"] === "vscode" || + process.env["OPENCODE_CALLER"] === "vscode-insiders" + ) } export async function install(ide: (typeof SUPPORTED_IDES)[number]["name"]) { diff --git a/packages/opencode/test/ide/ide.test.ts b/packages/opencode/test/ide/ide.test.ts new file mode 100644 index 00000000..9678aa90 --- /dev/null +++ b/packages/opencode/test/ide/ide.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, test, afterEach } from "bun:test" +import { Ide } from "../../src/ide" + +describe("ide", () => { + const original = structuredClone(process.env) + + afterEach(() => { + Object.keys(process.env).forEach((key) => { + delete process.env[key] + }) + Object.assign(process.env, original) + }) + + test("should detect Visual Studio Code", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Visual Studio Code") + }) + + test("should detect Visual Studio Code Insiders", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Visual Studio Code - Insiders") + }) + + test("should detect Cursor", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Cursor.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Cursor") + }) + + test("should detect VSCodium", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/VSCodium.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("VSCodium") + }) + + test("should detect Windsurf", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = + "/path/to/Windsurf.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("Windsurf") + }) + + test("should return unknown when TERM_PROGRAM is not vscode", () => { + process.env["TERM_PROGRAM"] = "iTerm2" + process.env["GIT_ASKPASS"] = + "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/extensions/git/dist/askpass.sh" + + expect(Ide.ide()).toBe("unknown") + }) + + test("should return unknown when GIT_ASKPASS does not contain IDE name", () => { + process.env["TERM_PROGRAM"] = "vscode" + process.env["GIT_ASKPASS"] = "/path/to/unknown/askpass.sh" + + expect(Ide.ide()).toBe("unknown") + }) + + test("should recognize vscode-insiders OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "vscode-insiders" + + expect(Ide.alreadyInstalled()).toBe(true) + }) + + test("should recognize vscode OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "vscode" + + expect(Ide.alreadyInstalled()).toBe(true) + }) + + test("should return false for unknown OPENCODE_CALLER", () => { + process.env["OPENCODE_CALLER"] = "unknown" + + expect(Ide.alreadyInstalled()).toBe(false) + }) +})