import assert from "node:assert/strict";import fs from "node:fs";import os from "node:os";import path from "node:path"; import { describe, expect, it } from "vitest"; import { isCommandAvailable, launchDetached, resolveBrowserLaunch, resolveAvailableEditors, resolveEditorLaunch,} from "./open";import { Effect } from "effect"; describe("resolveEditorLaunch", () => { it("returns commands for command-based editors", async () => { const cursorLaunch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "cursor" }, { platform: "darwin" }, ), ); assert.deepEqual(cursorLaunch, { command: "cursor", args: ["/tmp/workspace"], }); const vscodeLaunch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "vscode" }, { platform: "darwin" }, ), ); assert.deepEqual(vscodeLaunch, { command: "code", args: ["/tmp/workspace"], }); const zedLaunch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "zed" }, { platform: "darwin" }, ), ); assert.deepEqual(zedLaunch, { command: "zed", args: ["/tmp/workspace"], }); }); it("uses --goto when editor supports line/column suffixes", async () => { const lineOnly = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace/AGENTS.md:48", editor: "cursor" }, { platform: "darwin" }, ), ); assert.deepEqual(lineOnly, { command: "cursor", args: ["--goto", "/tmp/workspace/AGENTS.md:48"], }); const lineAndColumn = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace/src/open.ts:71:5", editor: "cursor" }, { platform: "darwin" }, ), ); assert.deepEqual(lineAndColumn, { command: "cursor", args: ["--goto", "/tmp/workspace/src/open.ts:71:5"], }); const vscodeLineAndColumn = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace/src/open.ts:71:5", editor: "vscode" }, { platform: "darwin" }, ), ); assert.deepEqual(vscodeLineAndColumn, { command: "code", args: ["--goto", "/tmp/workspace/src/open.ts:71:5"], }); const zedLineAndColumn = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace/src/open.ts:71:5", editor: "zed" }, { platform: "darwin" }, ), ); assert.deepEqual(zedLineAndColumn, { command: "zed", args: ["/tmp/workspace/src/open.ts:71:5"], }); }); it("maps file-manager editor to OS open commands", async () => { const launch1 = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "file-manager" }, { platform: "darwin" }, ), ); assert.deepEqual(launch1, { command: "open", args: ["/tmp/workspace"], }); const launch2 = await Effect.runPromise( resolveEditorLaunch( { cwd: "C:\\workspace", editor: "file-manager" }, { platform: "win32" }, ), ); assert.deepEqual(launch2, { command: "explorer", args: ["C:\\workspace"], }); const launch3 = await Effect.runPromise( resolveEditorLaunch( { cwd: "/tmp/workspace", editor: "file-manager" }, { platform: "linux" }, ), ); assert.deepEqual(launch3, { command: "xdg-open", args: ["/tmp/workspace"], }); }); it("prefers linux editor shims in wsl-hosted mode when available", async () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-linux-editor-")); try { fs.writeFileSync(path.join(dir, "code"), "#!/bin/sh\n", { mode: 0o755 }); const launch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/home/julius/project/src/open.ts:71:5", editor: "vscode" }, { platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, }, ), ); assert.deepEqual(launch, { command: "code", args: ["--goto", "/home/julius/project/src/open.ts:71:5"], }); } finally { fs.rmSync(dir, { recursive: true, force: true }); } }); it("falls back to windows editor executables in wsl-hosted mode", async () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-win-editor-")); try { fs.writeFileSync(path.join(dir, "code.exe"), "MZ", { mode: 0o755 }); const launch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/home/julius/project/src/open.ts:71:5", editor: "vscode" }, { platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, translateWslPathToWindows: (target) => target.replace( "/home/julius/project", "\\\\wsl.localhost\\Ubuntu\\home\\julius\\project", ), }, ), ); assert.deepEqual(launch, { command: "code.exe", args: [ "--goto", "\\\\wsl.localhost\\Ubuntu\\home\\julius\\project/src/open.ts:71:5", ], }); } finally { fs.rmSync(dir, { recursive: true, force: true }); } }); it("translates file-manager targets for wsl-hosted mode", async () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-file-manager-")); try { fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 }); const launch = await Effect.runPromise( resolveEditorLaunch( { cwd: "/home/julius/project/src/open.ts:71:5", editor: "file-manager" }, { platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, translateWslPathToWindows: (target) => target.replace( "/home/julius/project", "\\\\wsl.localhost\\Ubuntu\\home\\julius\\project", ), }, ), ); assert.deepEqual(launch, { command: "explorer.exe", args: ["\\\\wsl.localhost\\Ubuntu\\home\\julius\\project/src/open.ts"], }); } finally { fs.rmSync(dir, { recursive: true, force: true }); } });}); describe("launchDetached", () => { it("resolves when command can be spawned", async () => { await expect( Effect.runPromise( launchDetached({ command: process.execPath, args: ["-e", "process.exit(0)"], }), ), ).resolves.toBeUndefined(); }); it("rejects when command does not exist", async () => { const result = await Effect.runPromise( launchDetached({ command: `t3code-no-such-command-${Date.now()}`, args: [], }).pipe(Effect.result), ); assert.equal(result._tag, "Failure"); });}); describe("isCommandAvailable", () => { function withTempDir(run: (dir: string) => void): void { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-")); try { run(dir); } finally { fs.rmSync(dir, { recursive: true, force: true }); } } it("resolves win32 commands with PATHEXT", () => { withTempDir((dir) => { fs.writeFileSync(path.join(dir, "code.CMD"), "@echo off\r\n", "utf8"); const env = { PATH: dir, PATHEXT: ".COM;.EXE;.BAT;.CMD", } satisfies NodeJS.ProcessEnv; assert.equal(isCommandAvailable("code", { platform: "win32", env }), true); }); }); it("returns false when a command is not on PATH", () => { const env = { PATH: "", PATHEXT: ".COM;.EXE;.BAT;.CMD", } satisfies NodeJS.ProcessEnv; assert.equal(isCommandAvailable("definitely-not-installed", { platform: "win32", env }), false); }); it("does not treat bare files without executable extension as available on win32", () => { withTempDir((dir) => { fs.writeFileSync(path.join(dir, "npm"), "echo nope\r\n", "utf8"); const env = { PATH: dir, PATHEXT: ".COM;.EXE;.BAT;.CMD", } satisfies NodeJS.ProcessEnv; assert.equal(isCommandAvailable("npm", { platform: "win32", env }), false); }); }); it("appends PATHEXT for commands with non-executable extensions on win32", () => { withTempDir((dir) => { fs.writeFileSync(path.join(dir, "my.tool.CMD"), "@echo off\r\n", "utf8"); const env = { PATH: dir, PATHEXT: ".COM;.EXE;.BAT;.CMD", } satisfies NodeJS.ProcessEnv; assert.equal(isCommandAvailable("my.tool", { platform: "win32", env }), true); }); }); it("uses platform-specific PATH delimiter for platform overrides", () => { withTempDir((firstDir) => { withTempDir((secondDir) => { fs.writeFileSync(path.join(secondDir, "code.CMD"), "@echo off\r\n", "utf8"); const env = { PATH: `${firstDir};${secondDir}`, PATHEXT: ".COM;.EXE;.BAT;.CMD", } satisfies NodeJS.ProcessEnv; assert.equal(isCommandAvailable("code", { platform: "win32", env }), true); }); }); });}); describe("resolveAvailableEditors", () => { it("returns only editors whose launch commands are available", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-")); try { fs.writeFileSync(path.join(dir, "cursor.CMD"), "@echo off\r\n", "utf8"); fs.writeFileSync(path.join(dir, "explorer.EXE"), "MZ", "utf8"); const editors = resolveAvailableEditors({ platform: "win32", env: { PATH: dir, PATHEXT: ".COM;.EXE;.BAT;.CMD", }, }); assert.deepEqual(editors, ["cursor", "file-manager"]); } finally { fs.rmSync(dir, { recursive: true, force: true }); } }); it("accepts windows editor executables in wsl-hosted mode", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-wsl-")); try { fs.writeFileSync(path.join(dir, "code.exe"), "MZ", { mode: 0o755 }); fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 }); const editors = resolveAvailableEditors({ platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, }); assert.deepEqual(editors, ["vscode", "file-manager"]); } finally { fs.rmSync(dir, { recursive: true, force: true }); } });}); describe("resolveBrowserLaunch", () => { it("prefers wslview in wsl-hosted mode", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-browser-wsl-")); try { fs.writeFileSync(path.join(dir, "wslview"), "#!/bin/sh\n", { mode: 0o755 }); const launch = resolveBrowserLaunch("http://localhost:3773", { platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, }); assert.deepEqual(launch, { command: "wslview", args: ["http://localhost:3773"], }); } finally { fs.rmSync(dir, { recursive: true, force: true }); } }); it("falls back to explorer.exe in wsl-hosted mode", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-browser-wsl-explorer-")); try { fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 }); const launch = resolveBrowserLaunch("http://localhost:3773", { platform: "linux", runtimeEnvironment: { platform: "linux", pathStyle: "posix", isWsl: true, windowsInteropMode: "wsl-hosted", wslDistroName: "Ubuntu", }, env: { PATH: dir, }, }); assert.deepEqual(launch, { command: "explorer.exe", args: ["http://localhost:3773"], }); } finally { fs.rmSync(dir, { recursive: true, force: true }); } });});
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
isCommandAvailable,
launchDetached,
resolveBrowserLaunch,
resolveAvailableEditors,
resolveEditorLaunch,
} from "./open";
import { Effect } from "effect";
describe("resolveEditorLaunch", () => {
it("returns commands for command-based editors", async () => {
const cursorLaunch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "cursor" },
{ platform: "darwin" },
),
);
assert.deepEqual(cursorLaunch, {
command: "cursor",
args: ["/tmp/workspace"],
});
const vscodeLaunch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "vscode" },
{ platform: "darwin" },
),
);
assert.deepEqual(vscodeLaunch, {
command: "code",
args: ["/tmp/workspace"],
});
const zedLaunch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "zed" },
{ platform: "darwin" },
),
);
assert.deepEqual(zedLaunch, {
command: "zed",
args: ["/tmp/workspace"],
});
});
it("uses --goto when editor supports line/column suffixes", async () => {
const lineOnly = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace/AGENTS.md:48", editor: "cursor" },
{ platform: "darwin" },
),
);
assert.deepEqual(lineOnly, {
command: "cursor",
args: ["--goto", "/tmp/workspace/AGENTS.md:48"],
});
const lineAndColumn = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace/src/open.ts:71:5", editor: "cursor" },
{ platform: "darwin" },
),
);
assert.deepEqual(lineAndColumn, {
command: "cursor",
args: ["--goto", "/tmp/workspace/src/open.ts:71:5"],
});
const vscodeLineAndColumn = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace/src/open.ts:71:5", editor: "vscode" },
{ platform: "darwin" },
),
);
assert.deepEqual(vscodeLineAndColumn, {
command: "code",
args: ["--goto", "/tmp/workspace/src/open.ts:71:5"],
});
const zedLineAndColumn = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace/src/open.ts:71:5", editor: "zed" },
{ platform: "darwin" },
),
);
assert.deepEqual(zedLineAndColumn, {
command: "zed",
args: ["/tmp/workspace/src/open.ts:71:5"],
});
});
it("maps file-manager editor to OS open commands", async () => {
const launch1 = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "file-manager" },
{ platform: "darwin" },
),
);
assert.deepEqual(launch1, {
command: "open",
args: ["/tmp/workspace"],
});
const launch2 = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "C:\\workspace", editor: "file-manager" },
{ platform: "win32" },
),
);
assert.deepEqual(launch2, {
command: "explorer",
args: ["C:\\workspace"],
});
const launch3 = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "file-manager" },
{ platform: "linux" },
),
);
assert.deepEqual(launch3, {
command: "xdg-open",
args: ["/tmp/workspace"],
});
});
it("prefers linux editor shims in wsl-hosted mode when available", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-linux-editor-"));
try {
fs.writeFileSync(path.join(dir, "code"), "#!/bin/sh\n", { mode: 0o755 });
const launch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/home/julius/project/src/open.ts:71:5", editor: "vscode" },
{
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
},
),
);
assert.deepEqual(launch, {
command: "code",
args: ["--goto", "/home/julius/project/src/open.ts:71:5"],
});
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
it("falls back to windows editor executables in wsl-hosted mode", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-win-editor-"));
try {
fs.writeFileSync(path.join(dir, "code.exe"), "MZ", { mode: 0o755 });
const launch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/home/julius/project/src/open.ts:71:5", editor: "vscode" },
{
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
translateWslPathToWindows: (target) =>
target.replace(
"/home/julius/project",
"\\\\wsl.localhost\\Ubuntu\\home\\julius\\project",
),
},
),
);
assert.deepEqual(launch, {
command: "code.exe",
args: [
"--goto",
"\\\\wsl.localhost\\Ubuntu\\home\\julius\\project/src/open.ts:71:5",
],
});
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
it("translates file-manager targets for wsl-hosted mode", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-wsl-file-manager-"));
try {
fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 });
const launch = await Effect.runPromise(
resolveEditorLaunch(
{ cwd: "/home/julius/project/src/open.ts:71:5", editor: "file-manager" },
{
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
translateWslPathToWindows: (target) =>
target.replace(
"/home/julius/project",
"\\\\wsl.localhost\\Ubuntu\\home\\julius\\project",
),
},
),
);
assert.deepEqual(launch, {
command: "explorer.exe",
args: ["\\\\wsl.localhost\\Ubuntu\\home\\julius\\project/src/open.ts"],
});
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
});
describe("launchDetached", () => {
it("resolves when command can be spawned", async () => {
await expect(
Effect.runPromise(
launchDetached({
command: process.execPath,
args: ["-e", "process.exit(0)"],
}),
),
).resolves.toBeUndefined();
});
it("rejects when command does not exist", async () => {
const result = await Effect.runPromise(
launchDetached({
command: `t3code-no-such-command-${Date.now()}`,
args: [],
}).pipe(Effect.result),
);
assert.equal(result._tag, "Failure");
});
});
describe("isCommandAvailable", () => {
function withTempDir(run: (dir: string) => void): void {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-open-"));
try {
run(dir);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
}
it("resolves win32 commands with PATHEXT", () => {
withTempDir((dir) => {
fs.writeFileSync(path.join(dir, "code.CMD"), "@echo off\r\n", "utf8");
const env = {
PATH: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;
assert.equal(isCommandAvailable("code", { platform: "win32", env }), true);
});
});
it("returns false when a command is not on PATH", () => {
const env = {
PATH: "",
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;
assert.equal(isCommandAvailable("definitely-not-installed", { platform: "win32", env }), false);
});
it("does not treat bare files without executable extension as available on win32", () => {
withTempDir((dir) => {
fs.writeFileSync(path.join(dir, "npm"), "echo nope\r\n", "utf8");
const env = {
PATH: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;
assert.equal(isCommandAvailable("npm", { platform: "win32", env }), false);
});
});
it("appends PATHEXT for commands with non-executable extensions on win32", () => {
withTempDir((dir) => {
fs.writeFileSync(path.join(dir, "my.tool.CMD"), "@echo off\r\n", "utf8");
const env = {
PATH: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;
assert.equal(isCommandAvailable("my.tool", { platform: "win32", env }), true);
});
});
it("uses platform-specific PATH delimiter for platform overrides", () => {
withTempDir((firstDir) => {
withTempDir((secondDir) => {
fs.writeFileSync(path.join(secondDir, "code.CMD"), "@echo off\r\n", "utf8");
const env = {
PATH: `${firstDir};${secondDir}`,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
} satisfies NodeJS.ProcessEnv;
assert.equal(isCommandAvailable("code", { platform: "win32", env }), true);
});
});
});
});
describe("resolveAvailableEditors", () => {
it("returns only editors whose launch commands are available", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-"));
try {
fs.writeFileSync(path.join(dir, "cursor.CMD"), "@echo off\r\n", "utf8");
fs.writeFileSync(path.join(dir, "explorer.EXE"), "MZ", "utf8");
const editors = resolveAvailableEditors({
platform: "win32",
env: {
PATH: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
},
});
assert.deepEqual(editors, ["cursor", "file-manager"]);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
it("accepts windows editor executables in wsl-hosted mode", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-editors-wsl-"));
try {
fs.writeFileSync(path.join(dir, "code.exe"), "MZ", { mode: 0o755 });
fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 });
const editors = resolveAvailableEditors({
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
});
assert.deepEqual(editors, ["vscode", "file-manager"]);
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
});
describe("resolveBrowserLaunch", () => {
it("prefers wslview in wsl-hosted mode", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-browser-wsl-"));
try {
fs.writeFileSync(path.join(dir, "wslview"), "#!/bin/sh\n", { mode: 0o755 });
const launch = resolveBrowserLaunch("http://localhost:3773", {
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
});
assert.deepEqual(launch, {
command: "wslview",
args: ["http://localhost:3773"],
});
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
it("falls back to explorer.exe in wsl-hosted mode", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "t3-browser-wsl-explorer-"));
try {
fs.writeFileSync(path.join(dir, "explorer.exe"), "MZ", { mode: 0o755 });
const launch = resolveBrowserLaunch("http://localhost:3773", {
platform: "linux",
runtimeEnvironment: {
platform: "linux",
pathStyle: "posix",
isWsl: true,
windowsInteropMode: "wsl-hosted",
wslDistroName: "Ubuntu",
},
env: {
PATH: dir,
},
});
assert.deepEqual(launch, {
command: "explorer.exe",
args: ["http://localhost:3773"],
});
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
});