| author | |
| committer | |
| log | 876bbd715ae6aa8e1d663455747e17c92e0a287c |
| tree | 7881f15b09c9f4e7095776b7b2e384aa62751c9b |
| parent | ac0d1f52a087c63819b2b032ac4535d18d3c23af |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: cursor[bot] <206951365+cursor[bot]@users.noreply.github.com>8 files changed, 189 insertions(+), 83 deletions(-)
apps/web/src/components/PlanSidebar.tsx+6-24| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | import { memo, useState, useCallback, useRef, useEffect } from "react"; | 1 | import { memo, useState, useCallback } from "react"; |
| 2 | import { type TimestampFormat } from "../appSettings"; | 2 | import { type TimestampFormat } from "../appSettings"; |
| 3 | import { Badge } from "./ui/badge"; | 3 | import { Badge } from "./ui/badge"; |
| 4 | import { Button } from "./ui/button"; | 4 | import { Button } from "./ui/button"; |
| ... | @@ -26,6 +26,7 @@ import { | ... | @@ -26,6 +26,7 @@ import { |
| 26 | import { Menu, MenuItem, MenuPopup, MenuTrigger } from "./ui/menu"; | 26 | import { Menu, MenuItem, MenuPopup, MenuTrigger } from "./ui/menu"; |
| 27 | import { readNativeApi } from "~/nativeApi"; | 27 | import { readNativeApi } from "~/nativeApi"; |
| 28 | import { toastManager } from "./ui/toast"; | 28 | import { toastManager } from "./ui/toast"; |
| 29 | import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; | ||
| 29 | 30 | ||
| 30 | function stepStatusIcon(status: string): React.ReactNode { | 31 | function stepStatusIcon(status: string): React.ReactNode { |
| 31 | if (status === "completed") { | 32 | if (status === "completed") { |
| ... | @@ -68,8 +69,7 @@ const PlanSidebar = memo(function PlanSidebar({ | ... | @@ -68,8 +69,7 @@ const PlanSidebar = memo(function PlanSidebar({ |
| 68 | }: PlanSidebarProps) { | 69 | }: PlanSidebarProps) { |
| 69 | const [proposedPlanExpanded, setProposedPlanExpanded] = useState(false); | 70 | const [proposedPlanExpanded, setProposedPlanExpanded] = useState(false); |
| 70 | const [isSavingToWorkspace, setIsSavingToWorkspace] = useState(false); | 71 | const [isSavingToWorkspace, setIsSavingToWorkspace] = useState(false); |
| 71 | const [copied, setCopied] = useState(false); | 72 | const { copyToClipboard, isCopied } = useCopyToClipboard(); |
| 72 | const copiedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); | ||
| 73 | 73 | ||
| 74 | const planMarkdown = activeProposedPlan?.planMarkdown ?? null; | 74 | const planMarkdown = activeProposedPlan?.planMarkdown ?? null; |
| 75 | const displayedPlanMarkdown = planMarkdown ? stripDisplayedPlanMarkdown(planMarkdown) : null; | 75 | const displayedPlanMarkdown = planMarkdown ? stripDisplayedPlanMarkdown(planMarkdown) : null; |
| ... | @@ -77,26 +77,8 @@ const PlanSidebar = memo(function PlanSidebar({ | ... | @@ -77,26 +77,8 @@ const PlanSidebar = memo(function PlanSidebar({ |
| 77 | 77 | ||
| 78 | const handleCopyPlan = useCallback(() => { | 78 | const handleCopyPlan = useCallback(() => { |
| 79 | if (!planMarkdown) return; | 79 | if (!planMarkdown) return; |
| 80 | void navigator.clipboard.writeText(planMarkdown); | 80 | copyToClipboard(planMarkdown); |
| 81 | if (copiedTimerRef.current != null) { | 81 | }, [planMarkdown, copyToClipboard]); |
| 82 | clearTimeout(copiedTimerRef.current); | ||
| 83 | } | ||
| 84 | |||
| 85 | setCopied(true); | ||
| 86 | copiedTimerRef.current = setTimeout(() => { | ||
| 87 | setCopied(false); | ||
| 88 | copiedTimerRef.current = null; | ||
| 89 | }, 2000); | ||
| 90 | }, [planMarkdown]); | ||
| 91 | |||
| 92 | // Cleanup timeout on unmount | ||
| 93 | useEffect(() => { | ||
| 94 | return () => { | ||
| 95 | if (copiedTimerRef.current != null) { | ||
| 96 | clearTimeout(copiedTimerRef.current); | ||
| 97 | } | ||
| 98 | }; | ||
| 99 | }, []); | ||
| 100 | 82 | ||
| 101 | const handleDownload = useCallback(() => { | 83 | const handleDownload = useCallback(() => { |
| 102 | if (!planMarkdown) return; | 84 | if (!planMarkdown) return; |
| ... | @@ -169,7 +151,7 @@ const PlanSidebar = memo(function PlanSidebar({ | ... | @@ -169,7 +151,7 @@ const PlanSidebar = memo(function PlanSidebar({ |
| 169 | </MenuTrigger> | 151 | </MenuTrigger> |
| 170 | <MenuPopup align="end"> | 152 | <MenuPopup align="end"> |
| 171 | <MenuItem onClick={handleCopyPlan}> | 153 | <MenuItem onClick={handleCopyPlan}> |
| 172 | {copied ? "Copied!" : "Copy to clipboard"} | 154 | {isCopied ? "Copied!" : "Copy to clipboard"} |
| 173 | </MenuItem> | 155 | </MenuItem> |
| 174 | <MenuItem onClick={handleDownload}>Download as markdown</MenuItem> | 156 | <MenuItem onClick={handleDownload}>Download as markdown</MenuItem> |
| 175 | <MenuItem | 157 | <MenuItem |
apps/web/src/components/Sidebar.tsx+19-22| ... | @@ -89,17 +89,11 @@ import { | ... | @@ -89,17 +89,11 @@ import { |
| 89 | resolveThreadStatusPill, | 89 | resolveThreadStatusPill, |
| 90 | shouldClearThreadSelectionOnMouseDown, | 90 | shouldClearThreadSelectionOnMouseDown, |
| 91 | } from "./Sidebar.logic"; | 91 | } from "./Sidebar.logic"; |
| 92 | import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; | ||
| 92 | 93 | ||
| 93 | const EMPTY_KEYBINDINGS: ResolvedKeybindingsConfig = []; | 94 | const EMPTY_KEYBINDINGS: ResolvedKeybindingsConfig = []; |
| 94 | const THREAD_PREVIEW_LIMIT = 6; | 95 | const THREAD_PREVIEW_LIMIT = 6; |
| 95 | 96 | ||
| 96 | async function copyTextToClipboard(text: string): Promise<void> { | ||
| 97 | if (typeof navigator === "undefined" || navigator.clipboard?.writeText === undefined) { | ||
| 98 | throw new Error("Clipboard API unavailable."); | ||
| 99 | } | ||
| 100 | await navigator.clipboard.writeText(text); | ||
| 101 | } | ||
| 102 | |||
| 103 | function formatRelativeTime(iso: string): string { | 97 | function formatRelativeTime(iso: string): string { |
| 104 | const diff = Date.now() - new Date(iso).getTime(); | 98 | const diff = Date.now() - new Date(iso).getTime(); |
| 105 | const minutes = Math.floor(diff / 60_000); | 99 | const minutes = Math.floor(diff / 60_000); |
| ... | @@ -671,6 +665,22 @@ export default function Sidebar() { | ... | @@ -671,6 +665,22 @@ export default function Sidebar() { |
| 671 | ], | 665 | ], |
| 672 | ); | 666 | ); |
| 673 | 667 | ||
| 668 | const { copyToClipboard } = useCopyToClipboard<{ threadId: ThreadId }>({ | ||
| 669 | onCopy: (ctx) => { | ||
| 670 | toastManager.add({ | ||
| 671 | type: "success", | ||
| 672 | title: "Thread ID copied", | ||
| 673 | description: ctx.threadId, | ||
| 674 | }); | ||
| 675 | }, | ||
| 676 | onError: (error) => { | ||
| 677 | toastManager.add({ | ||
| 678 | type: "error", | ||
| 679 | title: "Failed to copy thread ID", | ||
| 680 | description: error instanceof Error ? error.message : "An error occurred.", | ||
| 681 | }); | ||
| 682 | }, | ||
| 683 | }); | ||
| 674 | const handleThreadContextMenu = useCallback( | 684 | const handleThreadContextMenu = useCallback( |
| 675 | async (threadId: ThreadId, position: { x: number; y: number }) => { | 685 | async (threadId: ThreadId, position: { x: number; y: number }) => { |
| 676 | const api = readNativeApi(); | 686 | const api = readNativeApi(); |
| ... | @@ -699,20 +709,7 @@ export default function Sidebar() { | ... | @@ -699,20 +709,7 @@ export default function Sidebar() { |
| 699 | return; | 709 | return; |
| 700 | } | 710 | } |
| 701 | if (clicked === "copy-thread-id") { | 711 | if (clicked === "copy-thread-id") { |
| 702 | try { | 712 | copyToClipboard(threadId, { threadId }); |
| 703 | await copyTextToClipboard(threadId); | ||
| 704 | toastManager.add({ | ||
| 705 | type: "success", | ||
| 706 | title: "Thread ID copied", | ||
| 707 | description: threadId, | ||
| 708 | }); | ||
| 709 | } catch (error) { | ||
| 710 | toastManager.add({ | ||
| 711 | type: "error", | ||
| 712 | title: "Failed to copy thread ID", | ||
| 713 | description: error instanceof Error ? error.message : "An error occurred.", | ||
| 714 | }); | ||
| 715 | } | ||
| 716 | return; | 713 | return; |
| 717 | } | 714 | } |
| 718 | if (clicked !== "delete") return; | 715 | if (clicked !== "delete") return; |
| ... | @@ -729,7 +726,7 @@ export default function Sidebar() { | ... | @@ -729,7 +726,7 @@ export default function Sidebar() { |
| 729 | } | 726 | } |
| 730 | await deleteThread(threadId); | 727 | await deleteThread(threadId); |
| 731 | }, | 728 | }, |
| 732 | [appSettings.confirmThreadDelete, deleteThread, markThreadUnread, threads], | 729 | [appSettings.confirmThreadDelete, copyToClipboard, deleteThread, markThreadUnread, threads], |
| 733 | ); | 730 | ); |
| 734 | 731 | ||
| 735 | const handleMultiSelectContextMenu = useCallback( | 732 | const handleMultiSelectContextMenu = useCallback( |
apps/web/src/components/chat/MessageCopyButton.tsx+11-10| ... | @@ -1,19 +1,20 @@ | ... | @@ -1,19 +1,20 @@ |
| 1 | import { memo, useCallback, useState } from "react"; | 1 | import { memo } from "react"; |
| 2 | import { CopyIcon, CheckIcon } from "lucide-react"; | 2 | import { CopyIcon, CheckIcon } from "lucide-react"; |
| 3 | import { Button } from "../ui/button"; | 3 | import { Button } from "../ui/button"; |
| 4 | import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; | ||
| 4 | 5 | ||
| 5 | export const MessageCopyButton = memo(function MessageCopyButton({ text }: { text: string }) { | 6 | export const MessageCopyButton = memo(function MessageCopyButton({ text }: { text: string }) { |
| 6 | const [copied, setCopied] = useState(false); | 7 | const { copyToClipboard, isCopied } = useCopyToClipboard(); |
| 7 | |||
| 8 | const handleCopy = useCallback(() => { | ||
| 9 | void navigator.clipboard.writeText(text); | ||
| 10 | setCopied(true); | ||
| 11 | setTimeout(() => setCopied(false), 2000); | ||
| 12 | }, [text]); | ||
| 13 | 8 | ||
| 14 | return ( | 9 | return ( |
| 15 | <Button type="button" size="xs" variant="outline" onClick={handleCopy} title="Copy message"> | 10 | <Button |
| 16 | {copied ? <CheckIcon className="size-3 text-success" /> : <CopyIcon className="size-3" />} | 11 | type="button" |
| 12 | size="xs" | ||
| 13 | variant="outline" | ||
| 14 | onClick={() => copyToClipboard(text)} | ||
| 15 | title="Copy message" | ||
| 16 | > | ||
| 17 | {isCopied ? <CheckIcon className="size-3 text-success" /> : <CopyIcon className="size-3" />} | ||
| 17 | </Button> | 18 | </Button> |
| 18 | ); | 19 | ); |
| 19 | }); | 20 | }); |
apps/web/src/components/ui/sidebar.tsx+2-2| ... | @@ -17,7 +17,7 @@ import { | ... | @@ -17,7 +17,7 @@ import { |
| 17 | } from "~/components/ui/sheet"; | 17 | } from "~/components/ui/sheet"; |
| 18 | import { Skeleton } from "~/components/ui/skeleton"; | 18 | import { Skeleton } from "~/components/ui/skeleton"; |
| 19 | import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip"; | 19 | import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip"; |
| 20 | import { useMediaQuery } from "~/hooks/useMediaQuery"; | 20 | import { useIsMobile } from "~/hooks/useMediaQuery"; |
| 21 | import { getLocalStorageItem, setLocalStorageItem } from "~/hooks/useLocalStorage"; | 21 | import { getLocalStorageItem, setLocalStorageItem } from "~/hooks/useLocalStorage"; |
| 22 | import { Schema } from "effect"; | 22 | import { Schema } from "effect"; |
| 23 | 23 | ||
| ... | @@ -98,7 +98,7 @@ function SidebarProvider({ | ... | @@ -98,7 +98,7 @@ function SidebarProvider({ |
| 98 | open?: boolean; | 98 | open?: boolean; |
| 99 | onOpenChange?: (open: boolean) => void; | 99 | onOpenChange?: (open: boolean) => void; |
| 100 | }) { | 100 | }) { |
| 101 | const isMobile = useMediaQuery("(max-width: 767px)"); | 101 | const isMobile = useIsMobile(); |
| 102 | const [openMobile, setOpenMobile] = React.useState(false); | 102 | const [openMobile, setOpenMobile] = React.useState(false); |
| 103 | 103 | ||
| 104 | // This is the internal state of the sidebar. | 104 | // This is the internal state of the sidebar. |
apps/web/src/hooks/useCopyToClipboard.ts created+66| ... | @@ -0,0 +1,66 @@ | ||
| 1 | import * as React from "react"; | ||
| 2 | |||
| 3 | export function useCopyToClipboard<TContext = void>({ | ||
| 4 | timeout = 2000, | ||
| 5 | onCopy, | ||
| 6 | onError, | ||
| 7 | }: { | ||
| 8 | timeout?: number; | ||
| 9 | onCopy?: (ctx: TContext) => void; | ||
| 10 | onError?: (error: Error, ctx: TContext) => void; | ||
| 11 | } = {}): { copyToClipboard: (value: string, ctx: TContext) => void; isCopied: boolean } { | ||
| 12 | const [isCopied, setIsCopied] = React.useState(false); | ||
| 13 | const timeoutIdRef = React.useRef<NodeJS.Timeout | null>(null); | ||
| 14 | const onCopyRef = React.useRef(onCopy); | ||
| 15 | const onErrorRef = React.useRef(onError); | ||
| 16 | const timeoutRef = React.useRef(timeout); | ||
| 17 | |||
| 18 | onCopyRef.current = onCopy; | ||
| 19 | onErrorRef.current = onError; | ||
| 20 | timeoutRef.current = timeout; | ||
| 21 | |||
| 22 | const copyToClipboard = React.useCallback((value: string, ctx: TContext): void => { | ||
| 23 | if (typeof window === "undefined" || !navigator.clipboard?.writeText) { | ||
| 24 | onErrorRef.current?.(new Error("Clipboard API unavailable."), ctx); | ||
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 28 | if (!value) return; | ||
| 29 | |||
| 30 | navigator.clipboard.writeText(value).then( | ||
| 31 | () => { | ||
| 32 | if (timeoutIdRef.current) { | ||
| 33 | clearTimeout(timeoutIdRef.current); | ||
| 34 | } | ||
| 35 | setIsCopied(true); | ||
| 36 | |||
| 37 | onCopyRef.current?.(ctx); | ||
| 38 | |||
| 39 | if (timeoutRef.current !== 0) { | ||
| 40 | timeoutIdRef.current = setTimeout(() => { | ||
| 41 | setIsCopied(false); | ||
| 42 | timeoutIdRef.current = null; | ||
| 43 | }, timeoutRef.current); | ||
| 44 | } | ||
| 45 | }, | ||
| 46 | (error) => { | ||
| 47 | if (onErrorRef.current) { | ||
| 48 | onErrorRef.current(error, ctx); | ||
| 49 | } else { | ||
| 50 | console.error(error); | ||
| 51 | } | ||
| 52 | }, | ||
| 53 | ); | ||
| 54 | }, []); | ||
| 55 | |||
| 56 | // Cleanup timeout on unmount | ||
| 57 | React.useEffect(() => { | ||
| 58 | return (): void => { | ||
| 59 | if (timeoutIdRef.current) { | ||
| 60 | clearTimeout(timeoutIdRef.current); | ||
| 61 | } | ||
| 62 | }; | ||
| 63 | }, []); | ||
| 64 | |||
| 65 | return { copyToClipboard, isCopied }; | ||
| 66 | } | ||
apps/web/src/hooks/useMediaQuery.ts+79-19| ... | @@ -1,27 +1,87 @@ | ... | @@ -1,27 +1,87 @@ |
| 1 | import { useEffect, useState } from "react"; | 1 | import { useCallback, useSyncExternalStore } from "react"; |
| 2 | 2 | ||
| 3 | function getMediaQueryMatch(query: string): boolean { | 3 | const BREAKPOINTS = { |
| 4 | if (typeof window === "undefined") { | 4 | "2xl": 1536, |
| 5 | return false; | 5 | "3xl": 1600, |
| 6 | "4xl": 2000, | ||
| 7 | lg: 1024, | ||
| 8 | md: 768, | ||
| 9 | sm: 640, | ||
| 10 | xl: 1280, | ||
| 11 | } as const; | ||
| 12 | |||
| 13 | type Breakpoint = keyof typeof BREAKPOINTS; | ||
| 14 | |||
| 15 | type BreakpointQuery = Breakpoint | `max-${Breakpoint}` | `${Breakpoint}:max-${Breakpoint}`; | ||
| 16 | |||
| 17 | function resolveMin(value: Breakpoint | number): string { | ||
| 18 | const px = typeof value === "number" ? value : BREAKPOINTS[value]; | ||
| 19 | return `(min-width: ${px}px)`; | ||
| 20 | } | ||
| 21 | |||
| 22 | function resolveMax(value: Breakpoint | number): string { | ||
| 23 | const px = typeof value === "number" ? value : BREAKPOINTS[value]; | ||
| 24 | return `(max-width: ${px - 1}px)`; | ||
| 25 | } | ||
| 26 | |||
| 27 | function parseQuery(query: BreakpointQuery | MediaQueryInput | (string & {})): string { | ||
| 28 | if (typeof query !== "string") { | ||
| 29 | const parts: string[] = []; | ||
| 30 | if (query.min != null) parts.push(resolveMin(query.min)); | ||
| 31 | if (query.max != null) parts.push(resolveMax(query.max)); | ||
| 32 | if (query.pointer === "coarse") parts.push("(pointer: coarse)"); | ||
| 33 | if (query.pointer === "fine") parts.push("(pointer: fine)"); | ||
| 34 | if (parts.length === 0) return "(min-width: 0px)"; | ||
| 35 | return parts.join(" and "); | ||
| 36 | } | ||
| 37 | |||
| 38 | if (query.startsWith("(")) return query; | ||
| 39 | |||
| 40 | const parts: string[] = []; | ||
| 41 | for (const segment of query.split(":")) { | ||
| 42 | if (segment.startsWith("max-")) { | ||
| 43 | const bp = segment.slice(4); | ||
| 44 | if (bp in BREAKPOINTS) parts.push(resolveMax(bp as Breakpoint)); | ||
| 45 | } else if (segment in BREAKPOINTS) { | ||
| 46 | parts.push(resolveMin(segment as Breakpoint)); | ||
| 47 | } | ||
| 6 | } | 48 | } |
| 7 | return window.matchMedia(query).matches; | 49 | |
| 50 | return parts.length > 0 ? parts.join(" and ") : query; | ||
| 51 | } | ||
| 52 | |||
| 53 | function getServerSnapshot(): boolean { | ||
| 54 | return false; | ||
| 8 | } | 55 | } |
| 9 | 56 | ||
| 10 | export function useMediaQuery(query: string): boolean { | 57 | export type MediaQueryInput = { |
| 11 | const [matches, setMatches] = useState(() => getMediaQueryMatch(query)); | 58 | min?: Breakpoint | number; |
| 59 | max?: Breakpoint | number; | ||
| 60 | /** Touch-like input (finger). Use "fine" for mouse/trackpad. */ | ||
| 61 | pointer?: "coarse" | "fine"; | ||
| 62 | }; | ||
| 63 | |||
| 64 | export function useMediaQuery(query: BreakpointQuery | MediaQueryInput | (string & {})): boolean { | ||
| 65 | const mediaQuery = parseQuery(query); | ||
| 12 | 66 | ||
| 13 | useEffect(() => { | 67 | const subscribe = useCallback( |
| 14 | const mediaQueryList = window.matchMedia(query); | 68 | (callback: () => void) => { |
| 15 | const handleChange = () => { | 69 | if (typeof window === "undefined") return () => {}; |
| 16 | setMatches(mediaQueryList.matches); | 70 | const mql = window.matchMedia(mediaQuery); |
| 17 | }; | 71 | mql.addEventListener("change", callback); |
| 72 | return () => mql.removeEventListener("change", callback); | ||
| 73 | }, | ||
| 74 | [mediaQuery], | ||
| 75 | ); | ||
| 18 | 76 | ||
| 19 | setMatches(mediaQueryList.matches); | 77 | const getSnapshot = useCallback(() => { |
| 20 | mediaQueryList.addEventListener("change", handleChange); | 78 | if (typeof window === "undefined") return false; |
| 21 | return () => { | 79 | return window.matchMedia(mediaQuery).matches; |
| 22 | mediaQueryList.removeEventListener("change", handleChange); | 80 | }, [mediaQuery]); |
| 23 | }; | 81 | |
| 24 | }, [query]); | 82 | return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); |
| 83 | } | ||
| 25 | 84 | ||
| 26 | return matches; | 85 | export function useIsMobile(): boolean { |
| 86 | return useMediaQuery("max-md"); | ||
| 27 | } | 87 | } |
apps/web/src/routes/_chat.$threadId.tsx+1-1| ... | @@ -221,7 +221,7 @@ function ChatThreadRouteView() { | ... | @@ -221,7 +221,7 @@ function ChatThreadRouteView() { |
| 221 | if (!shouldUseDiffSheet) { | 221 | if (!shouldUseDiffSheet) { |
| 222 | return ( | 222 | return ( |
| 223 | <> | 223 | <> |
| 224 | <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground"> | 224 | <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground"> |
| 225 | <ChatView key={threadId} threadId={threadId} /> | 225 | <ChatView key={threadId} threadId={threadId} /> |
| 226 | </SidebarInset> | 226 | </SidebarInset> |
| 227 | <DiffPanelInlineSidebar | 227 | <DiffPanelInlineSidebar |
bun.lock+5-5| ... | @@ -262,13 +262,13 @@ | ... | @@ -262,13 +262,13 @@ |
| 262 | 262 | ||
| 263 | "@effect/language-service": ["@effect/language-service@0.75.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-g9xD2tAQgRFpYC2YgpZq02VeSL5fBbFJ0B/g1o+14NuNmwtaYJc7SjiLWAA9eyhJHosNrn6h1Ye+Kx6j5mN0AA=="], | 263 | "@effect/language-service": ["@effect/language-service@0.75.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-g9xD2tAQgRFpYC2YgpZq02VeSL5fBbFJ0B/g1o+14NuNmwtaYJc7SjiLWAA9eyhJHosNrn6h1Ye+Kx6j5mN0AA=="], |
| 264 | 264 | ||
| 265 | "@effect/platform-node": ["@effect/platform-node@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node@8881a9b", { "dependencies": { "@effect/platform-node-shared": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@8881a9b606d84a6f5eb6615279138322984f5368", "mime": "^4.1.0", "undici": "^7.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.25", "ioredis": "^5.7.0" } }, "sha512-lOVb9aLpFnbkG4dWxY8lSTXihldd6kbcFI936X5UMvHz0HAYGrxsu1a+kHt/rYjiw1gjCmmnU6pE2pwKfO9erg=="], | 265 | "@effect/platform-node": ["@effect/platform-node@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node@8881a9b", { "dependencies": { "@effect/platform-node-shared": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@8881a9b606d84a6f5eb6615279138322984f5368", "mime": "^4.1.0", "undici": "^7.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.25", "ioredis": "^5.7.0" } }], |
| 266 | 266 | ||
| 267 | "@effect/platform-node-shared": ["@effect/platform-node-shared@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@8881a9b606d84a6f5eb6615279138322984f5368", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.25" } }, "sha512-73FDHSTVLh/ZHeWrHFEbnCbjFE9gKi1YdJ9LEatDj0doZ8ouuTJW2BbqLDwMEfSf4zNQrxMEg+Jj/pb612HyWg=="], | 267 | "@effect/platform-node-shared": ["@effect/platform-node-shared@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@8881a9b606d84a6f5eb6615279138322984f5368", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.25" } }], |
| 268 | 268 | ||
| 269 | "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@https://pkg.pr.new/Effect-TS/effect-smol/@effect/sql-sqlite-bun@8881a9b", { "peerDependencies": { "effect": "^4.0.0-beta.25" } }, "sha512-7Tcfkx/NfQILRHyO5c52I8NYrg6jBcxDAguTYx7tgbGHYU9WPQRGh/AkcRgQ+1fsUGjWdojSfd+WGb/r4ltYtQ=="], | 269 | "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@https://pkg.pr.new/Effect-TS/effect-smol/@effect/sql-sqlite-bun@8881a9b", { "peerDependencies": { "effect": "^4.0.0-beta.25" } }], |
| 270 | 270 | ||
| 271 | "@effect/vitest": ["@effect/vitest@https://pkg.pr.new/Effect-TS/effect-smol/@effect/vitest@8881a9b", { "peerDependencies": { "effect": "^4.0.0-beta.25", "vitest": "^3.0.0 || ^4.0.0" } }, "sha512-QQxLK156FZVPGYqSUPnEcybDm6e45KLcXb30XcimIKbIxuJLkuyxHQJW2hUu7lxjCoCotj2B4vc96gPKH/3Deg=="], | 271 | "@effect/vitest": ["@effect/vitest@https://pkg.pr.new/Effect-TS/effect-smol/@effect/vitest@8881a9b", { "peerDependencies": { "effect": "^4.0.0-beta.25", "vitest": "^3.0.0 || ^4.0.0" } }], |
| 272 | 272 | ||
| 273 | "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], | 273 | "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], |
| 274 | 274 | ||
| ... | @@ -1010,7 +1010,7 @@ | ... | @@ -1010,7 +1010,7 @@ |
| 1010 | 1010 | ||
| 1011 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], | 1011 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], |
| 1012 | 1012 | ||
| 1013 | "effect": ["effect@https://pkg.pr.new/Effect-TS/effect-smol/effect@8881a9b", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-tZcsKgsLpQ5p1T5/duJHebWAqyG8owTuJdASj/2V+WPMuDlnB+uKvetMMXJsrNOyElUb3lVFeF2Mq00BbCnL9g=="], | 1013 | "effect": ["effect@https://pkg.pr.new/Effect-TS/effect-smol/effect@8881a9b", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }], |
| 1014 | 1014 | ||
| 1015 | "electron": ["electron@40.6.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-ett8W+yOFGDuM0vhJMamYSkrbV3LoaffzJd9GfjI96zRAxyrNqUSKqBpf/WGbQCweDxX2pkUCUfrv4wwKpsFZA=="], | 1015 | "electron": ["electron@40.6.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-ett8W+yOFGDuM0vhJMamYSkrbV3LoaffzJd9GfjI96zRAxyrNqUSKqBpf/WGbQCweDxX2pkUCUfrv4wwKpsFZA=="], |
| 1016 | 1016 |