802 lines · 27.0 KB · TypeScript
RawDownload
import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import { assertSuccess } from "@effect/vitest/utils";import * as Effect from "effect/Effect";import * as Encoding from "effect/Encoding";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Path from "effect/Path";import * as Random from "effect/Random";import * as Sink from "effect/Sink";import * as Stream from "effect/Stream";import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import {  isCommandAvailable,  launchBrowser,  launchEditorProcess,  resolveAvailableEditors,  resolveBrowserLaunch,  resolveEditorLaunch,} from "./externalLauncher.ts"; function encodeUtf16LeBase64(input: string): string {  const bytes = new Uint8Array(input.length * 2);  for (let index = 0; index < input.length; index += 1) {    const code = input.charCodeAt(index);    bytes[index * 2] = code & 0xff;    bytes[index * 2 + 1] = code >>> 8;  }  return Encoding.encodeBase64(bytes);} function makeMockDetachedHandle(onUnref: () => void = () => undefined) {  return ChildProcessSpawner.makeHandle({    pid: ChildProcessSpawner.ProcessId(1),    exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(0)),    isRunning: Effect.succeed(true),    kill: () => Effect.void,    unref: Effect.sync(() => {      onUnref();      return Effect.void;    }),    stdin: Sink.drain,    stdout: Stream.empty,    stderr: Stream.empty,    all: Stream.empty,    getInputFd: () => Sink.drain,    getOutputFd: () => Stream.empty,  });} it.layer(NodeServices.layer)("resolveEditorLaunch", (it) => {  it.effect("returns commands for command-based editors", () =>    Effect.gen(function* () {      const antigravityLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "antigravity" },        "darwin",        { PATH: "" },      );      assert.deepEqual(antigravityLaunch, {        command: "agy",        args: ["/tmp/workspace"],      });       const cursorLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "cursor" },        "darwin",        { PATH: "" },      );      assert.deepEqual(cursorLaunch, {        command: "cursor",        args: ["/tmp/workspace"],      });       const traeLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "trae" },        "darwin",      );      assert.deepEqual(traeLaunch, {        command: "trae",        args: ["/tmp/workspace"],      });       const kiroLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "kiro" },        "darwin",        { PATH: "" },      );      assert.deepEqual(kiroLaunch, {        command: "kiro",        args: ["ide", "/tmp/workspace"],      });       const vscodeLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "vscode" },        "darwin",        { PATH: "" },      );      assert.deepEqual(vscodeLaunch, {        command: "code",        args: ["/tmp/workspace"],      });       const vscodeInsidersLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "vscode-insiders" },        "darwin",      );      assert.deepEqual(vscodeInsidersLaunch, {        command: "code-insiders",        args: ["/tmp/workspace"],      });       const vscodiumLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "vscodium" },        "darwin",      );      assert.deepEqual(vscodiumLaunch, {        command: "codium",        args: ["/tmp/workspace"],      });       const zedLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "zed" },        "darwin",        { PATH: "" },      );      assert.deepEqual(zedLaunch, {        command: "zed",        args: ["/tmp/workspace"],      });       const ideaLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "idea" },        "darwin",      );      assert.deepEqual(ideaLaunch, {        command: "idea",        args: ["/tmp/workspace"],      });       const aquaLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "aqua" },        "darwin",      );      assert.deepEqual(aquaLaunch, {        command: "aqua",        args: ["/tmp/workspace"],      });       const clionLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "clion" },        "darwin",      );      assert.deepEqual(clionLaunch, {        command: "clion",        args: ["/tmp/workspace"],      });       const datagripLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "datagrip" },        "darwin",      );      assert.deepEqual(datagripLaunch, {        command: "datagrip",        args: ["/tmp/workspace"],      });       const dataspellLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "dataspell" },        "darwin",      );      assert.deepEqual(dataspellLaunch, {        command: "dataspell",        args: ["/tmp/workspace"],      });       const golandLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "goland" },        "darwin",      );      assert.deepEqual(golandLaunch, {        command: "goland",        args: ["/tmp/workspace"],      });       const phpstormLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "phpstorm" },        "darwin",      );      assert.deepEqual(phpstormLaunch, {        command: "phpstorm",        args: ["/tmp/workspace"],      });       const pycharmLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "pycharm" },        "darwin",      );      assert.deepEqual(pycharmLaunch, {        command: "pycharm",        args: ["/tmp/workspace"],      });       const riderLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "rider" },        "darwin",      );      assert.deepEqual(riderLaunch, {        command: "rider",        args: ["/tmp/workspace"],      });       const rubymineLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "rubymine" },        "darwin",      );      assert.deepEqual(rubymineLaunch, {        command: "rubymine",        args: ["/tmp/workspace"],      });       const rustroverLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "rustrover" },        "darwin",      );      assert.deepEqual(rustroverLaunch, {        command: "rustrover",        args: ["/tmp/workspace"],      });       const webstormLaunch = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "webstorm" },        "darwin",      );      assert.deepEqual(webstormLaunch, {        command: "webstorm",        args: ["/tmp/workspace"],      });    }),  );   it.effect("applies launch-style-specific navigation arguments", () =>    Effect.gen(function* () {      const lineOnly = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/AGENTS.md:48", editor: "cursor" },        "darwin",        { PATH: "" },      );      assert.deepEqual(lineOnly, {        command: "cursor",        args: ["--goto", "/tmp/workspace/AGENTS.md:48"],      });       const lineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "cursor" },        "darwin",        { PATH: "" },      );      assert.deepEqual(lineAndColumn, {        command: "cursor",        args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const traeLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "trae" },        "darwin",      );      assert.deepEqual(traeLineAndColumn, {        command: "trae",        args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const kiroLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "kiro" },        "darwin",        { PATH: "" },      );      assert.deepEqual(kiroLineAndColumn, {        command: "kiro",        args: ["ide", "--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const vscodeLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode" },        "darwin",        { PATH: "" },      );      assert.deepEqual(vscodeLineAndColumn, {        command: "code",        args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const vscodeInsidersLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscode-insiders" },        "darwin",      );      assert.deepEqual(vscodeInsidersLineAndColumn, {        command: "code-insiders",        args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const vscodiumLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "vscodium" },        "darwin",      );      assert.deepEqual(vscodiumLineAndColumn, {        command: "codium",        args: ["--goto", "/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const zedLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "zed" },        "darwin",        { PATH: "" },      );      assert.deepEqual(zedLineAndColumn, {        command: "zed",        args: ["/tmp/workspace/src/process/externalLauncher.ts:71:5"],      });       const zedLineOnly = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/AGENTS.md:48", editor: "zed" },        "darwin",        { PATH: "" },      );      assert.deepEqual(zedLineOnly, {        command: "zed",        args: ["/tmp/workspace/AGENTS.md:48"],      });       const ideaLineOnly = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/AGENTS.md:48", editor: "idea" },        "darwin",      );      assert.deepEqual(ideaLineOnly, {        command: "idea",        args: ["--line", "48", "/tmp/workspace/AGENTS.md"],      });       const ideaLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "idea" },        "darwin",      );      assert.deepEqual(ideaLineAndColumn, {        command: "idea",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const aquaLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "aqua" },        "darwin",      );      assert.deepEqual(aquaLineAndColumn, {        command: "aqua",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const clionLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "clion" },        "darwin",      );      assert.deepEqual(clionLineAndColumn, {        command: "clion",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const datagripLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "datagrip" },        "darwin",      );      assert.deepEqual(datagripLineAndColumn, {        command: "datagrip",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const dataspellLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "dataspell" },        "darwin",      );      assert.deepEqual(dataspellLineAndColumn, {        command: "dataspell",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const golandLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "goland" },        "darwin",      );      assert.deepEqual(golandLineAndColumn, {        command: "goland",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const phpstormLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "phpstorm" },        "darwin",      );      assert.deepEqual(phpstormLineAndColumn, {        command: "phpstorm",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const pycharmLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "pycharm" },        "darwin",      );      assert.deepEqual(pycharmLineAndColumn, {        command: "pycharm",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const riderLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rider" },        "darwin",      );      assert.deepEqual(riderLineAndColumn, {        command: "rider",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const rubymineLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rubymine" },        "darwin",      );      assert.deepEqual(rubymineLineAndColumn, {        command: "rubymine",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const rustroverLineAndColumn = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/src/process/externalLauncher.ts:71:5", editor: "rustrover" },        "darwin",      );      assert.deepEqual(rustroverLineAndColumn, {        command: "rustrover",        args: ["--line", "71", "--column", "5", "/tmp/workspace/src/process/externalLauncher.ts"],      });       const webstormLineOnly = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace/AGENTS.md:48", editor: "webstorm" },        "darwin",      );      assert.deepEqual(webstormLineOnly, {        command: "webstorm",        args: ["--line", "48", "/tmp/workspace/AGENTS.md"],      });    }),  );   it.effect("falls back to zeditor when zed is not installed", () =>    Effect.gen(function* () {      const fs = yield* FileSystem.FileSystem;      const path = yield* Path.Path;      const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-external-launcher-test-" });      yield* fs.writeFileString(path.join(dir, "zeditor"), "#!/bin/sh\nexit 0\n");      yield* fs.chmod(path.join(dir, "zeditor"), 0o755);       const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", {        PATH: dir,      });       assert.deepEqual(result, {        command: "zeditor",        args: ["/tmp/workspace"],      });    }),  );   it.effect("falls back to the primary command when no alias is installed", () =>    Effect.gen(function* () {      const result = yield* resolveEditorLaunch({ cwd: "/tmp/workspace", editor: "zed" }, "linux", {        PATH: "",      });      assert.deepEqual(result, {        command: "zed",        args: ["/tmp/workspace"],      });    }),  );   it.effect("maps file-manager editor to OS open commands", () =>    Effect.gen(function* () {      const launch1 = yield* resolveEditorLaunch(        { cwd: "/tmp/workspace", editor: "file-manager" },        "darwin",        { PATH: "" },      );      assert.deepEqual(launch1, {        command: "open",        args: ["/tmp/workspace"],      });       const launch2 = yield* resolveEditorLaunch(        { cwd: "C:\\workspace", editor: "file-manager" },        "win32",        { PATH: "" },      );      assert.deepEqual(launch2, {        command: "explorer",        args: ["C:\\workspace"],

Lines 1–500 of 802.