Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
21 changes: 20 additions & 1 deletion apps/server/src/open.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ it.layer(NodeServices.layer)("resolveEditorLaunch", (it) => {
args: ["/tmp/workspace"],
});

const traeLaunch = yield* resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "trae" },
"darwin",
);
assert.deepEqual(traeLaunch, {
command: "trae",
args: ["/tmp/workspace"],
});

const vscodeLaunch = yield* resolveEditorLaunch(
{ cwd: "/tmp/workspace", editor: "vscode" },
"darwin",
Expand Down Expand Up @@ -89,6 +98,15 @@ it.layer(NodeServices.layer)("resolveEditorLaunch", (it) => {
args: ["--goto", "/tmp/workspace/src/open.ts:71:5"],
});

const traeLineAndColumn = yield* resolveEditorLaunch(
{ cwd: "/tmp/workspace/src/open.ts:71:5", editor: "trae" },
"darwin",
);
assert.deepEqual(traeLineAndColumn, {
command: "trae",
args: ["--goto", "/tmp/workspace/src/open.ts:71:5"],
});

const vscodeLineAndColumn = yield* resolveEditorLaunch(
{ cwd: "/tmp/workspace/src/open.ts:71:5", editor: "vscode" },
"darwin",
Expand Down Expand Up @@ -256,14 +274,15 @@ it.layer(NodeServices.layer)("resolveAvailableEditors", (it) => {
const path = yield* Path.Path;
const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-editors-" });

yield* fs.writeFileString(path.join(dir, "trae.CMD"), "@echo off\r\n");
yield* fs.writeFileString(path.join(dir, "code-insiders.CMD"), "@echo off\r\n");
yield* fs.writeFileString(path.join(dir, "codium.CMD"), "@echo off\r\n");
yield* fs.writeFileString(path.join(dir, "explorer.CMD"), "MZ");
const editors = resolveAvailableEditors("win32", {
PATH: dir,
PATHEXT: ".COM;.EXE;.BAT;.CMD",
});
assert.deepEqual(editors, ["vscode-insiders", "vscodium", "file-manager"]);
assert.deepEqual(editors, ["trae", "vscode-insiders", "vscodium", "file-manager"]);
}),
);
});
46 changes: 46 additions & 0 deletions apps/web/src/components/ChatView.browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,52 @@ describe("ChatView timeline estimator parity (full app)", () => {
}
});

it("opens the project cwd with Trae when it is the only available editor", async () => {
setDraftThreadWithoutWorktree();

const mounted = await mountChatView({
viewport: DEFAULT_VIEWPORT,
snapshot: createDraftOnlySnapshot(),
configureFixture: (nextFixture) => {
nextFixture.serverConfig = {
...nextFixture.serverConfig,
availableEditors: ["trae"],
};
},
});

try {
await waitForServerConfigToApply();
const openButton = await waitForElement(
() =>
Array.from(document.querySelectorAll("button")).find(
(button) => button.textContent?.trim() === "Open",
) as HTMLButtonElement | null,
"Unable to find Open button.",
);
await vi.waitFor(() => {
expect(openButton.disabled).toBe(false);
});
openButton.click();

await vi.waitFor(
() => {
const openRequest = wsRequests.find(
(request) => request._tag === WS_METHODS.shellOpenInEditor,
);
expect(openRequest).toMatchObject({
_tag: WS_METHODS.shellOpenInEditor,
cwd: "/repo/project",
editor: "trae",
});
},
{ timeout: 8_000, interval: 16 },
);
} finally {
await mounted.cleanup();
}
});

it("filters the open picker menu and opens VSCodium from the menu", async () => {
setDraftThreadWithoutWorktree();

Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ export const CursorIcon: Icon = (props) => (
</svg>
);

export const TraeIcon: Icon = (props) => (
<svg {...props} viewBox="0 0 24 24" fill="currentColor">
{/* Back rectangle: left strip + bottom strip drawn separately — empty bottom-left corner is the gap between them */}
<rect x="1" y="4" width="3" height="14" />
<rect x="4" y="18" width="18" height="3" />
{/* Front frame: top bar + right bar only — left and bottom are replaced by the back strips above */}
<rect x="4" y="4" width="18" height="3" />
<rect x="19" y="7" width="3" height="11" />
{/* Two diamonds, offset slightly to the right within the open area */}
<path d="M11 10L13 12L11 14L9 12Z" />
<path d="M16 10L18 12L16 14L14 12Z" />
</svg>
);

export const VisualStudioCode: Icon = (props) => {
const id = useId();
const maskId = `${id}-vscode-a`;
Expand Down
7 changes: 6 additions & 1 deletion apps/web/src/components/chat/OpenInPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ChevronDownIcon, FolderClosedIcon } from "lucide-react";
import { Button } from "../ui/button";
import { Group, GroupSeparator } from "../ui/group";
import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "../ui/menu";
import { AntigravityIcon, CursorIcon, Icon, VisualStudioCode, Zed } from "../Icons";
import { AntigravityIcon, CursorIcon, Icon, TraeIcon, VisualStudioCode, Zed } from "../Icons";
import { isMacPlatform, isWindowsPlatform } from "~/lib/utils";
import { readNativeApi } from "~/nativeApi";

Expand All @@ -17,6 +17,11 @@ const resolveOptions = (platform: string, availableEditors: ReadonlyArray<Editor
Icon: CursorIcon,
value: "cursor",
},
{
label: "Trae",
Icon: TraeIcon,
value: "trae",
},
{
label: "VS Code",
Icon: VisualStudioCode,
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TrimmedNonEmptyString } from "./baseSchemas";

export const EDITORS = [
{ id: "cursor", label: "Cursor", command: "cursor", supportsGoto: true },
{ id: "trae", label: "Trae", command: "trae", supportsGoto: true },
{ id: "vscode", label: "VS Code", command: "code", supportsGoto: true },
{
id: "vscode-insiders",
Expand Down
Loading