authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-02 16:17:07-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-02 18:53:21-08:00
logde61c0c42b0797735a5cbe7ec6d4b3358fcf4295
treef74abd294eb0468d9ec8b7359a3db49ebf80d2ec
parentecb4a1efa43ae762b4314895505371033170faae

Guard worktree branch rename and fix branch toolbar state

- Skip auto-rename when the active worktree branch no longer matches the temp branch - Update reactor tests to cover branch-switch and first-turn rename behavior - Show the actual current branch in the toolbar and use a VS Code icon in Open In picker

5 files changed, 231 insertions(+), 76 deletions(-)

apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts+75-12
...@@ -108,11 +108,27 @@ describe("ProviderCommandReactor", () => {...@@ -108,11 +108,27 @@ describe("ProviderCommandReactor", () => {
108 const interruptTurn = vi.fn((_: unknown) => Effect.void);108 const interruptTurn = vi.fn((_: unknown) => Effect.void);
109 const respondToRequest = vi.fn((_: unknown) => Effect.void);109 const respondToRequest = vi.fn((_: unknown) => Effect.void);
110 const stopSession = vi.fn((_: unknown) => Effect.void);110 const stopSession = vi.fn((_: unknown) => Effect.void);
111 const statusBranchByCwd = new Map<string, string | null>();
111 const renameBranch = vi.fn((_: unknown) =>112 const renameBranch = vi.fn((_: unknown) =>
112 Effect.succeed({113 Effect.succeed({
113 branch: "t3code/generated-name",114 branch: "t3code/generated-name",
114 }),115 }),
115 );116 );
117 const statusDetails = vi.fn((cwd: string) =>
118 Effect.succeed({
119 branch: statusBranchByCwd.get(cwd) ?? null,
120 upstreamRef: null,
121 hasWorkingTreeChanges: false,
122 workingTree: {
123 files: [],
124 insertions: 0,
125 deletions: 0,
126 },
127 hasUpstream: false,
128 aheadCount: 0,
129 behindCount: 0,
130 }),
131 );
116 const generateBranchName = vi.fn<TextGenerationShape["generateBranchName"]>(() =>132 const generateBranchName = vi.fn<TextGenerationShape["generateBranchName"]>(() =>
117 Effect.succeed({133 Effect.succeed({
118 branch: "generated-name",134 branch: "generated-name",
...@@ -141,7 +157,12 @@ describe("ProviderCommandReactor", () => {...@@ -141,7 +157,12 @@ describe("ProviderCommandReactor", () => {
141 const layer = ProviderCommandReactorLive.pipe(157 const layer = ProviderCommandReactorLive.pipe(
142 Layer.provideMerge(orchestrationLayer),158 Layer.provideMerge(orchestrationLayer),
143 Layer.provideMerge(Layer.succeed(ProviderService, service)),159 Layer.provideMerge(Layer.succeed(ProviderService, service)),
144 Layer.provideMerge(Layer.succeed(GitCore, { renameBranch } as unknown as GitCoreShape)),160 Layer.provideMerge(
161 Layer.succeed(
162 GitCore,
163 { renameBranch, statusDetails } as unknown as GitCoreShape,
164 ),
165 ),
145 Layer.provideMerge(166 Layer.provideMerge(
146 Layer.succeed(TextGeneration, { generateBranchName } as unknown as TextGenerationShape),167 Layer.succeed(TextGeneration, { generateBranchName } as unknown as TextGenerationShape),
147 ),168 ),
...@@ -189,7 +210,11 @@ describe("ProviderCommandReactor", () => {...@@ -189,7 +210,11 @@ describe("ProviderCommandReactor", () => {
189 respondToRequest,210 respondToRequest,
190 stopSession,211 stopSession,
191 renameBranch,212 renameBranch,
213 statusDetails,
192 generateBranchName,214 generateBranchName,
215 setStatusBranch: (cwd: string, branch: string | null) => {
216 statusBranchByCwd.set(cwd, branch);
217 },
193 stateDir,218 stateDir,
194 };219 };
195 }220 }
...@@ -235,6 +260,7 @@ describe("ProviderCommandReactor", () => {...@@ -235,6 +260,7 @@ describe("ProviderCommandReactor", () => {
235 it("generates and renames temporary worktree branch on first turn", async () => {260 it("generates and renames temporary worktree branch on first turn", async () => {
236 const harness = await createHarness();261 const harness = await createHarness();
237 const now = new Date().toISOString();262 const now = new Date().toISOString();
263 const worktreeCwd = "/tmp/provider-project/.t3/worktrees/t3code-89abc123";
238264
239 await Effect.runPromise(265 await Effect.runPromise(
240 harness.engine.dispatch({266 harness.engine.dispatch({
...@@ -242,9 +268,10 @@ describe("ProviderCommandReactor", () => {...@@ -242,9 +268,10 @@ describe("ProviderCommandReactor", () => {
242 commandId: CommandId.makeUnsafe("cmd-thread-meta-set-temp-branch"),268 commandId: CommandId.makeUnsafe("cmd-thread-meta-set-temp-branch"),
243 threadId: ThreadId.makeUnsafe("thread-1"),269 threadId: ThreadId.makeUnsafe("thread-1"),
244 branch: "t3code/89abc123",270 branch: "t3code/89abc123",
245 worktreePath: "/tmp/provider-project/.t3/worktrees/t3code-89abc123",271 worktreePath: worktreeCwd,
246 }),272 }),
247 );273 );
274 harness.setStatusBranch(worktreeCwd, "t3code/89abc123");
248275
249 await Effect.runPromise(276 await Effect.runPromise(
250 harness.engine.dispatch({277 harness.engine.dispatch({
...@@ -275,7 +302,7 @@ describe("ProviderCommandReactor", () => {...@@ -275,7 +302,7 @@ describe("ProviderCommandReactor", () => {
275 await waitFor(() => harness.renameBranch.mock.calls.length === 1);302 await waitFor(() => harness.renameBranch.mock.calls.length === 1);
276303
277 expect(harness.generateBranchName.mock.calls[0]?.[0]).toEqual({304 expect(harness.generateBranchName.mock.calls[0]?.[0]).toEqual({
278 cwd: "/tmp/provider-project/.t3/worktrees/t3code-89abc123",305 cwd: worktreeCwd,
279 message: "Fix visual bug from screenshot",306 message: "Fix visual bug from screenshot",
280 attachments: [307 attachments: [
281 {308 {
...@@ -288,18 +315,14 @@ describe("ProviderCommandReactor", () => {...@@ -288,18 +315,14 @@ describe("ProviderCommandReactor", () => {
288 ],315 ],
289 });316 });
290 expect(harness.renameBranch.mock.calls[0]?.[0]).toEqual({317 expect(harness.renameBranch.mock.calls[0]?.[0]).toEqual({
291 cwd: "/tmp/provider-project/.t3/worktrees/t3code-89abc123",318 cwd: worktreeCwd,
292 oldBranch: "t3code/89abc123",319 oldBranch: "t3code/89abc123",
293 newBranch: "t3code/generated-name",320 newBranch: "t3code/generated-name",
294 });321 });
295322
296 await waitFor(() => {323 const readModel = await Effect.runPromise(harness.engine.getReadModel());
297 const readModel = Effect.runSync(harness.engine.getReadModel());324 const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1"));
298 const thread = readModel.threads.find(325 expect(thread?.branch).toBe("t3code/89abc123");
299 (entry) => entry.id === ThreadId.makeUnsafe("thread-1"),
300 );
301 return thread?.branch === "t3code/generated-name";
302 });
303 });326 });
304327
305 it("passes persisted attachment references to branch generation and turn start", async () => {328 it("passes persisted attachment references to branch generation and turn start", async () => {
...@@ -373,6 +396,7 @@ describe("ProviderCommandReactor", () => {...@@ -373,6 +396,7 @@ describe("ProviderCommandReactor", () => {
373 it("skips worktree branch generation after the first user turn", async () => {396 it("skips worktree branch generation after the first user turn", async () => {
374 const harness = await createHarness();397 const harness = await createHarness();
375 const now = new Date().toISOString();398 const now = new Date().toISOString();
399 const worktreeCwd = "/tmp/provider-project/.t3/worktrees/t3code-1234abcd";
376400
377 await Effect.runPromise(401 await Effect.runPromise(
378 harness.engine.dispatch({402 harness.engine.dispatch({
...@@ -380,9 +404,10 @@ describe("ProviderCommandReactor", () => {...@@ -380,9 +404,10 @@ describe("ProviderCommandReactor", () => {
380 commandId: CommandId.makeUnsafe("cmd-thread-meta-set-temp-branch-2"),404 commandId: CommandId.makeUnsafe("cmd-thread-meta-set-temp-branch-2"),
381 threadId: ThreadId.makeUnsafe("thread-1"),405 threadId: ThreadId.makeUnsafe("thread-1"),
382 branch: "t3code/1234abcd",406 branch: "t3code/1234abcd",
383 worktreePath: "/tmp/provider-project/.t3/worktrees/t3code-1234abcd",407 worktreePath: worktreeCwd,
384 }),408 }),
385 );409 );
410 harness.setStatusBranch(worktreeCwd, "t3code/1234abcd");
386411
387 await Effect.runPromise(412 await Effect.runPromise(
388 harness.engine.dispatch({413 harness.engine.dispatch({
...@@ -425,6 +450,44 @@ describe("ProviderCommandReactor", () => {...@@ -425,6 +450,44 @@ describe("ProviderCommandReactor", () => {
425 expect(harness.renameBranch.mock.calls.length).toBe(1);450 expect(harness.renameBranch.mock.calls.length).toBe(1);
426 });451 });
427452
453 it("skips worktree rename when active branch already changed", async () => {
454 const harness = await createHarness();
455 const now = new Date().toISOString();
456 const worktreeCwd = "/tmp/provider-project/.t3/worktrees/t3code-badf00d0";
457
458 await Effect.runPromise(
459 harness.engine.dispatch({
460 type: "thread.meta.update",
461 commandId: CommandId.makeUnsafe("cmd-thread-meta-set-temp-branch-switched"),
462 threadId: ThreadId.makeUnsafe("thread-1"),
463 branch: "t3code/badf00d0",
464 worktreePath: worktreeCwd,
465 }),
466 );
467 harness.setStatusBranch(worktreeCwd, "feature/add-vscode-open-in-support");
468
469 await Effect.runPromise(
470 harness.engine.dispatch({
471 type: "thread.turn.start",
472 commandId: CommandId.makeUnsafe("cmd-turn-start-worktree-switched"),
473 threadId: ThreadId.makeUnsafe("thread-1"),
474 message: {
475 messageId: asMessageId("user-message-worktree-switched"),
476 role: "user",
477 text: "Fix visual bug from screenshot",
478 attachments: [],
479 },
480 approvalPolicy: "on-request",
481 sandboxMode: "workspace-write",
482 createdAt: now,
483 }),
484 );
485
486 await waitFor(() => harness.generateBranchName.mock.calls.length === 1);
487 await Effect.runPromise(Effect.sleep("20 millis"));
488 expect(harness.renameBranch.mock.calls.length).toBe(0);
489 });
490
428 it("skips worktree rename when branch-name generation fails", async () => {491 it("skips worktree rename when branch-name generation fails", async () => {
429 const harness = await createHarness();492 const harness = await createHarness();
430 const now = new Date().toISOString();493 const now = new Date().toISOString();
apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+36-11
...@@ -330,17 +330,42 @@ const make = Effect.gen(function* () {...@@ -330,17 +330,42 @@ const make = Effect.gen(function* () {
330 const targetBranch = buildGeneratedWorktreeBranchName(generated.branch);330 const targetBranch = buildGeneratedWorktreeBranchName(generated.branch);
331 if (targetBranch === oldBranch) return Effect.void;331 if (targetBranch === oldBranch) return Effect.void;
332332
333 return Effect.flatMap(333 return Effect.gen(function* () {
334 git.renameBranch({ cwd, oldBranch, newBranch: targetBranch }),334 const currentBranch = yield* git.statusDetails(cwd).pipe(
335 (renamed) =>335 Effect.map((status) => status.branch),
336 orchestrationEngine.dispatch({336 Effect.catch((error) =>
337 type: "thread.meta.update",337 Effect.logWarning(
338 commandId: serverCommandId("worktree-branch-rename"),338 "provider command reactor failed to read active worktree branch",
339 threadId: input.threadId,339 {
340 branch: renamed.branch,340 threadId: input.threadId,
341 worktreePath: cwd,341 cwd,
342 }),342 oldBranch,
343 );343 targetBranch,
344 reason: error.message,
345 },
346 ).pipe(Effect.as(null)),
347 ),
348 );
349
350 if (currentBranch !== oldBranch) {
351 return yield* Effect.logWarning(
352 "provider command reactor skipped worktree branch rename because active branch changed",
353 {
354 threadId: input.threadId,
355 cwd,
356 oldBranch,
357 targetBranch,
358 currentBranch,
359 },
360 );
361 }
362
363 yield* git.renameBranch({
364 cwd,
365 oldBranch,
366 newBranch: targetBranch,
367 });
368 });
344 }),369 }),
345 Effect.catchCause((cause) =>370 Effect.catchCause((cause) =>
346 Effect.logWarning(371 Effect.logWarning(
apps/web/src/components/BranchToolbar.tsx+11-51
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import type { GitBranch, ThreadId } from "@t3tools/contracts";1import type { GitBranch, ThreadId } from "@t3tools/contracts";
2import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";2import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3import { useEffect, useState } from "react";3import { useState } from "react";
44
5import { newCommandId } from "../lib/utils";5import { newCommandId } from "../lib/utils";
6import {6import {
...@@ -14,7 +14,6 @@ import { useStore } from "../store";...@@ -14,7 +14,6 @@ import { useStore } from "../store";
14import {14import {
15 dedupeRemoteBranchesWithLocalMatches,15 dedupeRemoteBranchesWithLocalMatches,
16 deriveLocalBranchNameFromRemoteRef,16 deriveLocalBranchNameFromRemoteRef,
17 deriveSyncedLocalBranch,
18} from "./BranchToolbar.logic";17} from "./BranchToolbar.logic";
19import { Button } from "./ui/button";18import { Button } from "./ui/button";
20import {19import {
...@@ -72,6 +71,11 @@ export default function BranchToolbar({...@@ -72,6 +71,11 @@ export default function BranchToolbar({
72 const branchesQuery = useQuery(gitBranchesQueryOptions(branchCwd));71 const branchesQuery = useQuery(gitBranchesQueryOptions(branchCwd));
7372
74 const branches = dedupeRemoteBranchesWithLocalMatches(branchesQuery.data?.branches ?? []);73 const branches = dedupeRemoteBranchesWithLocalMatches(branchesQuery.data?.branches ?? []);
74 const currentGitBranch = branches.find((branch) => branch.current)?.name ?? null;
75 const resolvedActiveBranch =
76 effectiveEnvMode === "worktree" && !activeWorktreePath
77 ? activeThreadBranch
78 : (currentGitBranch ?? activeThreadBranch);
75 const branchNames = branches.map((branch) => branch.name);79 const branchNames = branches.map((branch) => branch.name);
76 const branchByName = new Map(branches.map((branch) => [branch.name, branch]));80 const branchByName = new Map(branches.map((branch) => [branch.name, branch]));
77 const trimmedBranchQuery = branchQuery.trim();81 const trimmedBranchQuery = branchQuery.trim();
...@@ -92,50 +96,6 @@ export default function BranchToolbar({...@@ -92,50 +96,6 @@ export default function BranchToolbar({
92 gitCreateBranchAndCheckoutMutationOptions({ cwd: branchCwd, queryClient }),96 gitCreateBranchAndCheckoutMutationOptions({ cwd: branchCwd, queryClient }),
93 );97 );
9498
95 // ── Effects ───────────────────────────────────────────────────────────
96
97 // Keep thread branch synced to git current branch for local threads.
98 const queryBranches = branchesQuery.data?.branches;
99 useEffect(() => {
100 const syncedBranch = deriveSyncedLocalBranch({
101 activeThreadId,
102 activeWorktreePath,
103 envMode: effectiveEnvMode,
104 activeThreadBranch,
105 queryBranches,
106 });
107 if (!activeThreadId || !syncedBranch) return;
108 const api = readNativeApi();
109
110 if (api && hasServerThread) {
111 void api.orchestration.dispatchCommand({
112 type: "thread.meta.update",
113 commandId: newCommandId(),
114 threadId: activeThreadId,
115 branch: syncedBranch,
116 worktreePath: null,
117 });
118 }
119 if (hasServerThread) {
120 setThreadBranchAction(activeThreadId, syncedBranch, null);
121 return;
122 }
123 setDraftThreadContext(threadId, {
124 branch: syncedBranch,
125 worktreePath: null,
126 });
127 }, [
128 activeThreadId,
129 activeWorktreePath,
130 activeThreadBranch,
131 queryBranches,
132 effectiveEnvMode,
133 setThreadBranchAction,
134 hasServerThread,
135 setDraftThreadContext,
136 threadId,
137 ]);
138
139 // ── Helpers ───────────────────────────────────────────────────────────99 // ── Helpers ───────────────────────────────────────────────────────────
140100
141 const setThreadError = (error: string | null) => {101 const setThreadError = (error: string | null) => {
...@@ -282,7 +242,7 @@ export default function BranchToolbar({...@@ -282,7 +242,7 @@ export default function BranchToolbar({
282 }242 }
283 }}243 }}
284 open={isBranchMenuOpen}244 open={isBranchMenuOpen}
285 value={activeThreadBranch}245 value={resolvedActiveBranch}
286 >246 >
287 <ComboboxTrigger247 <ComboboxTrigger
288 render={<Button variant="ghost" size="xs" />}248 render={<Button variant="ghost" size="xs" />}
...@@ -290,10 +250,10 @@ export default function BranchToolbar({...@@ -290,10 +250,10 @@ export default function BranchToolbar({
290 disabled={branchesQuery.isLoading}250 disabled={branchesQuery.isLoading}
291 >251 >
292 <span className="max-w-[240px] truncate">252 <span className="max-w-[240px] truncate">
293 {activeThreadBranch253 {resolvedActiveBranch
294 ? effectiveEnvMode === "worktree" && !activeWorktreePath254 ? effectiveEnvMode === "worktree" && !activeWorktreePath
295 ? `From ${activeThreadBranch}`255 ? `From ${resolvedActiveBranch}`
296 : activeThreadBranch256 : resolvedActiveBranch
297 : "Select branch"}257 : "Select branch"}
298 </span>258 </span>
299 <ChevronDownIcon />259 <ChevronDownIcon />
...@@ -347,7 +307,7 @@ export default function BranchToolbar({...@@ -347,7 +307,7 @@ export default function BranchToolbar({
347 key={itemValue}307 key={itemValue}
348 value={itemValue}308 value={itemValue}
349 className={309 className={
350 itemValue === activeThreadBranch ? "bg-accent text-foreground" : undefined310 itemValue === resolvedActiveBranch ? "bg-accent text-foreground" : undefined
351 }311 }
352 onClick={() => selectBranch(branch)}312 onClick={() => selectBranch(branch)}
353 >313 >
apps/web/src/components/ChatView.tsx+2-2
...@@ -100,7 +100,7 @@ import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "./u...@@ -100,7 +100,7 @@ import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "./u
100import { Separator } from "./ui/separator";100import { Separator } from "./ui/separator";
101import { Group, GroupSeparator } from "./ui/group";101import { Group, GroupSeparator } from "./ui/group";
102import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu";102import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu";
103import { CursorIcon, Icon } from "./Icons";103import { CursorIcon, Icon, VisualStudioCode } from "./Icons";
104import { cn, isMacPlatform, isWindowsPlatform } from "~/lib/utils";104import { cn, isMacPlatform, isWindowsPlatform } from "~/lib/utils";
105import { Badge } from "./ui/badge";105import { Badge } from "./ui/badge";
106import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";106import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
...@@ -3681,7 +3681,7 @@ const OpenInPicker = memo(function OpenInPicker({...@@ -3681,7 +3681,7 @@ const OpenInPicker = memo(function OpenInPicker({
3681 },3681 },
3682 {3682 {
3683 label: "VS Code",3683 label: "VS Code",
3684 Icon: FileIcon,3684 Icon: VisualStudioCode,
3685 value: "vscode",3685 value: "vscode",
3686 },3686 },
3687 {3687 {
apps/web/src/components/Icons.tsx+107
...@@ -19,3 +19,110 @@ export const CursorIcon: Icon = (props) => (...@@ -19,3 +19,110 @@ export const CursorIcon: Icon = (props) => (
19 <path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" />19 <path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" />
20 </svg>20 </svg>
21);21);
22
23export const VisualStudioCode: Icon = (props) => (
24 <svg {...props} fill="none" viewBox="0 0 100 100">
25 <mask
26 id="vscode__a"
27 width="100"
28 height="100"
29 x="0"
30 y="0"
31 maskUnits="userSpaceOnUse"
32 >
33 <path
34 fill="#fff"
35 fillRule="evenodd"
36 d="M70.912 99.317a6.223 6.223 0 0 0 4.96-.19l20.589-9.907A6.25 6.25 0 0 0 100 83.587V16.413a6.25 6.25 0 0 0-3.54-5.632L75.874.874a6.226 6.226 0 0 0-7.104 1.21L29.355 38.04 12.187 25.01a4.162 4.162 0 0 0-5.318.236l-5.506 5.009a4.168 4.168 0 0 0-.004 6.162L16.247 50 1.36 63.583a4.168 4.168 0 0 0 .004 6.162l5.506 5.01a4.162 4.162 0 0 0 5.318.236l17.168-13.032L68.77 97.917a6.217 6.217 0 0 0 2.143 1.4ZM75.015 27.3 45.11 50l29.906 22.701V27.3Z"
37 clipRule="evenodd"
38 />
39 </mask>
40 <g mask="url(#vscode__a)">
41 <path
42 fill="#0065A9"
43 d="M96.461 10.796 75.857.876a6.23 6.23 0 0 0-7.107 1.207l-67.451 61.5a4.167 4.167 0 0 0 .004 6.162l5.51 5.009a4.167 4.167 0 0 0 5.32.236l81.228-61.62c2.725-2.067 6.639-.124 6.639 3.297v-.24a6.25 6.25 0 0 0-3.539-5.63Z"
44 />
45 <g filter="url(#vscode__b)">
46 <path
47 fill="#007ACC"
48 d="m96.461 89.204-20.604 9.92a6.229 6.229 0 0 1-7.107-1.207l-67.451-61.5a4.167 4.167 0 0 1 .004-6.162l5.51-5.009a4.167 4.167 0 0 1 5.32-.236l81.228 61.62c2.725 2.067 6.639.124 6.639-3.297v.24a6.25 6.25 0 0 1-3.539 5.63Z"
49 />
50 </g>
51 <g filter="url(#vscode__c)">
52 <path
53 fill="#1F9CF0"
54 d="M75.858 99.126a6.232 6.232 0 0 1-7.108-1.21c2.306 2.307 6.25.674 6.25-2.588V4.672c0-3.262-3.944-4.895-6.25-2.589a6.232 6.232 0 0 1 7.108-1.21l20.6 9.908A6.25 6.25 0 0 1 100 16.413v67.174a6.25 6.25 0 0 1-3.541 5.633l-20.601 9.906Z"
55 />
56 </g>
57 <path
58 fill="url(#vscode__d)"
59 fillRule="evenodd"
60 d="M70.851 99.317a6.224 6.224 0 0 0 4.96-.19L96.4 89.22a6.25 6.25 0 0 0 3.54-5.633V16.413a6.25 6.25 0 0 0-3.54-5.632L75.812.874a6.226 6.226 0 0 0-7.104 1.21L29.294 38.04 12.126 25.01a4.162 4.162 0 0 0-5.317.236l-5.507 5.009a4.168 4.168 0 0 0-.004 6.162L16.186 50 1.298 63.583a4.168 4.168 0 0 0 .004 6.162l5.507 5.009a4.162 4.162 0 0 0 5.317.236L29.294 61.96l39.414 35.958a6.218 6.218 0 0 0 2.143 1.4ZM74.954 27.3 45.048 50l29.906 22.701V27.3Z"
61 clipRule="evenodd"
62 opacity=".25"
63 style={{ mixBlendMode: "overlay" }}
64 />
65 </g>
66 <defs>
67 <filter
68 id="vscode__b"
69 width="116.727"
70 height="92.246"
71 x="-8.394"
72 y="15.829"
73 colorInterpolationFilters="sRGB"
74 filterUnits="userSpaceOnUse"
75 >
76 <feFlood floodOpacity="0" result="BackgroundImageFix" />
77 <feColorMatrix
78 in="SourceAlpha"
79 values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
80 />
81 <feOffset />
82 <feGaussianBlur stdDeviation="4.167" />
83 <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
84 <feBlend
85 in2="BackgroundImageFix"
86 mode="overlay"
87 result="effect1_dropShadow"
88 />
89 <feBlend in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
90 </filter>
91 <filter
92 id="vscode__c"
93 width="47.917"
94 height="116.151"
95 x="60.417"
96 y="-8.076"
97 colorInterpolationFilters="sRGB"
98 filterUnits="userSpaceOnUse"
99 >
100 <feFlood floodOpacity="0" result="BackgroundImageFix" />
101 <feColorMatrix
102 in="SourceAlpha"
103 values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
104 />
105 <feOffset />
106 <feGaussianBlur stdDeviation="4.167" />
107 <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
108 <feBlend
109 in2="BackgroundImageFix"
110 mode="overlay"
111 result="effect1_dropShadow"
112 />
113 <feBlend in="SourceGraphic" in2="effect1_dropShadow" result="shape" />
114 </filter>
115 <linearGradient
116 id="vscode__d"
117 x1="49.939"
118 x2="49.939"
119 y1=".258"
120 y2="99.742"
121 gradientUnits="userSpaceOnUse"
122 >
123 <stop stopColor="#fff" />
124 <stop offset="1" stopColor="#fff" stopOpacity="0" />
125 </linearGradient>
126 </defs>
127 </svg>
128);