From b0fc5bb3f90341b2059c16f76a942e1df4b71867 Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 11:07:58 +0200 Subject: [PATCH 01/12] feat(graph): add sectioned graph layout --- .gitignore | 1 + src/modules/graph/components/graph-canvas.tsx | 41 +- src/modules/graph/components/section-node.tsx | 35 ++ src/modules/graph/components/summary-node.tsx | 53 ++ src/modules/graph/lib/to-xyflow.test.ts | 69 ++- src/modules/graph/lib/to-xyflow.ts | 537 +++++++++++++++--- src/modules/graph/types.ts | 21 + src/modules/parser/dump.ts | 4 +- tests/fixtures/api/postController.ts | 38 -- tests/fixtures/api/userController.ts | 22 - tests/fixtures/db/database.ts | 33 -- tests/fixtures/index.ts | 23 - tests/fixtures/models/post.ts | 27 - tests/fixtures/models/user.ts | 27 - tests/fixtures/services/postService.ts | 44 -- tests/fixtures/services/userService.ts | 38 -- tests/fixtures/utils/format.ts | 18 - tests/fixtures/utils/validate.ts | 20 - 18 files changed, 679 insertions(+), 372 deletions(-) create mode 100644 src/modules/graph/components/section-node.tsx create mode 100644 src/modules/graph/components/summary-node.tsx delete mode 100644 tests/fixtures/api/postController.ts delete mode 100644 tests/fixtures/api/userController.ts delete mode 100644 tests/fixtures/db/database.ts delete mode 100644 tests/fixtures/index.ts delete mode 100644 tests/fixtures/models/post.ts delete mode 100644 tests/fixtures/models/user.ts delete mode 100644 tests/fixtures/services/postService.ts delete mode 100644 tests/fixtures/services/userService.ts delete mode 100644 tests/fixtures/utils/format.ts delete mode 100644 tests/fixtures/utils/validate.ts diff --git a/.gitignore b/.gitignore index 263c3a2..81b203e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ dist-ssr .vinxi __unconfig* todos.json +.graphy/ .idea release/ dist-electron diff --git a/src/modules/graph/components/graph-canvas.tsx b/src/modules/graph/components/graph-canvas.tsx index bddec61..a6c5d87 100644 --- a/src/modules/graph/components/graph-canvas.tsx +++ b/src/modules/graph/components/graph-canvas.tsx @@ -13,30 +13,51 @@ import { CodeNode } from '@/modules/graph/components/code-node' import { EmptyState } from '@/modules/graph/components/empty-state' import { FunctionSheet } from '@/modules/graph/components/function-sheet' import type { FunctionSheetTarget } from '@/modules/graph/components/function-sheet' +import { SectionNode } from '@/modules/graph/components/section-node' +import { SummaryNode } from '@/modules/graph/components/summary-node' import { useGraph } from '@/modules/graph/hooks/use-graph' import { useProject } from '@/modules/graph/hooks/use-project' import { toXYFlow } from '@/modules/graph/lib/to-xyflow' -import type { CodeNodeData } from '@/modules/graph/types' +import type { GraphNodeData } from '@/modules/graph/types' import { clearGraphFocus, useGraphFocusRequest } from '@/shared/lib/graph-focus' -const nodeTypes: NodeTypes = { code: CodeNode } +const nodeTypes: NodeTypes = { + code: CodeNode, + section: SectionNode, + summary: SummaryNode, +} export function GraphCanvas() { const { graph, folder, loading, error } = useGraph() const { recents, openFolder, openRecent } = useProject() const { fitView } = useReactFlow() - const [nodes, setNodes, onNodesChange] = useNodesState>([]) + const [nodes, setNodes, onNodesChange] = useNodesState>( + [], + ) const [edges, setEdges, onEdgesChange] = useEdgesState([]) const [layouting, setLayouting] = useState(false) const [layoutError, setLayoutError] = useState(null) const [sheetTarget, setSheetTarget] = useState( null, ) + const [expandedGroups, setExpandedGroups] = useState>( + () => new Set(), + ) const focusRequest = useGraphFocusRequest() const lastFocusTs = useRef(0) const handleNodeClick = useCallback( - (_event: unknown, node: Node) => { + (_event: unknown, node: Node) => { + if (node.data.kind === 'summary') { + setExpandedGroups((current) => { + const next = new Set(current) + next.add(node.id) + return next + }) + return + } + if (node.data.kind === 'section') return + setSheetTarget({ displayName: node.data.displayName, file: node.data.file, @@ -51,6 +72,10 @@ export function GraphCanvas() { if (!open) setSheetTarget(null) }, []) + useEffect(() => { + setExpandedGroups(new Set()) + }, [graph]) + useEffect(() => { let cancelled = false let fitFrame: number | null = null @@ -68,7 +93,7 @@ export function GraphCanvas() { setLayouting(true) setLayoutError(null) - toXYFlow(graph) + toXYFlow(graph, { expandedGroups }) .then((xyflow) => { if (cancelled) return setNodes(xyflow.nodes) @@ -89,13 +114,15 @@ export function GraphCanvas() { cancelled = true if (fitFrame !== null) window.cancelAnimationFrame(fitFrame) } - }, [fitView, graph, setNodes, setEdges]) + }, [expandedGroups, fitView, graph, setNodes, setEdges]) useEffect(() => { if (!focusRequest || focusRequest.timestamp === lastFocusTs.current) return lastFocusTs.current = focusRequest.timestamp const matching = nodes - .filter((n) => n.data.file === focusRequest.file) + .filter( + (n) => n.data.kind === 'code' && n.data.file === focusRequest.file, + ) .map((n) => n.id) if (matching.length > 0) { fitView({ diff --git a/src/modules/graph/components/section-node.tsx b/src/modules/graph/components/section-node.tsx new file mode 100644 index 0000000..a7c3bb0 --- /dev/null +++ b/src/modules/graph/components/section-node.tsx @@ -0,0 +1,35 @@ +import type { NodeProps } from '@xyflow/react' +import { CornerRightDown } from 'lucide-react' +import { memo } from 'react' + +import type { SectionNodeData } from '@/modules/graph/types' + +type SectionNodeProps = NodeProps & { data: SectionNodeData } + +function SectionNodeImpl({ data, selected }: SectionNodeProps) { + return ( +
+
+ +
+
+ {data.label} +
+
+ {data.subtitle} +
+
+
+
+ ) +} + +export const SectionNode = memo(SectionNodeImpl) diff --git a/src/modules/graph/components/summary-node.tsx b/src/modules/graph/components/summary-node.tsx new file mode 100644 index 0000000..7e85142 --- /dev/null +++ b/src/modules/graph/components/summary-node.tsx @@ -0,0 +1,53 @@ +import { Handle, Position } from '@xyflow/react' +import type { NodeProps } from '@xyflow/react' +import { Layers } from 'lucide-react' +import { memo } from 'react' + +import type { SummaryNodeData } from '@/modules/graph/types' + +type SummaryNodeProps = NodeProps & { data: SummaryNodeData } + +function SummaryNodeImpl({ data, selected }: SummaryNodeProps) { + return ( +
+ + +
+
+ + + {data.label} + +
+ +
+ {data.subtitle} +
+
+ + + +
+ ) +} + +export const SummaryNode = memo(SummaryNodeImpl) diff --git a/src/modules/graph/lib/to-xyflow.test.ts b/src/modules/graph/lib/to-xyflow.test.ts index 2e956c9..e0fb551 100644 --- a/src/modules/graph/lib/to-xyflow.test.ts +++ b/src/modules/graph/lib/to-xyflow.test.ts @@ -4,20 +4,50 @@ import type { Graph, GraphNode } from '@/modules/parser' import { toXYFlow } from '@/modules/graph/lib/to-xyflow' describe('toXYFlow', () => { - it('returns every input node and edge exactly once', async () => { + it('summarizes noisy detail without losing cross-boundary edges', async () => { const graph = makeGraph() const result = await toXYFlow(graph) - expect(result.nodes.map((node) => node.id).sort()).toEqual( - graph.nodes.map((node) => node.id).sort(), + expect(result.nodes.map((node) => node.id).sort()).toEqual([ + 'api/userController.ts::registerUser', + 'db/database.ts::Database.saveUser', + 'index.ts::seedDemo', + 'section:index.ts::seedDemo', + 'services/userService.ts::UserService.create', + 'summary:isolated:utils/format.ts', + 'summary:src/shared/ui', + ]) + expect( + result.edges.map((edge) => `${edge.source}->${edge.target}`), + ).toEqual( + expect.arrayContaining([ + 'api/userController.ts::registerUser->summary:src/shared/ui', + ]), ) - expect(result.edges).toHaveLength(graph.edges.length) expect(new Set(result.edges.map((edge) => edge.id)).size).toBe( - graph.edges.length, + result.edges.length, ) }) + it('places connected nodes inside an entry section', async () => { + const result = await toXYFlow(makeGraph()) + const section = result.nodes.find( + (node) => node.id === 'section:index.ts::seedDemo', + ) + const sectionChildren = result.nodes.filter( + (node) => node.parentId === section?.id, + ) + + expect(section?.type).toBe('section') + expect(sectionChildren.length).toBeGreaterThan(0) + expect( + sectionChildren.every( + (node) => node.position.x >= 0 && node.position.y >= 0, + ), + ).toBe(true) + }) + it('assigns finite numeric positions', async () => { const result = await toXYFlow(makeGraph()) @@ -27,6 +57,19 @@ describe('toXYFlow', () => { } }) + it('expands summarized groups on request', async () => { + const result = await toXYFlow(makeGraph(), { + expandedGroups: ['summary:src/shared/ui'], + }) + + expect(result.nodes.map((node) => node.id)).toContain( + 'src/shared/ui/button.tsx::Button', + ) + expect(result.nodes.map((node) => node.id)).not.toContain( + 'summary:src/shared/ui', + ) + }) + it('places direct callees to the right of their callers', async () => { const result = await toXYFlow(makeGraph()) const byId = new Map(result.nodes.map((node) => [node.id, node])) @@ -87,10 +130,10 @@ describe('toXYFlow', () => { it('keeps disconnected nodes separated from the main flow', async () => { const result = await toXYFlow(makeGraph()) const connectedNodes = result.nodes.filter( - (node) => node.id !== 'utils/format.ts::slugify', + (node) => node.id !== 'summary:isolated:utils/format.ts', ) const unusedNode = result.nodes.find( - (node) => node.id === 'utils/format.ts::slugify', + (node) => node.id === 'summary:isolated:utils/format.ts', ) const connectedBottom = Math.max( ...connectedNodes.map((node) => node.position.y), @@ -157,6 +200,13 @@ function makeGraph(): Graph { file: 'utils/format.ts', line: 1, }), + makeNode({ + id: 'src/shared/ui/button.tsx::Button', + name: 'Button', + file: 'src/shared/ui/button.tsx', + line: 4, + inDegree: 1, + }), ], edges: [ { @@ -179,6 +229,11 @@ function makeGraph(): Graph { target: 'db/database.ts::Database.saveUser', type: 'calls', }, + { + source: 'api/userController.ts::registerUser', + target: 'src/shared/ui/button.tsx::Button', + type: 'calls', + }, ], } } diff --git a/src/modules/graph/lib/to-xyflow.ts b/src/modules/graph/lib/to-xyflow.ts index feb6ce7..ac71ee3 100644 --- a/src/modules/graph/lib/to-xyflow.ts +++ b/src/modules/graph/lib/to-xyflow.ts @@ -3,51 +3,47 @@ import ELK from 'elkjs/lib/elk.bundled.js' import type { ElkExtendedEdge, ElkNode } from 'elkjs/lib/elk.bundled.js' import type { Graph } from '@/modules/parser' -import type { CodeNodeData } from '@/modules/graph/types' +import type { + CodeNodeData, + GraphNodeData, + SectionNodeData, + SummaryNodeData, +} from '@/modules/graph/types' const NODE_WIDTH = 240 const NODE_HEIGHT = 54 const COLUMN_X_TOLERANCE = 8 -const MIN_COLUMN_NODE_GAP = 42 -const UNUSED_COLUMNS = 4 +const MIN_COLUMN_NODE_GAP = 18 +const COMPONENT_ROW_WIDTH = 3600 +const COMPONENT_GAP_X = 220 +const COMPONENT_GAP_Y = 160 +const SECTION_PADDING_X = 48 +const SECTION_PADDING_TOP = 82 +const SECTION_PADDING_BOTTOM = 42 +const SECTION_MIN_SIZE = 420 +const UNUSED_COLUMNS = 6 const UNUSED_COLUMN_GAP = 300 -const UNUSED_ROW_GAP = 120 -const UNUSED_SECTION_GAP = 280 +const UNUSED_ROW_GAP = 92 +const UNUSED_SECTION_GAP = 180 const elk = new ELK() export interface XYFlowGraph { - nodes: Array> + nodes: Array> edges: Array } -export async function toXYFlow(graph: Graph): Promise { - const nodes = graph.nodes.map>((node) => ({ - id: node.id, - type: 'code', - position: { x: 0, y: 0 }, - data: { - displayName: qualifiedName(node.id, node.name), - type: node.type, - signature: node.signature, - file: node.file, - line: node.line, - endLine: node.endLine, - isAsync: node.isAsync, - isExported: node.isExported, - isStatic: node.isStatic, - bodyLines: node.bodyLines, - inDegree: node.inDegree, - outDegree: node.outDegree, - }, - })) +export interface XYFlowOptions { + expandedGroups?: Iterable +} - const edges = graph.edges.map((edge, index) => ({ - id: `${edge.source}->${edge.target}:${edge.type}:${index}`, - source: edge.source, - target: edge.target, - className: 'graph-edge', - })) +export async function toXYFlow( + graph: Graph, + options: XYFlowOptions = {}, +): Promise { + const summarized = summarizeGraph(graph, options) + const nodes = summarized.nodes + const edges = summarized.edges if (nodes.length === 0) return { nodes, edges } @@ -67,21 +63,115 @@ export async function toXYFlow(graph: Graph): Promise { } } + const layoutedConnectedNodes = packComponents( + await Promise.all( + splitConnectedComponents(connectedNodes, edges).map((component) => + layoutComponent(component.nodes, component.edges), + ), + ), + ) + const unusedOrigin = unusedShelfOrigin(layoutedConnectedNodes) + + return { + nodes: [ + ...layoutedConnectedNodes, + ...placeUnusedNodes(unusedNodes, unusedOrigin), + ], + edges, + } +} + +interface ConnectedComponent { + nodes: Array> + edges: Array +} + +interface LayoutedComponent { + nodes: Array> + width: number + height: number +} + +function splitConnectedComponents( + nodes: Array>, + edges: Array, +): ConnectedComponent[] { + const nodesById = new Map(nodes.map((node) => [node.id, node])) + const adjacency = new Map>() + + for (const node of nodes) adjacency.set(node.id, new Set()) + + for (const edge of edges) { + if (!nodesById.has(edge.source) || !nodesById.has(edge.target)) continue + adjacency.get(edge.source)?.add(edge.target) + adjacency.get(edge.target)?.add(edge.source) + } + + const visited = new Set() + const components: ConnectedComponent[] = [] + + for (const node of nodes) { + if (visited.has(node.id)) continue + + const stack = [node.id] + const componentIds = new Set() + + while (stack.length > 0) { + const id = stack.pop() + if (!id || visited.has(id)) continue + + visited.add(id) + componentIds.add(id) + + for (const next of adjacency.get(id) ?? []) { + if (!visited.has(next)) stack.push(next) + } + } + + components.push({ + nodes: nodes.filter((candidate) => componentIds.has(candidate.id)), + edges: edges.filter( + (edge) => + componentIds.has(edge.source) && componentIds.has(edge.target), + ), + }) + } + + return components.sort((a, b) => b.nodes.length - a.nodes.length) +} + +async function layoutComponent( + nodes: Array>, + edges: Array, +): Promise { + if (nodes.length === 0) return { nodes: [], width: 0, height: 0 } + + if (nodes.length === 1) { + const node = nodes[0] + const framed = frameComponent([node], edges) + + return { + nodes: framed.nodes, + width: framed.width, + height: framed.height, + } + } + const layoutedGraph = await elk.layout({ id: 'root', layoutOptions: { 'elk.algorithm': 'layered', 'elk.direction': 'RIGHT', 'elk.edgeRouting': 'ORTHOGONAL', - 'elk.spacing.nodeNode': '76', - 'elk.layered.spacing.nodeNodeBetweenLayers': '150', - 'elk.layered.spacing.edgeEdgeBetweenLayers': '32', - 'elk.layered.spacing.edgeNodeBetweenLayers': '48', + 'elk.spacing.nodeNode': '44', + 'elk.layered.spacing.nodeNodeBetweenLayers': '135', + 'elk.layered.spacing.edgeEdgeBetweenLayers': '18', + 'elk.layered.spacing.edgeNodeBetweenLayers': '28', 'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX', 'elk.layered.crossingMinimization.strategy': 'LAYER_SWEEP', 'elk.layered.cycleBreaking.strategy': 'GREEDY', }, - children: connectedNodes.map((node) => ({ + children: nodes.map((node) => ({ id: node.id, width: NODE_WIDTH, height: NODE_HEIGHT, @@ -96,36 +186,155 @@ export async function toXYFlow(graph: Graph): Promise { const layoutedById = new Map( layoutedGraph.children?.map((node) => [node.id, node]) ?? [], ) - const layoutedConnectedNodes = resolveColumnOverlaps( - centerEntryNodes( - connectedNodes.map((node) => { - const layoutedNode = layoutedById.get(node.id) - return { - ...node, - position: { - x: layoutedNode?.x ?? node.position.x, - y: layoutedNode?.y ?? node.position.y, - }, - } - }), - edges, + const layoutedNodes = normalizeNodes( + resolveColumnOverlaps( + centerEntryNodes( + nodes.map((node) => { + const layoutedNode = layoutedById.get(node.id) + return { + ...node, + position: { + x: layoutedNode?.x ?? node.position.x, + y: layoutedNode?.y ?? node.position.y, + }, + } + }), + edges, + ), ), ) - const unusedOrigin = unusedShelfOrigin(layoutedConnectedNodes) + const bounds = nodeBounds(layoutedNodes) + const framed = frameComponent(layoutedNodes, edges) return { - nodes: [ - ...layoutedConnectedNodes, - ...placeUnusedNodes(unusedNodes, unusedOrigin), - ], - edges, + nodes: framed.nodes, + width: Math.max(bounds.width, framed.width), + height: Math.max(bounds.height, framed.height), + } +} + +function frameComponent( + nodes: Array>, + edges: Array, +): LayoutedComponent { + const bounds = nodeBounds(nodes) + const width = Math.max(bounds.width + SECTION_PADDING_X * 2, SECTION_MIN_SIZE) + const height = Math.max( + bounds.height + SECTION_PADDING_TOP + SECTION_PADDING_BOTTOM, + SECTION_MIN_SIZE, + ) + const sectionId = `section:${entryNodeIds(nodes, edges).join('|') || nodes[0]?.id || 'empty'}` + const label = sectionLabel(nodes, edges) + const childNodes = nodes.map((node) => ({ + ...node, + parentId: sectionId, + extent: 'parent' as const, + position: { + x: node.position.x + SECTION_PADDING_X, + y: node.position.y + SECTION_PADDING_TOP, + }, + })) + const sectionNode: Node = { + id: sectionId, + type: 'section', + position: { x: 0, y: 0 }, + selectable: false, + draggable: false, + data: { + kind: 'section', + label: label.title, + subtitle: label.subtitle, + width, + height, + }, + style: { width, height }, + } + + return { + nodes: [sectionNode, ...childNodes], + width, + height, + } +} + +function entryNodeIds( + nodes: Array>, + edges: Array, +): string[] { + const ids = new Set(nodes.map((node) => node.id)) + const incomingIds = new Set( + edges + .filter((edge) => ids.has(edge.source) && ids.has(edge.target)) + .map((edge) => edge.target), + ) + const outgoingIds = new Set( + edges + .filter((edge) => ids.has(edge.source) && ids.has(edge.target)) + .map((edge) => edge.source), + ) + + return nodes + .filter((node) => !incomingIds.has(node.id) && outgoingIds.has(node.id)) + .map((node) => node.id) + .sort() +} + +function sectionLabel( + nodes: Array>, + edges: Array, +): { title: string; subtitle: string } { + const byId = new Map(nodes.map((node) => [node.id, node])) + const entries = entryNodeIds(nodes, edges) + .map((id) => byId.get(id)) + .filter((node): node is Node => Boolean(node)) + const firstEntry = entries.length > 0 ? entries[0] : undefined + let title = 'Entry flow' + if (firstEntry?.data.kind === 'code') title = firstEntry.data.displayName + if (firstEntry?.data.kind === 'summary') title = firstEntry.data.label + const suffix = entries.length > 1 ? ` + ${entries.length - 1} more` : '' + + return { + title: `${title}${suffix}`, + subtitle: `${nodes.length} symbols`, + } +} + +function packComponents( + components: LayoutedComponent[], +): Array> { + const packedNodes: Array> = [] + let x = 0 + let y = 0 + let rowHeight = 0 + + for (const component of components) { + if (x > 0 && x + component.width > COMPONENT_ROW_WIDTH) { + x = 0 + y += rowHeight + COMPONENT_GAP_Y + rowHeight = 0 + } + + packedNodes.push( + ...component.nodes.map((node) => ({ + ...node, + position: { + x: node.parentId ? node.position.x : node.position.x + x, + y: node.parentId ? node.position.y : node.position.y + y, + }, + })), + ) + + x += component.width + COMPONENT_GAP_X + rowHeight = Math.max(rowHeight, component.height) } + + return packedNodes } function resolveColumnOverlaps( - nodes: Array>, -): Array> { - const columns = new Map>>() + nodes: Array>, +): Array> { + const columns = new Map>>() for (const node of nodes) { const columnKey = @@ -182,9 +391,9 @@ function resolveColumnOverlaps( } function centerEntryNodes( - nodes: Array>, + nodes: Array>, edges: Array, -): Array> { +): Array> { const nodesById = new Map(nodes.map((node) => [node.id, node])) const incomingIds = new Set(edges.map((edge) => edge.target)) const targetsBySource = new Map() @@ -201,7 +410,7 @@ function centerEntryNodes( .map((node) => { const targetCenters = (targetsBySource.get(node.id) ?? []) .map((targetId) => nodesById.get(targetId)) - .filter((target): target is Node => Boolean(target)) + .filter((target): target is Node => Boolean(target)) .map((target) => target.position.y + NODE_HEIGHT / 2) .sort((a, b) => a - b) const desiredCenter = median(targetCenters) @@ -245,10 +454,52 @@ function median(values: number[]): number { return ((values[middle - 1] ?? 0) + (values[middle] ?? 0)) / 2 } +function normalizeNodes( + nodes: Array>, +): Array> { + const bounds = nodeBounds(nodes) + + return nodes.map((node) => ({ + ...node, + position: { + x: node.position.x - bounds.minX, + y: node.position.y - bounds.minY, + }, + })) +} + +function nodeBounds(nodes: Array>): { + minX: number + minY: number + width: number + height: number +} { + const bounds = nodes.reduce( + (acc, node) => ({ + minX: Math.min(acc.minX, node.position.x), + minY: Math.min(acc.minY, node.position.y), + maxX: Math.max(acc.maxX, node.position.x + NODE_WIDTH), + maxY: Math.max(acc.maxY, node.position.y + NODE_HEIGHT), + }), + { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity }, + ) + + if (!Number.isFinite(bounds.minX) || !Number.isFinite(bounds.minY)) { + return { minX: 0, minY: 0, width: 0, height: 0 } + } + + return { + minX: bounds.minX, + minY: bounds.minY, + width: bounds.maxX - bounds.minX, + height: bounds.maxY - bounds.minY, + } +} + function placeUnusedNodes( - nodes: Array>, + nodes: Array>, origin: { x: number; y: number }, -): Array> { +): Array> { return nodes.map((node, index) => ({ ...node, position: { @@ -258,14 +509,14 @@ function placeUnusedNodes( })) } -function unusedShelfOrigin(nodes: Array>): { +function unusedShelfOrigin(nodes: Array>): { x: number y: number } { const bounds = nodes.reduce( (acc, node) => ({ minX: Math.min(acc.minX, node.position.x), - maxY: Math.max(acc.maxY, node.position.y + NODE_HEIGHT), + maxY: Math.max(acc.maxY, node.position.y + nodeHeight(node)), }), { minX: Infinity, maxY: -Infinity }, ) @@ -276,7 +527,161 @@ function unusedShelfOrigin(nodes: Array>): { } } +function nodeHeight(node: Node): number { + return node.data.kind === 'section' ? node.data.height : NODE_HEIGHT +} + function qualifiedName(id: string, fallback: string): string { const idx = id.indexOf('::') return idx >= 0 ? id.slice(idx + 2) : fallback } + +function summarizeGraph(graph: Graph, options: XYFlowOptions): XYFlowGraph { + const expandedGroups = new Set(options.expandedGroups ?? []) + const groups = new Map< + string, + { + data: Omit + memberIds: Set + files: Set + } + >() + const visibleIdByOriginalId = new Map() + const visibleNodes: Array> = [] + + for (const node of graph.nodes) { + const group = groupForNode(node) + if (!group || expandedGroups.has(group.id)) { + visibleIdByOriginalId.set(node.id, node.id) + visibleNodes.push({ + id: node.id, + type: 'code', + position: { x: 0, y: 0 }, + data: { + kind: 'code', + displayName: qualifiedName(node.id, node.name), + type: node.type, + signature: node.signature, + file: node.file, + line: node.line, + endLine: node.endLine, + isAsync: node.isAsync, + isExported: node.isExported, + isStatic: node.isStatic, + bodyLines: node.bodyLines, + inDegree: node.inDegree, + outDegree: node.outDegree, + }, + }) + continue + } + + const existing = groups.get(group.id) ?? { + data: { + kind: 'summary' as const, + label: group.label, + subtitle: group.subtitle, + count: 0, + fileCount: 0, + }, + memberIds: new Set(), + files: new Set(), + } + existing.data.count += 1 + existing.memberIds.add(node.id) + existing.files.add(node.file) + groups.set(group.id, existing) + visibleIdByOriginalId.set(node.id, group.id) + } + + const edgeKeys = new Set() + const visibleEdges: Edge[] = [] + + for (const edge of graph.edges) { + const source = visibleIdByOriginalId.get(edge.source) + const target = visibleIdByOriginalId.get(edge.target) + if (!source || !target || source === target) continue + + const key = `${source}->${target}:${edge.type}` + if (edgeKeys.has(key)) continue + edgeKeys.add(key) + + visibleEdges.push({ + id: key, + source, + target, + className: 'graph-edge', + }) + } + + const degreeById = new Map() + for (const edge of visibleEdges) { + const sourceDegree = degreeById.get(edge.source) ?? { + inDegree: 0, + outDegree: 0, + } + sourceDegree.outDegree += 1 + degreeById.set(edge.source, sourceDegree) + + const targetDegree = degreeById.get(edge.target) ?? { + inDegree: 0, + outDegree: 0, + } + targetDegree.inDegree += 1 + degreeById.set(edge.target, targetDegree) + } + + for (const [id, group] of groups) { + const degree = degreeById.get(id) ?? { inDegree: 0, outDegree: 0 } + visibleNodes.push({ + id, + type: 'summary', + position: { x: 0, y: 0 }, + data: { + ...group.data, + fileCount: group.files.size, + subtitle: `${group.data.subtitle} · ${group.data.count} symbols`, + inDegree: degree.inDegree, + outDegree: degree.outDegree, + }, + }) + } + + return { nodes: visibleNodes, edges: visibleEdges } +} + +function groupForNode(node: Graph['nodes'][number]): + | { + id: string + label: string + subtitle: string + } + | undefined { + if (node.file.startsWith('src/shared/ui/')) { + return { + id: 'summary:src/shared/ui', + label: 'UI primitives', + subtitle: 'src/shared/ui', + } + } + + if (node.inDegree === 0 && node.outDegree === 0) { + const folder = summaryFolder(node.file) + return { + id: `summary:isolated:${folder}`, + label: 'Unconnected symbols', + subtitle: folder, + } + } + + return undefined +} + +function summaryFolder(file: string): string { + const parts = file.split('/') + if (parts.length <= 1) return file + if (parts[0] === 'src' && parts.length >= 3) { + return parts.slice(0, 3).join('/') + } + return parts.slice(0, 2).join('/') +} diff --git a/src/modules/graph/types.ts b/src/modules/graph/types.ts index 770b49f..f72bd20 100644 --- a/src/modules/graph/types.ts +++ b/src/modules/graph/types.ts @@ -1,6 +1,7 @@ import type { NodeType } from '@/modules/parser' export type CodeNodeData = { + kind: 'code' displayName: string type: NodeType signature: string @@ -14,3 +15,23 @@ export type CodeNodeData = { inDegree: number outDegree: number } + +export type SummaryNodeData = { + kind: 'summary' + label: string + subtitle: string + count: number + fileCount: number + inDegree: number + outDegree: number +} + +export type SectionNodeData = { + kind: 'section' + label: string + subtitle: string + width: number + height: number +} + +export type GraphNodeData = CodeNodeData | SummaryNodeData | SectionNodeData diff --git a/src/modules/parser/dump.ts b/src/modules/parser/dump.ts index 6ee6f96..fa1dec8 100644 --- a/src/modules/parser/dump.ts +++ b/src/modules/parser/dump.ts @@ -11,8 +11,8 @@ export interface DumpResult { export function dumpGraph(root: string): DumpResult { const graph = parseProject(root) - const outDir = path.join(process.cwd(), 'public') - const outPath = path.join(outDir, 'sample-graph.json') + const outDir = path.join(process.cwd(), '.graphy') + const outPath = path.join(outDir, 'graph-dump.json') mkdirSync(outDir, { recursive: true }) writeFileSync(outPath, serializeGraph(graph)) diff --git a/tests/fixtures/api/postController.ts b/tests/fixtures/api/postController.ts deleted file mode 100644 index c212ad4..0000000 --- a/tests/fixtures/api/postController.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { postService } from '../services/postService' -import { formatDate, truncate } from '../utils/format' - -export interface PostSummary { - slug: string - title: string - preview: string - publishedAt: string | null -} - -export function createPost(input: { - authorId: string - title: string - body: string -}): PostSummary { - const post = postService.create(input) - return summarize(post) -} - -export function publishPost(id: string): PostSummary { - const post = postService.publish(id) - return summarize(post) -} - -export function listAuthorPosts(authorId: string): PostSummary[] { - return postService.byAuthor(authorId).map(summarize) -} - -function summarize(post: ReturnType): PostSummary { - return { - slug: post.slug, - title: truncate(post.record.title, 60), - preview: post.preview(), - publishedAt: post.record.publishedAt - ? formatDate(post.record.publishedAt) - : null, - } -} diff --git a/tests/fixtures/api/userController.ts b/tests/fixtures/api/userController.ts deleted file mode 100644 index d431f66..0000000 --- a/tests/fixtures/api/userController.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { userService } from '../services/userService' -import { capitalize } from '../utils/format' - -export function registerUser(input: { - email: string - displayName: string - role: 'admin' | 'reader' | 'author' -}): { id: string; displayName: string } { - const user = userService.create({ - email: input.email, - displayName: capitalize(input.displayName), - role: input.role, - }) - return user.toPublic() -} - -export function fetchUser( - id: string, -): { id: string; displayName: string } | null { - const user = userService.get(id) - return user ? user.toPublic() : null -} diff --git a/tests/fixtures/db/database.ts b/tests/fixtures/db/database.ts deleted file mode 100644 index 1cc3f7e..0000000 --- a/tests/fixtures/db/database.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { UserRecord } from '../models/user' -import type { PostRecord } from '../models/post' - -export class Database { - private users = new Map() - private posts = new Map() - - saveUser(record: UserRecord): void { - this.users.set(record.id, record) - } - - findUser(id: string): UserRecord | undefined { - return this.users.get(id) - } - - savePost(record: PostRecord): void { - this.posts.set(record.id, record) - } - - findPost(id: string): PostRecord | undefined { - return this.posts.get(id) - } - - listPostsByAuthor(authorId: string): PostRecord[] { - const all: PostRecord[] = [] - for (const post of this.posts.values()) { - if (post.authorId === authorId) all.push(post) - } - return all - } -} - -export const db = new Database() diff --git a/tests/fixtures/index.ts b/tests/fixtures/index.ts deleted file mode 100644 index 1c4e23d..0000000 --- a/tests/fixtures/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { registerUser } from './api/userController' -import { createPost, listAuthorPosts, publishPost } from './api/postController' - -function seedDemo(): void { - const author = registerUser({ - email: 'alice@example.com', - displayName: 'alice', - role: 'author', - }) - - const draft = createPost({ - authorId: author.id, - title: 'Hello, Graphy', - body: 'A short post body that the parser will summarize.', - }) - - publishPost(draft.slug) - - const all = listAuthorPosts(author.id) - console.log(`Author ${author.displayName} has ${all.length} post(s)`) -} - -seedDemo() diff --git a/tests/fixtures/models/post.ts b/tests/fixtures/models/post.ts deleted file mode 100644 index 71c059e..0000000 --- a/tests/fixtures/models/post.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { slugify } from '../utils/format' - -export interface PostRecord { - id: string - authorId: string - title: string - body: string - publishedAt: Date | null -} - -export class Post { - constructor(public record: PostRecord) {} - - get slug(): string { - return slugify(this.record.title) - } - - isPublished(): boolean { - return this.record.publishedAt !== null - } - - preview(maxLength = 140): string { - const body = this.record.body - if (body.length <= maxLength) return body - return `${body.slice(0, maxLength - 1).trimEnd()}…` - } -} diff --git a/tests/fixtures/models/user.ts b/tests/fixtures/models/user.ts deleted file mode 100644 index 4b60501..0000000 --- a/tests/fixtures/models/user.ts +++ /dev/null @@ -1,27 +0,0 @@ -export interface UserRecord { - id: string - email: string - displayName: string - role: 'admin' | 'reader' | 'author' - createdAt: Date -} - -export class User { - constructor(public record: UserRecord) {} - - get id(): string { - return this.record.id - } - - canPublish(): boolean { - return this.record.role === 'admin' || this.record.role === 'author' - } - - canModerate(): boolean { - return this.record.role === 'admin' - } - - toPublic(): Pick { - return { id: this.record.id, displayName: this.record.displayName } - } -} diff --git a/tests/fixtures/services/postService.ts b/tests/fixtures/services/postService.ts deleted file mode 100644 index 3a5f570..0000000 --- a/tests/fixtures/services/postService.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { db } from '../db/database' -import { Post } from '../models/post' -import type { PostRecord } from '../models/post' -import { userService } from './userService' -import { assertTitle } from '../utils/validate' - -export class PostService { - create(input: { authorId: string; title: string; body: string }): Post { - assertTitle(input.title) - const author = userService.get(input.authorId) - if (!author) throw new Error(`Unknown author: ${input.authorId}`) - if (!author.canPublish()) { - throw new Error(`User ${author.id} is not allowed to publish`) - } - - const record: PostRecord = { - id: makePostId(), - authorId: input.authorId, - title: input.title, - body: input.body, - publishedAt: null, - } - db.savePost(record) - return new Post(record) - } - - publish(id: string): Post { - const record = db.findPost(id) - if (!record) throw new Error(`Unknown post: ${id}`) - record.publishedAt = new Date() - db.savePost(record) - return new Post(record) - } - - byAuthor(authorId: string): Post[] { - return db.listPostsByAuthor(authorId).map((r) => new Post(r)) - } -} - -function makePostId(): string { - return `p_${Math.random().toString(36).slice(2, 10)}` -} - -export const postService = new PostService() diff --git a/tests/fixtures/services/userService.ts b/tests/fixtures/services/userService.ts deleted file mode 100644 index 00810ff..0000000 --- a/tests/fixtures/services/userService.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { db } from '../db/database' -import { User } from '../models/user' -import type { UserRecord } from '../models/user' -import { assertEmail } from '../utils/validate' - -export class UserService { - create(input: Omit): User { - assertEmail(input.email) - const record: UserRecord = { - id: makeId(), - email: input.email, - displayName: input.displayName, - role: input.role, - createdAt: new Date(), - } - db.saveUser(record) - return new User(record) - } - - get(id: string): User | null { - const record = db.findUser(id) - if (!record) return null - return new User(record) - } -} - -function makeId(): string { - console.log('hello world') - console.log('deuxieme fois') - console.log('troisieme fois') - return Math.random().toString(36).slice(2, 10) -} - -function makeZizi(): string { - return Math.random().toString(36).slice(2, 10) -} - -export const userService = new UserService() diff --git a/tests/fixtures/utils/format.ts b/tests/fixtures/utils/format.ts deleted file mode 100644 index a5d9898..0000000 --- a/tests/fixtures/utils/format.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function slugify(input: string): string { - return input - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, '') -} - -export function formatDate(date: Date): string { - return date.toISOString().slice(0, 10) -} - -export const truncate = (text: string, max: number): string => { - if (text.length <= max) return text - return `${text.slice(0, max - 1)}…` -} - -export const capitalize = (word: string): string => - word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() diff --git a/tests/fixtures/utils/validate.ts b/tests/fixtures/utils/validate.ts deleted file mode 100644 index d9eb7ad..0000000 --- a/tests/fixtures/utils/validate.ts +++ /dev/null @@ -1,20 +0,0 @@ -const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - -export const isEmail = (value: string): boolean => EMAIL_RE.test(value) - -export const isNonEmpty = (value: string): boolean => value.trim().length > 0 - -export function assertEmail(value: string): void { - if (!isEmail(value)) { - throw new Error(`Invalid email: ${value}`) - } -} - -export function assertTitle(value: string): void { - if (!isNonEmpty(value)) { - throw new Error('Title must not be empty') - } - if (value.length > 120) { - throw new Error('Title too long (max 120)') - } -} From f5f30d1136cbf2920fcdc6c85b79f39579578f33 Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 11:12:47 +0200 Subject: [PATCH 02/12] feat(graph): update edge styles and node surface class --- src/app/styles.css | 28 +++++++++---------- src/modules/graph/components/code-node.tsx | 6 ++-- src/modules/graph/components/graph-canvas.tsx | 17 +++++++++-- src/modules/graph/components/section-node.tsx | 4 +-- src/modules/graph/components/summary-node.tsx | 4 +-- src/modules/graph/lib/to-xyflow.ts | 4 +++ 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/app/styles.css b/src/app/styles.css index 2b4440d..e7dfda2 100644 --- a/src/app/styles.css +++ b/src/app/styles.css @@ -265,24 +265,20 @@ body { .react-flow__edge.graph-edge .react-flow__edge-path { stroke: color-mix(in oklab, var(--muted-foreground) 46%, transparent); - stroke-width: 1.25; - stroke-dasharray: 7 7; - stroke-linecap: round; - transition: - stroke 160ms ease, - stroke-width 160ms ease, - stroke-dasharray 160ms ease, - filter 160ms ease; + stroke-width: 1; + stroke-linecap: square; + shape-rendering: optimizeSpeed; } .react-flow__edge.graph-edge:hover .react-flow__edge-path, .react-flow__edge.graph-edge.selected .react-flow__edge-path { - stroke: color-mix(in oklab, var(--primary) 72%, white 8%); - stroke-width: 1.8; - stroke-dasharray: none; - filter: drop-shadow( - 0 0 5px color-mix(in oklab, var(--primary) 28%, transparent) - ); + stroke: color-mix(in oklab, var(--muted-foreground) 60%, transparent); +} + +.react-flow__node-code, +.react-flow__node-section, +.react-flow__node-summary { + contain: layout paint style; } @supports (corner-shape: round) { @@ -324,6 +320,10 @@ body { -webkit-backdrop-filter: blur(10px) saturate(120%); } + .graph-node-surface { + background: color-mix(in oklab, var(--card) 90%, transparent); + } + .app-drag { -webkit-app-region: drag; } diff --git a/src/modules/graph/components/code-node.tsx b/src/modules/graph/components/code-node.tsx index 0b3f389..6e3f28d 100644 --- a/src/modules/graph/components/code-node.tsx +++ b/src/modules/graph/components/code-node.tsx @@ -24,10 +24,8 @@ function CodeNodeImpl({ data, selected }: CodeNodeProps) { return (
diff --git a/src/modules/graph/components/graph-canvas.tsx b/src/modules/graph/components/graph-canvas.tsx index a6c5d87..c9f0690 100644 --- a/src/modules/graph/components/graph-canvas.tsx +++ b/src/modules/graph/components/graph-canvas.tsx @@ -174,14 +174,25 @@ export function GraphCanvas() { fitView fitViewOptions={{ padding: 0.25 }} proOptions={{ hideAttribution: true }} + onlyRenderVisibleElements + nodesDraggable={false} + nodesConnectable={false} + nodesFocusable={false} + edgesFocusable={false} + elementsSelectable={false} + elevateNodesOnSelect={false} + elevateEdgesOnSelect={false} + selectNodesOnDrag={false} + zoomOnDoubleClick={false} defaultEdgeOptions={{ - type: 'default', - pathOptions: { curvature: 0.55 }, + type: 'straight', + interactionWidth: 0, + selectable: false, }} minZoom={0.05} maxZoom={2.5} > - + -
+
diff --git a/src/modules/graph/lib/to-xyflow.ts b/src/modules/graph/lib/to-xyflow.ts index ac71ee3..3280b60 100644 --- a/src/modules/graph/lib/to-xyflow.ts +++ b/src/modules/graph/lib/to-xyflow.ts @@ -610,7 +610,11 @@ function summarizeGraph(graph: Graph, options: XYFlowOptions): XYFlowGraph { id: key, source, target, + type: 'straight', className: 'graph-edge', + interactionWidth: 0, + selectable: false, + focusable: false, }) } From 3598751e93d36a0e666821da1f1c5c8ae58c1d00 Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 11:32:07 +0200 Subject: [PATCH 03/12] feat(graph): implement canvas edges and update layout logic --- src/app/styles.css | 5 + src/modules/graph/components/canvas-edges.tsx | 184 ++++++++++++++++++ src/modules/graph/components/graph-canvas.tsx | 23 +-- src/modules/graph/components/section-node.tsx | 23 +-- src/modules/graph/lib/to-xyflow.ts | 21 +- 5 files changed, 213 insertions(+), 43 deletions(-) create mode 100644 src/modules/graph/components/canvas-edges.tsx diff --git a/src/app/styles.css b/src/app/styles.css index e7dfda2..8c657c6 100644 --- a/src/app/styles.css +++ b/src/app/styles.css @@ -275,10 +275,15 @@ body { stroke: color-mix(in oklab, var(--muted-foreground) 60%, transparent); } +.graph-canvas-edges { + color: color-mix(in oklab, var(--muted-foreground) 62%, transparent); +} + .react-flow__node-code, .react-flow__node-section, .react-flow__node-summary { contain: layout paint style; + z-index: 2; } @supports (corner-shape: round) { diff --git a/src/modules/graph/components/canvas-edges.tsx b/src/modules/graph/components/canvas-edges.tsx new file mode 100644 index 0000000..520d14d --- /dev/null +++ b/src/modules/graph/components/canvas-edges.tsx @@ -0,0 +1,184 @@ +import { useStore } from '@xyflow/react' +import type { Edge, Node } from '@xyflow/react' +import { useEffect, useMemo, useRef } from 'react' + +import type { GraphNodeData } from '@/modules/graph/types' + +const CODE_NODE_WIDTH = 240 +const CODE_NODE_HEIGHT = 54 + +type CanvasEdgesProps = { + edges: Edge[] + nodes: Array> +} + +type EdgeEndpoint = { + sourceX: number + sourceY: number + targetX: number + targetY: number +} + +type AbsoluteNode = { + x: number + y: number + width: number + height: number +} + +export function CanvasEdges({ edges, nodes }: CanvasEdgesProps) { + const canvasRef = useRef(null) + const transform = useStore((state) => state.transform) + const width = useStore((state) => state.width) + const height = useStore((state) => state.height) + const edgeEndpoints = useMemo( + () => buildEdgeEndpoints(nodes, edges), + [edges, nodes], + ) + + useEffect(() => { + const canvas = canvasRef.current + if (!canvas) return + + const context = canvas.getContext('2d') + if (!context) return + + const frame = window.requestAnimationFrame(() => { + const ratio = window.devicePixelRatio || 1 + const pixelWidth = Math.max(1, Math.floor(width * ratio)) + const pixelHeight = Math.max(1, Math.floor(height * ratio)) + + if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) { + canvas.width = pixelWidth + canvas.height = pixelHeight + } + + canvas.style.width = `${width}px` + canvas.style.height = `${height}px` + + context.setTransform(ratio, 0, 0, ratio, 0, 0) + context.clearRect(0, 0, width, height) + + if (edgeEndpoints.length === 0) return + + const edgeColor = getComputedStyle(canvas).color + + context.save() + context.translate(transform[0], transform[1]) + context.scale(transform[2], transform[2]) + context.strokeStyle = edgeColor || 'rgba(148, 163, 184, 0.46)' + context.globalAlpha = 0.58 + context.lineWidth = Math.max(1 / transform[2], 0.7) + context.lineCap = 'square' + + const viewLeft = -transform[0] / transform[2] + const viewTop = -transform[1] / transform[2] + const viewRight = viewLeft + width / transform[2] + const viewBottom = viewTop + height / transform[2] + + context.beginPath() + for (const endpoint of edgeEndpoints) { + if ( + !isEdgeVisible(endpoint, viewLeft, viewTop, viewRight, viewBottom) + ) { + continue + } + + context.moveTo(endpoint.sourceX, endpoint.sourceY) + context.lineTo(endpoint.targetX, endpoint.targetY) + } + context.stroke() + context.restore() + }) + + return () => window.cancelAnimationFrame(frame) + }, [edgeEndpoints, height, transform, width]) + + return ( +
+ title={`${data.label} · ${data.subtitle}`} + /> ) } diff --git a/src/modules/graph/lib/to-xyflow.ts b/src/modules/graph/lib/to-xyflow.ts index 3280b60..4883ab1 100644 --- a/src/modules/graph/lib/to-xyflow.ts +++ b/src/modules/graph/lib/to-xyflow.ts @@ -18,9 +18,10 @@ const COMPONENT_ROW_WIDTH = 3600 const COMPONENT_GAP_X = 220 const COMPONENT_GAP_Y = 160 const SECTION_PADDING_X = 48 -const SECTION_PADDING_TOP = 82 +const SECTION_PADDING_TOP = 42 const SECTION_PADDING_BOTTOM = 42 -const SECTION_MIN_SIZE = 420 +const SECTION_MIN_WIDTH = 420 +const SECTION_MIN_HEIGHT = 180 const UNUSED_COLUMNS = 6 const UNUSED_COLUMN_GAP = 300 const UNUSED_ROW_GAP = 92 @@ -218,11 +219,13 @@ function frameComponent( edges: Array, ): LayoutedComponent { const bounds = nodeBounds(nodes) - const width = Math.max(bounds.width + SECTION_PADDING_X * 2, SECTION_MIN_SIZE) - const height = Math.max( - bounds.height + SECTION_PADDING_TOP + SECTION_PADDING_BOTTOM, - SECTION_MIN_SIZE, - ) + const contentWidth = bounds.width + SECTION_PADDING_X * 2 + const contentHeight = + bounds.height + SECTION_PADDING_TOP + SECTION_PADDING_BOTTOM + const width = Math.max(contentWidth, SECTION_MIN_WIDTH) + const height = Math.max(contentHeight, SECTION_MIN_HEIGHT) + const extraX = Math.max(0, width - contentWidth) / 2 + const extraY = Math.max(0, height - contentHeight) / 2 const sectionId = `section:${entryNodeIds(nodes, edges).join('|') || nodes[0]?.id || 'empty'}` const label = sectionLabel(nodes, edges) const childNodes = nodes.map((node) => ({ @@ -230,8 +233,8 @@ function frameComponent( parentId: sectionId, extent: 'parent' as const, position: { - x: node.position.x + SECTION_PADDING_X, - y: node.position.y + SECTION_PADDING_TOP, + x: node.position.x + SECTION_PADDING_X + extraX, + y: node.position.y + SECTION_PADDING_TOP + extraY, }, })) const sectionNode: Node = { From 319d25d0899ca88ca26c63d0919d1d2f6ea6537d Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 11:47:43 +0200 Subject: [PATCH 04/12] feat(graph): expand node types and enhance graph legend --- src/modules/ai/tools/graph/list-nodes.tool.ts | 17 +- src/modules/graph/components/code-node.tsx | 12 + src/modules/graph/components/graph-legend.tsx | 16 + src/modules/parser/core/models.ts | 15 +- src/modules/parser/index.ts | 34 +- src/modules/parser/structureExtractor.ts | 331 ++++++++++++++++++ 6 files changed, 411 insertions(+), 14 deletions(-) create mode 100644 src/modules/parser/structureExtractor.ts diff --git a/src/modules/ai/tools/graph/list-nodes.tool.ts b/src/modules/ai/tools/graph/list-nodes.tool.ts index 79c0e89..fd9bd15 100644 --- a/src/modules/ai/tools/graph/list-nodes.tool.ts +++ b/src/modules/ai/tools/graph/list-nodes.tool.ts @@ -2,7 +2,20 @@ import type { Graph, GraphNode, NodeType } from '@/modules/parser' import type { AiTool } from '../tools.interface' -const NODE_TYPES: NodeType[] = ['function', 'method', 'arrow', 'class'] +const NODE_TYPES: NodeType[] = [ + 'file', + 'route', + 'component', + 'hook', + 'function', + 'method', + 'arrow', + 'class', + 'object', + 'constructor', + 'getter', + 'setter', +] interface ListNodesInput { type?: NodeType @@ -37,7 +50,7 @@ export function createListNodesTool(graph: Graph): AiTool { return { name: 'list_nodes', description: - 'List nodes in the parsed code graph. Each node is a function, method, arrow function, or class. Filters are optional and combine with AND. Use this to discover what exists before asking for details with `get_node` or `inspect_class`.', + 'List nodes in the parsed code graph. Nodes include files, routes, components, hooks, functions, classes, objects, and methods. Filters are optional and combine with AND. Use this to discover what exists before asking for details with `get_node` or `inspect_class`.', inputSchema: { type: 'object', properties: { diff --git a/src/modules/graph/components/code-node.tsx b/src/modules/graph/components/code-node.tsx index 6e3f28d..a32a2a0 100644 --- a/src/modules/graph/components/code-node.tsx +++ b/src/modules/graph/components/code-node.tsx @@ -8,6 +8,10 @@ import type { CodeNodeData } from '@/modules/graph/types' type CodeNodeProps = NodeProps & { data: CodeNodeData } const TYPE_LABEL: Record = { + file: 'file', + route: 'route', + component: 'cmp', + hook: 'hook', function: 'fn', arrow: 'fn', method: 'm', @@ -70,6 +74,14 @@ function CodeNodeImpl({ data, selected }: CodeNodeProps) { function typeAccent(type: NodeType): { bar: string; label: string } { switch (type) { + case 'file': + return { bar: 'bg-muted-foreground', label: 'text-muted-foreground' } + case 'route': + return { bar: 'bg-rose-500', label: 'text-rose-500' } + case 'component': + return { bar: 'bg-node-class', label: 'text-node-class-fg' } + case 'hook': + return { bar: 'bg-node-arrow', label: 'text-node-arrow' } case 'class': case 'object': return { bar: 'bg-node-class', label: 'text-node-class-fg' } diff --git a/src/modules/graph/components/graph-legend.tsx b/src/modules/graph/components/graph-legend.tsx index c233f88..f896abf 100644 --- a/src/modules/graph/components/graph-legend.tsx +++ b/src/modules/graph/components/graph-legend.tsx @@ -6,6 +6,10 @@ import { Button } from '@/shared/ui/button' import { Tooltip, TooltipContent, TooltipTrigger } from '@/shared/ui/tooltip' const LEGEND_ITEMS: { type: NodeType; abbr: string; label: string }[] = [ + { type: 'file', abbr: 'file', label: 'File' }, + { type: 'route', abbr: 'route', label: 'Route file' }, + { type: 'component', abbr: 'cmp', label: 'Component' }, + { type: 'hook', abbr: 'hook', label: 'Hook' }, { type: 'function', abbr: 'fn', label: 'Function' }, { type: 'arrow', abbr: 'fn', label: 'Arrow function' }, { type: 'class', abbr: 'cls', label: 'Class' }, @@ -18,9 +22,15 @@ const LEGEND_ITEMS: { type: NodeType; abbr: string; label: string }[] = [ function accentColor(type: NodeType): string { switch (type) { + case 'file': + return 'bg-muted-foreground' + case 'route': + return 'bg-rose-500' + case 'component': case 'class': case 'object': return 'bg-amber-500' + case 'hook': case 'method': case 'constructor': return 'bg-violet-500' @@ -37,9 +47,15 @@ function accentColor(type: NodeType): string { function labelColor(type: NodeType): string { switch (type) { + case 'file': + return 'text-muted-foreground' + case 'route': + return 'text-rose-500' + case 'component': case 'class': case 'object': return 'text-amber-600' + case 'hook': case 'method': case 'constructor': return 'text-violet-500' diff --git a/src/modules/parser/core/models.ts b/src/modules/parser/core/models.ts index ca33dda..3c56da1 100644 --- a/src/modules/parser/core/models.ts +++ b/src/modules/parser/core/models.ts @@ -6,6 +6,10 @@ import type { Node as TsMorphNode } from 'ts-morph' export type NodeType = + | 'file' + | 'route' + | 'component' + | 'hook' | 'function' | 'method' | 'arrow' @@ -15,7 +19,16 @@ export type NodeType = | 'getter' | 'setter' -export type EdgeType = 'calls' | 'inherits' | 'imports' +export type EdgeType = + | 'owns' + | 'imports' + | 'renders' + | 'uses-hook' + | 'routes-to' + | 'instantiates' + | 'extends' + | 'implements' + | 'passes-callback' export interface GraphNode { id: string diff --git a/src/modules/parser/index.ts b/src/modules/parser/index.ts index 4a8aae9..4adf297 100644 --- a/src/modules/parser/index.ts +++ b/src/modules/parser/index.ts @@ -3,12 +3,16 @@ import path from 'node:path' import { Project, ScriptTarget } from 'ts-morph' import type { Node, SourceFile } from 'ts-morph' -import { extractCalls } from './callExtractor' import { extractClasses } from './classExtractor' import { extractFunctions } from './functionExtractor' import { extractObjects } from './objectExtractor' import type { Graph, GraphEdge, GraphNode } from './core/models' import { SCHEMA_VERSION, validateGraph } from './core/schema' +import { + classifyNode, + extractStructuralEdges, + makeFileNode, +} from './structureExtractor' export type { EdgeType, @@ -53,10 +57,14 @@ function loadSourceFiles(root: string): SourceFile[] { } export function parseProject(root: string): Graph { - const sourceFiles = loadSourceFiles(root) + const sourceFiles = loadSourceFiles(root).filter( + (sourceFile) => !sourceFile.isDeclarationFile(), + ) - // Pass 1 — single walk: collect nodes + the ts-morph-declaration → id map - const nodes: GraphNode[] = [] + // Pass 1 — collect files, symbols, and the ts-morph-declaration → id map. + const nodes: GraphNode[] = sourceFiles.map((sourceFile) => + makeFileNode(root, sourceFile), + ) const declarationMap = new Map() for (const sourceFile of sourceFiles) { @@ -68,16 +76,20 @@ export function parseProject(root: string): Graph { ] for (const { graphNode, declaration } of collected) { - nodes.push(graphNode) - declarationMap.set(declaration, graphNode.id) + const node = classifyNode(graphNode) + nodes.push(node) + declarationMap.set(declaration, node.id) } } - // Pass 2 — resolve call edges using the global declaration map - const edges: GraphEdge[] = [] - for (const sourceFile of sourceFiles) { - edges.push(...extractCalls(sourceFile, declarationMap)) - } + // Pass 2 — resolve structure-first relationships. We intentionally do not + // emit direct call edges here; the graph is organized by app/module shape. + const edges: GraphEdge[] = extractStructuralEdges( + root, + sourceFiles, + declarationMap, + nodes, + ) // Pass 3 — annotate each node with its in/out degree annotateDegrees(nodes, edges) diff --git a/src/modules/parser/structureExtractor.ts b/src/modules/parser/structureExtractor.ts new file mode 100644 index 0000000..d6759ec --- /dev/null +++ b/src/modules/parser/structureExtractor.ts @@ -0,0 +1,331 @@ +import { Node } from 'ts-morph' +import type { GraphEdge, GraphNode } from './core/models' +import { makeNodeId } from './core/models' +import type { SourceFile } from 'ts-morph' +import path from 'node:path' + +export function makeFileNode(root: string, sourceFile: SourceFile): GraphNode { + const file = sourceFile.getFilePath().slice(root.length + 1) + const statements = sourceFile.getStatements() + const endLine = + statements.length > 0 + ? (statements[statements.length - 1]?.getEndLineNumber() ?? 1) + : 1 + + return { + id: fileNodeId(file), + name: file.split('/').at(-1) ?? file, + type: file.startsWith('src/routes/') ? 'route' : 'file', + file, + line: 1, + endLine, + signature: '', + isAsync: false, + isExported: false, + isStatic: false, + bodyLines: endLine, + inDegree: 0, + outDegree: 0, + } +} + +export function extractStructuralEdges( + root: string, + sourceFiles: SourceFile[], + declarationMap: Map, + nodes: GraphNode[], +): GraphEdge[] { + const nodeIds = new Set(nodes.map((node) => node.id)) + const edges: GraphEdge[] = [] + const seen = new Set() + + for (const sourceFile of sourceFiles) { + const file = relativePath(root, sourceFile) + const sourceFileId = fileNodeId(file) + + addOwnershipEdges(edges, seen, sourceFileId, nodes) + addImportEdges(edges, seen, root, sourceFile, sourceFileId, nodeIds) + addJsxEdges(edges, seen, sourceFile, sourceFileId, declarationMap) + addHookEdges(edges, seen, sourceFile, sourceFileId, declarationMap) + addInstantiationEdges(edges, seen, sourceFile, sourceFileId, declarationMap) + addInheritanceEdges(edges, seen, sourceFile, declarationMap) + } + + return edges +} + +export function classifyNode(node: GraphNode): GraphNode { + if (node.type !== 'function' && node.type !== 'arrow') return node + + if (isHookName(node.name)) { + return { ...node, type: 'hook' } + } + + if (isComponentName(node.name)) { + return { ...node, type: 'component' } + } + + return node +} + +function addOwnershipEdges( + edges: GraphEdge[], + seen: Set, + fileId: string, + nodes: GraphNode[], +): void { + const file = fileId.slice('file:'.length) + + for (const node of nodes) { + if (node.id === fileId || node.file !== file) continue + + const ownerId = ownerNodeId(node) + addEdge(edges, seen, ownerId ?? fileId, node.id, 'owns') + } +} + +function addImportEdges( + edges: GraphEdge[], + seen: Set, + root: string, + sourceFile: SourceFile, + sourceFileId: string, + nodeIds: Set, +): void { + for (const importDeclaration of sourceFile.getImportDeclarations()) { + const target = importDeclaration.getModuleSpecifierSourceFile() + if (!target) continue + + const targetId = fileNodeId(relativePath(root, target)) + if (!nodeIds.has(targetId) || targetId === sourceFileId) continue + + addEdge(edges, seen, sourceFileId, targetId, 'imports') + } +} + +function addJsxEdges( + edges: GraphEdge[], + seen: Set, + sourceFile: SourceFile, + sourceFileId: string, + declarationMap: Map, +): void { + const jsxNodes = [ + ...sourceFile.getDescendants().filter(Node.isJsxOpeningElement), + ...sourceFile.getDescendants().filter(Node.isJsxSelfClosingElement), + ] + + for (const jsx of jsxNodes) { + const targetId = resolveSymbolTargetId(jsx.getTagNameNode(), declarationMap) + if (targetId) { + addEdge( + edges, + seen, + resolveSourceId(jsx, declarationMap) ?? sourceFileId, + targetId, + 'renders', + ) + } + + for (const attribute of jsx.getAttributes()) { + if (!Node.isJsxAttribute(attribute)) continue + const expression = attribute.getInitializer() + if (!expression) continue + + for (const identifier of expression + .getDescendants() + .filter(Node.isIdentifier)) { + const callbackId = resolveSymbolTargetId(identifier, declarationMap) + if (!callbackId) continue + + addEdge( + edges, + seen, + resolveSourceId(jsx, declarationMap) ?? sourceFileId, + callbackId, + 'passes-callback', + ) + } + } + } +} + +function addHookEdges( + edges: GraphEdge[], + seen: Set, + sourceFile: SourceFile, + sourceFileId: string, + declarationMap: Map, +): void { + for (const call of sourceFile + .getDescendants() + .filter(Node.isCallExpression)) { + const expression = call.getExpression() + const name = expression.getText() + if (!isHookName(name.split('.').at(-1) ?? name)) continue + + const targetId = resolveSymbolTargetId(expression, declarationMap) + if (!targetId) continue + + addEdge( + edges, + seen, + resolveSourceId(call, declarationMap) ?? sourceFileId, + targetId, + 'uses-hook', + ) + } +} + +function addInstantiationEdges( + edges: GraphEdge[], + seen: Set, + sourceFile: SourceFile, + sourceFileId: string, + declarationMap: Map, +): void { + for (const expression of sourceFile + .getDescendants() + .filter(Node.isNewExpression)) { + const targetId = resolveSymbolTargetId( + expression.getExpression(), + declarationMap, + ) + if (!targetId) continue + + addEdge( + edges, + seen, + resolveSourceId(expression, declarationMap) ?? sourceFileId, + targetId, + 'instantiates', + ) + } +} + +function addInheritanceEdges( + edges: GraphEdge[], + seen: Set, + sourceFile: SourceFile, + declarationMap: Map, +): void { + for (const cls of sourceFile.getClasses()) { + const sourceId = declarationMap.get(cls) + if (!sourceId) continue + + const base = cls.getExtends() + if (base) { + const targetId = resolveSymbolTargetId( + base.getExpression(), + declarationMap, + ) + if (targetId) addEdge(edges, seen, sourceId, targetId, 'extends') + } + + for (const implementation of cls.getImplements()) { + const targetId = resolveSymbolTargetId( + implementation.getExpression(), + declarationMap, + ) + if (targetId) addEdge(edges, seen, sourceId, targetId, 'implements') + } + } +} + +function resolveSymbolTargetId( + node: Node, + declarationMap: Map, +): string | undefined { + const symbol = node.getSymbol() + if (!symbol) return undefined + + const candidates = [symbol] + const aliased = symbol.getAliasedSymbol() + if (aliased) candidates.push(aliased) + + for (const candidate of candidates) { + for (const declaration of candidate.getDeclarations()) { + const id = declarationMap.get(declaration) + if (id) return id + } + } + + return undefined +} + +function resolveSourceId( + node: Node, + declarationMap: Map, +): string | undefined { + let current = node.getParent() + while (current) { + if ( + Node.isFunctionDeclaration(current) || + Node.isMethodDeclaration(current) || + Node.isConstructorDeclaration(current) || + Node.isGetAccessorDeclaration(current) || + Node.isSetAccessorDeclaration(current) + ) { + return declarationMap.get(current) + } + + if (Node.isArrowFunction(current) || Node.isFunctionExpression(current)) { + const parent = current.getParent() + if ( + Node.isVariableDeclaration(parent) || + Node.isPropertyDeclaration(parent) || + Node.isPropertyAssignment(parent) + ) { + return declarationMap.get(parent) + } + return undefined + } + + current = current.getParent() + } + return undefined +} + +function ownerNodeId(node: GraphNode): string | null { + const separator = node.id.indexOf('::') + if (separator < 0) return null + + const file = node.id.slice(0, separator) + const name = node.id.slice(separator + 2) + const dot = name.indexOf('.') + if (dot < 0) return null + + return makeNodeId(file, name.slice(0, dot)) +} + +function addEdge( + edges: GraphEdge[], + seen: Set, + source: string, + target: string, + type: GraphEdge['type'], +): void { + if (source === target) return + + const key = `${source}->${target}:${type}` + if (seen.has(key)) return + + seen.add(key) + edges.push({ source, target, type }) +} + +function fileNodeId(file: string): string { + return `file:${file}` +} + +function relativePath(root: string, sourceFile: SourceFile): string { + return path.relative(root, sourceFile.getFilePath()) +} + +function isComponentName(name: string): boolean { + return /^[A-Z]/.test(name) +} + +function isHookName(name: string): boolean { + return /^use[A-Z0-9]/.test(name) +} From cce20ba9caf666abc25b5d83340eeaec96f70238 Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 13:31:25 +0200 Subject: [PATCH 05/12] refactor(graph): remove file and route types from models --- electron/main.cjs | 40 --- electron/preload.cjs | 3 - src/modules/ai/tools/graph/list-nodes.tool.ts | 4 +- src/modules/graph/components/canvas-edges.tsx | 21 ++ src/modules/graph/components/code-editor.tsx | 16 +- src/modules/graph/components/code-node.tsx | 6 - .../graph/components/function-sheet.tsx | 63 ++--- src/modules/graph/components/graph-canvas.tsx | 4 +- src/modules/graph/components/graph-legend.tsx | 10 - src/modules/graph/lib/to-xyflow.test.ts | 256 ------------------ src/modules/graph/lib/to-xyflow.ts | 2 +- src/modules/parser/bindingExtractor.ts | 117 ++++++++ src/modules/parser/core/models.ts | 6 +- src/modules/parser/index.ts | 26 +- src/modules/parser/referenceExtractor.ts | 69 +++++ src/modules/parser/structureExtractor.ts | 120 ++------ src/shared/lib/desktop.ts | 27 -- 17 files changed, 285 insertions(+), 505 deletions(-) delete mode 100644 src/modules/graph/lib/to-xyflow.test.ts create mode 100644 src/modules/parser/bindingExtractor.ts create mode 100644 src/modules/parser/referenceExtractor.ts diff --git a/electron/main.cjs b/electron/main.cjs index 20f8b3e..edd3a7a 100644 --- a/electron/main.cjs +++ b/electron/main.cjs @@ -71,14 +71,6 @@ async function resolveSafePath(file) { return absoluteFile } -function detectLineEnding(text) { - return text.includes('\r\n') ? '\r\n' : '\n' -} - -function splitLines(text) { - return text.split(/\r\n|\n/) -} - app.setName('Graphy') app.setAppUserModelId('com.ntgrm.graphy') @@ -408,38 +400,6 @@ function registerIpc() { const absolute = await resolveSafePath(file) await fsp.writeFile(absolute, content, 'utf8') }) - - ipcMain.handle('function:read', async (_event, payload) => { - const { file, startLine, endLine } = payload ?? {} - const absolute = await resolveSafePath(file) - const raw = await fsp.readFile(absolute, 'utf8') - const lines = splitLines(raw) - const start = Math.max(1, Number(startLine) | 0) - const end = Math.min(lines.length, Math.max(start, Number(endLine) | 0)) - const slice = lines.slice(start - 1, end).join('\n') - return { source: slice, startLine: start, endLine: end } - }) - - ipcMain.handle('function:write', async (_event, payload) => { - const { file, startLine, endLine, source } = payload ?? {} - if (typeof source !== 'string') { - throw new Error('Missing source content') - } - const absolute = await resolveSafePath(file) - const raw = await fsp.readFile(absolute, 'utf8') - const eol = detectLineEnding(raw) - const lines = splitLines(raw) - const start = Math.max(1, Number(startLine) | 0) - const end = Math.min(lines.length, Math.max(start, Number(endLine) | 0)) - const replacement = source.replace(/\r\n/g, '\n').split('\n') - const next = [ - ...lines.slice(0, start - 1), - ...replacement, - ...lines.slice(end), - ] - await fsp.writeFile(absolute, next.join(eol), 'utf8') - return { endLine: start - 1 + replacement.length } - }) } async function startBundledServer() { diff --git a/electron/preload.cjs b/electron/preload.cjs index 05de23d..a735366 100644 --- a/electron/preload.cjs +++ b/electron/preload.cjs @@ -16,9 +16,6 @@ contextBridge.exposeInMainWorld('graphyDesktop', { clearRecents: () => ipcRenderer.invoke('graphy:clear-recents'), onProject: (handler) => subscribe('project:set', handler), onGraph: (handler) => subscribe('graph:set', handler), - readFunctionSource: (payload) => ipcRenderer.invoke('function:read', payload), - writeFunctionSource: (payload) => - ipcRenderer.invoke('function:write', payload), getFileTree: () => ipcRenderer.invoke('graphy:file-tree'), createFile: (filePath) => ipcRenderer.invoke('graphy:create-file', filePath), createDir: (dirPath) => ipcRenderer.invoke('graphy:create-dir', dirPath), diff --git a/src/modules/ai/tools/graph/list-nodes.tool.ts b/src/modules/ai/tools/graph/list-nodes.tool.ts index fd9bd15..0d1ff8a 100644 --- a/src/modules/ai/tools/graph/list-nodes.tool.ts +++ b/src/modules/ai/tools/graph/list-nodes.tool.ts @@ -3,8 +3,6 @@ import type { Graph, GraphNode, NodeType } from '@/modules/parser' import type { AiTool } from '../tools.interface' const NODE_TYPES: NodeType[] = [ - 'file', - 'route', 'component', 'hook', 'function', @@ -50,7 +48,7 @@ export function createListNodesTool(graph: Graph): AiTool { return { name: 'list_nodes', description: - 'List nodes in the parsed code graph. Nodes include files, routes, components, hooks, functions, classes, objects, and methods. Filters are optional and combine with AND. Use this to discover what exists before asking for details with `get_node` or `inspect_class`.', + 'List nodes in the parsed code graph. Nodes include components, hooks, functions, classes, objects, and methods. Filters are optional and combine with AND. Use this to discover what exists before asking for details with `get_node` or `inspect_class`.', inputSchema: { type: 'object', properties: { diff --git a/src/modules/graph/components/canvas-edges.tsx b/src/modules/graph/components/canvas-edges.tsx index 520d14d..3395125 100644 --- a/src/modules/graph/components/canvas-edges.tsx +++ b/src/modules/graph/components/canvas-edges.tsx @@ -76,6 +76,9 @@ export function CanvasEdges({ edges, nodes }: CanvasEdgesProps) { const viewRight = viewLeft + width / transform[2] const viewBottom = viewTop + height / transform[2] + const arrowLength = 14 + const arrowAngle = Math.PI / 7 + context.beginPath() for (const endpoint of edgeEndpoints) { if ( @@ -86,6 +89,24 @@ export function CanvasEdges({ edges, nodes }: CanvasEdgesProps) { context.moveTo(endpoint.sourceX, endpoint.sourceY) context.lineTo(endpoint.targetX, endpoint.targetY) + + const angle = Math.atan2( + endpoint.targetY - endpoint.sourceY, + endpoint.targetX - endpoint.sourceX, + ) + const wing1X = + endpoint.targetX - arrowLength * Math.cos(angle - arrowAngle) + const wing1Y = + endpoint.targetY - arrowLength * Math.sin(angle - arrowAngle) + const wing2X = + endpoint.targetX - arrowLength * Math.cos(angle + arrowAngle) + const wing2Y = + endpoint.targetY - arrowLength * Math.sin(angle + arrowAngle) + + context.moveTo(wing1X, wing1Y) + context.lineTo(endpoint.targetX, endpoint.targetY) + context.moveTo(wing2X, wing2Y) + context.lineTo(endpoint.targetX, endpoint.targetY) } context.stroke() context.restore() diff --git a/src/modules/graph/components/code-editor.tsx b/src/modules/graph/components/code-editor.tsx index 5cad038..edbaad7 100644 --- a/src/modules/graph/components/code-editor.tsx +++ b/src/modules/graph/components/code-editor.tsx @@ -12,7 +12,7 @@ import { } from '@codemirror/commands' import { javascript } from '@codemirror/lang-javascript' import { indentUnit } from '@codemirror/language' -import { EditorState } from '@codemirror/state' +import { EditorSelection, EditorState } from '@codemirror/state' import { oneDark } from '@codemirror/theme-one-dark' import { EditorView, keymap, lineNumbers } from '@codemirror/view' import { useEffect, useRef } from 'react' @@ -22,6 +22,7 @@ type CodeEditorProps = { onChange: (value: string) => void language?: 'tsx' | 'ts' tabSize?: 2 | 4 + scrollToLine?: number } export function CodeEditor({ @@ -29,6 +30,7 @@ export function CodeEditor({ onChange, language = 'tsx', tabSize = 4, + scrollToLine, }: CodeEditorProps) { const hostRef = useRef(null) const viewRef = useRef(null) @@ -92,5 +94,17 @@ export function CodeEditor({ }) }, [value]) + useEffect(() => { + const view = viewRef.current + if (!view || !scrollToLine) return + const totalLines = view.state.doc.lines + const line = Math.min(Math.max(1, scrollToLine), totalLines) + const pos = view.state.doc.line(line).from + view.dispatch({ + selection: EditorSelection.cursor(pos), + effects: EditorView.scrollIntoView(pos, { y: 'start', yMargin: 24 }), + }) + }, [scrollToLine, value]) + return
} diff --git a/src/modules/graph/components/code-node.tsx b/src/modules/graph/components/code-node.tsx index a32a2a0..88a7d77 100644 --- a/src/modules/graph/components/code-node.tsx +++ b/src/modules/graph/components/code-node.tsx @@ -8,8 +8,6 @@ import type { CodeNodeData } from '@/modules/graph/types' type CodeNodeProps = NodeProps & { data: CodeNodeData } const TYPE_LABEL: Record = { - file: 'file', - route: 'route', component: 'cmp', hook: 'hook', function: 'fn', @@ -74,10 +72,6 @@ function CodeNodeImpl({ data, selected }: CodeNodeProps) { function typeAccent(type: NodeType): { bar: string; label: string } { switch (type) { - case 'file': - return { bar: 'bg-muted-foreground', label: 'text-muted-foreground' } - case 'route': - return { bar: 'bg-rose-500', label: 'text-rose-500' } case 'component': return { bar: 'bg-node-class', label: 'text-node-class-fg' } case 'hook': diff --git a/src/modules/graph/components/function-sheet.tsx b/src/modules/graph/components/function-sheet.tsx index 8fadf3c..5cca3bd 100644 --- a/src/modules/graph/components/function-sheet.tsx +++ b/src/modules/graph/components/function-sheet.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react' import { openFile } from '@/modules/files/lib/open-file' +import { getDesktop } from '@/shared/lib/desktop' import { Button } from '@/shared/ui/button' import { Sheet, @@ -16,40 +17,31 @@ import { CodeEditor } from './code-editor' export type FunctionSheetTarget = { displayName: string file: string - startLine: number - endLine: number + line: number } type FunctionSheetProps = { - root: string | null target: FunctionSheetTarget | null onOpenChange: (open: boolean) => void - onSaved?: (next: { endLine: number }) => void } type Status = 'idle' | 'loading' | 'ready' | 'saving' | 'error' -export function FunctionSheet({ - root, - target, - onOpenChange, - onSaved, -}: FunctionSheetProps) { +export function FunctionSheet({ target, onOpenChange }: FunctionSheetProps) { const [original, setOriginal] = useState('') const [draft, setDraft] = useState('') - const [resolvedEndLine, setResolvedEndLine] = useState(null) const [status, setStatus] = useState('idle') const [errorMessage, setErrorMessage] = useState(null) const open = target !== null useEffect(() => { - if (!target || !root) return - const desktop = window.graphyDesktop - if (!desktop?.readFunctionSource) { + if (!target) return + const desktop = getDesktop() + if (!desktop?.readFile) { setStatus('error') setErrorMessage( - 'Function editing requires the Graphy desktop app (Electron).', + 'File editing requires the Graphy desktop app (Electron).', ) return } @@ -58,17 +50,11 @@ export function FunctionSheet({ setStatus('loading') setErrorMessage(null) desktop - .readFunctionSource({ - root, - file: target.file, - startLine: target.startLine, - endLine: target.endLine, - }) - .then((result) => { + .readFile(target.file) + .then((source) => { if (cancelled) return - setOriginal(result.source) - setDraft(result.source) - setResolvedEndLine(result.endLine) + setOriginal(source) + setDraft(source) setStatus('ready') }) .catch((err: unknown) => { @@ -80,30 +66,22 @@ export function FunctionSheet({ return () => { cancelled = true } - }, [open, root, target]) + }, [target]) const dirty = status === 'ready' && draft !== original const isTsx = target?.file.endsWith('.tsx') ? 'tsx' : 'ts' async function handleSave() { - if (!target || !root || resolvedEndLine === null) return - const desktop = window.graphyDesktop - if (!desktop?.writeFunctionSource) return + if (!target) return + const desktop = getDesktop() + if (!desktop?.writeFile) return setStatus('saving') setErrorMessage(null) try { - const result = await desktop.writeFunctionSource({ - root, - file: target.file, - startLine: target.startLine, - endLine: resolvedEndLine, - source: draft, - }) + await desktop.writeFile(target.file, draft) setOriginal(draft) - setResolvedEndLine(result.endLine) setStatus('ready') - onSaved?.({ endLine: result.endLine }) } catch (err) { setErrorMessage(err instanceof Error ? err.message : String(err)) setStatus('error') @@ -130,7 +108,7 @@ export function FunctionSheet({ openFile(target.file, name) }} > - {target ? `${target.file}:${target.startLine}` : ''} + {target ? `${target.file}:${target.line}` : ''} @@ -147,7 +125,12 @@ export function FunctionSheet({
)} {(status === 'ready' || status === 'saving') && ( - + )}
diff --git a/src/modules/graph/components/graph-canvas.tsx b/src/modules/graph/components/graph-canvas.tsx index 8d976d5..7daad41 100644 --- a/src/modules/graph/components/graph-canvas.tsx +++ b/src/modules/graph/components/graph-canvas.tsx @@ -55,8 +55,7 @@ export function GraphCanvas() { setSheetTarget({ displayName: node.data.displayName, file: node.data.file, - startLine: node.data.line, - endLine: node.data.endLine, + line: node.data.line, }) }, [], @@ -188,7 +187,6 @@ export function GraphCanvas() { diff --git a/src/modules/graph/components/graph-legend.tsx b/src/modules/graph/components/graph-legend.tsx index f896abf..e6d70cb 100644 --- a/src/modules/graph/components/graph-legend.tsx +++ b/src/modules/graph/components/graph-legend.tsx @@ -6,8 +6,6 @@ import { Button } from '@/shared/ui/button' import { Tooltip, TooltipContent, TooltipTrigger } from '@/shared/ui/tooltip' const LEGEND_ITEMS: { type: NodeType; abbr: string; label: string }[] = [ - { type: 'file', abbr: 'file', label: 'File' }, - { type: 'route', abbr: 'route', label: 'Route file' }, { type: 'component', abbr: 'cmp', label: 'Component' }, { type: 'hook', abbr: 'hook', label: 'Hook' }, { type: 'function', abbr: 'fn', label: 'Function' }, @@ -22,10 +20,6 @@ const LEGEND_ITEMS: { type: NodeType; abbr: string; label: string }[] = [ function accentColor(type: NodeType): string { switch (type) { - case 'file': - return 'bg-muted-foreground' - case 'route': - return 'bg-rose-500' case 'component': case 'class': case 'object': @@ -47,10 +41,6 @@ function accentColor(type: NodeType): string { function labelColor(type: NodeType): string { switch (type) { - case 'file': - return 'text-muted-foreground' - case 'route': - return 'text-rose-500' case 'component': case 'class': case 'object': diff --git a/src/modules/graph/lib/to-xyflow.test.ts b/src/modules/graph/lib/to-xyflow.test.ts deleted file mode 100644 index e0fb551..0000000 --- a/src/modules/graph/lib/to-xyflow.test.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { describe, expect, it } from 'vitest' - -import type { Graph, GraphNode } from '@/modules/parser' -import { toXYFlow } from '@/modules/graph/lib/to-xyflow' - -describe('toXYFlow', () => { - it('summarizes noisy detail without losing cross-boundary edges', async () => { - const graph = makeGraph() - - const result = await toXYFlow(graph) - - expect(result.nodes.map((node) => node.id).sort()).toEqual([ - 'api/userController.ts::registerUser', - 'db/database.ts::Database.saveUser', - 'index.ts::seedDemo', - 'section:index.ts::seedDemo', - 'services/userService.ts::UserService.create', - 'summary:isolated:utils/format.ts', - 'summary:src/shared/ui', - ]) - expect( - result.edges.map((edge) => `${edge.source}->${edge.target}`), - ).toEqual( - expect.arrayContaining([ - 'api/userController.ts::registerUser->summary:src/shared/ui', - ]), - ) - expect(new Set(result.edges.map((edge) => edge.id)).size).toBe( - result.edges.length, - ) - }) - - it('places connected nodes inside an entry section', async () => { - const result = await toXYFlow(makeGraph()) - const section = result.nodes.find( - (node) => node.id === 'section:index.ts::seedDemo', - ) - const sectionChildren = result.nodes.filter( - (node) => node.parentId === section?.id, - ) - - expect(section?.type).toBe('section') - expect(sectionChildren.length).toBeGreaterThan(0) - expect( - sectionChildren.every( - (node) => node.position.x >= 0 && node.position.y >= 0, - ), - ).toBe(true) - }) - - it('assigns finite numeric positions', async () => { - const result = await toXYFlow(makeGraph()) - - for (const node of result.nodes) { - expect(Number.isFinite(node.position.x)).toBe(true) - expect(Number.isFinite(node.position.y)).toBe(true) - } - }) - - it('expands summarized groups on request', async () => { - const result = await toXYFlow(makeGraph(), { - expandedGroups: ['summary:src/shared/ui'], - }) - - expect(result.nodes.map((node) => node.id)).toContain( - 'src/shared/ui/button.tsx::Button', - ) - expect(result.nodes.map((node) => node.id)).not.toContain( - 'summary:src/shared/ui', - ) - }) - - it('places direct callees to the right of their callers', async () => { - const result = await toXYFlow(makeGraph()) - const byId = new Map(result.nodes.map((node) => [node.id, node])) - const caller = byId.get('api/userController.ts::registerUser') - const callee = byId.get('services/userService.ts::UserService.create') - - expect(caller).toBeDefined() - expect(callee).toBeDefined() - expect(callee?.position.x).toBeGreaterThan(caller?.position.x ?? Infinity) - }) - - it('centers source-only entry nodes against their outgoing flow', async () => { - const result = await toXYFlow(makeGraph()) - const byId = new Map(result.nodes.map((node) => [node.id, node])) - const entry = byId.get('index.ts::seedDemo') - const firstTarget = byId.get('api/userController.ts::registerUser') - const secondTarget = byId.get('db/database.ts::Database.saveUser') - - expect(entry).toBeDefined() - expect(firstTarget).toBeDefined() - expect(secondTarget).toBeDefined() - - const entryCenter = (entry?.position.y ?? 0) + 27 - const targetMedian = - ((firstTarget?.position.y ?? 0) + (secondTarget?.position.y ?? 0)) / 2 + - 27 - - expect(Math.abs(entryCenter - targetMedian)).toBeLessThan(1) - }) - - it('keeps nodes in the same column from overlapping', async () => { - const result = await toXYFlow(makeGraph()) - const columns = new Map() - - for (const node of result.nodes) { - const columnKey = Math.round(node.position.x / 8) * 8 - const columnNodes = columns.get(columnKey) ?? [] - columnNodes.push(node) - columns.set(columnKey, columnNodes) - } - - for (const columnNodes of columns.values()) { - const sortedNodes = [...columnNodes].sort( - (a, b) => a.position.y - b.position.y, - ) - - for (let index = 1; index < sortedNodes.length; index += 1) { - const previous = sortedNodes[index - 1] - const current = sortedNodes[index] - - expect(current.position.y - previous.position.y).toBeGreaterThanOrEqual( - 54, - ) - } - } - }) - - it('keeps disconnected nodes separated from the main flow', async () => { - const result = await toXYFlow(makeGraph()) - const connectedNodes = result.nodes.filter( - (node) => node.id !== 'summary:isolated:utils/format.ts', - ) - const unusedNode = result.nodes.find( - (node) => node.id === 'summary:isolated:utils/format.ts', - ) - const connectedBottom = Math.max( - ...connectedNodes.map((node) => node.position.y), - ) - - expect(unusedNode).toBeDefined() - expect(unusedNode?.position.y).toBeGreaterThan(connectedBottom + 200) - }) - - it('handles empty graphs', async () => { - const result = await toXYFlow({ - version: '1', - language: 'typescript', - root: '/tmp/project', - nodes: [], - edges: [], - }) - - expect(result).toEqual({ nodes: [], edges: [] }) - }) -}) - -function makeGraph(): Graph { - return { - version: '1', - language: 'typescript', - root: '/tmp/project', - nodes: [ - makeNode({ - id: 'index.ts::seedDemo', - name: 'seedDemo', - file: 'index.ts', - line: 4, - outDegree: 2, - }), - makeNode({ - id: 'api/userController.ts::registerUser', - name: 'registerUser', - file: 'api/userController.ts', - line: 4, - inDegree: 1, - outDegree: 1, - }), - makeNode({ - id: 'services/userService.ts::UserService.create', - name: 'UserService.create', - type: 'method', - file: 'services/userService.ts', - line: 7, - inDegree: 1, - outDegree: 1, - }), - makeNode({ - id: 'db/database.ts::Database.saveUser', - name: 'Database.saveUser', - type: 'method', - file: 'db/database.ts', - line: 8, - inDegree: 2, - }), - makeNode({ - id: 'utils/format.ts::slugify', - name: 'slugify', - file: 'utils/format.ts', - line: 1, - }), - makeNode({ - id: 'src/shared/ui/button.tsx::Button', - name: 'Button', - file: 'src/shared/ui/button.tsx', - line: 4, - inDegree: 1, - }), - ], - edges: [ - { - source: 'index.ts::seedDemo', - target: 'api/userController.ts::registerUser', - type: 'calls', - }, - { - source: 'index.ts::seedDemo', - target: 'db/database.ts::Database.saveUser', - type: 'calls', - }, - { - source: 'api/userController.ts::registerUser', - target: 'services/userService.ts::UserService.create', - type: 'calls', - }, - { - source: 'services/userService.ts::UserService.create', - target: 'db/database.ts::Database.saveUser', - type: 'calls', - }, - { - source: 'api/userController.ts::registerUser', - target: 'src/shared/ui/button.tsx::Button', - type: 'calls', - }, - ], - } -} - -function makeNode(node: Partial & Pick) { - return { - type: 'function', - file: 'index.ts', - line: 1, - endLine: 1, - signature: '()', - isAsync: false, - isExported: true, - isStatic: false, - bodyLines: 1, - inDegree: 0, - outDegree: 0, - ...node, - } satisfies GraphNode -} diff --git a/src/modules/graph/lib/to-xyflow.ts b/src/modules/graph/lib/to-xyflow.ts index 4883ab1..cf6af4c 100644 --- a/src/modules/graph/lib/to-xyflow.ts +++ b/src/modules/graph/lib/to-xyflow.ts @@ -605,7 +605,7 @@ function summarizeGraph(graph: Graph, options: XYFlowOptions): XYFlowGraph { const target = visibleIdByOriginalId.get(edge.target) if (!source || !target || source === target) continue - const key = `${source}->${target}:${edge.type}` + const key = `${source}->${target}` if (edgeKeys.has(key)) continue edgeKeys.add(key) diff --git a/src/modules/parser/bindingExtractor.ts b/src/modules/parser/bindingExtractor.ts new file mode 100644 index 0000000..39737cd --- /dev/null +++ b/src/modules/parser/bindingExtractor.ts @@ -0,0 +1,117 @@ +import { Node, SyntaxKind } from 'ts-morph' +import type { + ObjectLiteralExpression, + SourceFile, + VariableDeclaration, +} from 'ts-morph' + +import type { CollectedNode } from './core/models' +import { makeNodeId } from './core/models' + +export function extractBindings( + sourceFile: SourceFile, + relativeFilePath: string, +): CollectedNode[] { + const collected: CollectedNode[] = [] + + for (const variable of sourceFile.getVariableDeclarations()) { + if (!isTopLevel(variable)) continue + + const nameNode = variable.getNameNode() + if (!Node.isIdentifier(nameNode)) continue + + const initializer = variable.getInitializer() + if (!initializer) continue + if (isCoveredByFunctionExtractor(initializer)) continue + if (isCoveredByObjectExtractor(initializer)) continue + if (isPureLiteral(initializer)) continue + + const statement = variable.getVariableStatement() + const startLine = + statement?.getStartLineNumber() ?? variable.getStartLineNumber() + const endLine = + statement?.getEndLineNumber() ?? initializer.getEndLineNumber() + const name = variable.getName() + + collected.push({ + graphNode: { + id: makeNodeId(relativeFilePath, name), + name, + type: 'object', + file: relativeFilePath, + line: startLine, + endLine, + signature: '', + isAsync: false, + isExported: statement?.isExported() ?? false, + isStatic: false, + bodyLines: spanLines( + initializer.getStartLineNumber(), + initializer.getEndLineNumber(), + ), + inDegree: 0, + outDegree: 0, + }, + declaration: variable, + }) + } + + return collected +} + +function isTopLevel(variable: VariableDeclaration): boolean { + const statement = variable.getVariableStatement() + if (!statement) return false + return statement.getParent().getKind() === SyntaxKind.SourceFile +} + +function isCoveredByFunctionExtractor(initializer: Node): boolean { + return ( + Node.isArrowFunction(initializer) || Node.isFunctionExpression(initializer) + ) +} + +function isCoveredByObjectExtractor(initializer: Node): boolean { + if (!Node.isObjectLiteralExpression(initializer)) return false + return hasMethodLikeMember(initializer) +} + +function hasMethodLikeMember(obj: ObjectLiteralExpression): boolean { + for (const prop of obj.getProperties()) { + if ( + Node.isMethodDeclaration(prop) || + Node.isGetAccessorDeclaration(prop) || + Node.isSetAccessorDeclaration(prop) + ) { + return true + } + if (Node.isPropertyAssignment(prop)) { + const init = prop.getInitializer() + if ( + init && + (Node.isArrowFunction(init) || Node.isFunctionExpression(init)) + ) { + return true + } + } + } + return false +} + +function isPureLiteral(node: Node): boolean { + const kind = node.getKind() + return ( + kind === SyntaxKind.StringLiteral || + kind === SyntaxKind.NumericLiteral || + kind === SyntaxKind.BigIntLiteral || + kind === SyntaxKind.NoSubstitutionTemplateLiteral || + kind === SyntaxKind.RegularExpressionLiteral || + kind === SyntaxKind.TrueKeyword || + kind === SyntaxKind.FalseKeyword || + kind === SyntaxKind.NullKeyword + ) +} + +function spanLines(start: number, end: number): number { + return Math.max(1, end - start + 1) +} diff --git a/src/modules/parser/core/models.ts b/src/modules/parser/core/models.ts index 3c56da1..2f63c11 100644 --- a/src/modules/parser/core/models.ts +++ b/src/modules/parser/core/models.ts @@ -6,8 +6,6 @@ import type { Node as TsMorphNode } from 'ts-morph' export type NodeType = - | 'file' - | 'route' | 'component' | 'hook' | 'function' @@ -21,10 +19,10 @@ export type NodeType = export type EdgeType = | 'owns' - | 'imports' + | 'calls' + | 'references' | 'renders' | 'uses-hook' - | 'routes-to' | 'instantiates' | 'extends' | 'implements' diff --git a/src/modules/parser/index.ts b/src/modules/parser/index.ts index 4adf297..dcb15c8 100644 --- a/src/modules/parser/index.ts +++ b/src/modules/parser/index.ts @@ -3,16 +3,15 @@ import path from 'node:path' import { Project, ScriptTarget } from 'ts-morph' import type { Node, SourceFile } from 'ts-morph' +import { extractBindings } from './bindingExtractor' +import { extractCalls } from './callExtractor' import { extractClasses } from './classExtractor' import { extractFunctions } from './functionExtractor' import { extractObjects } from './objectExtractor' +import { extractReferences } from './referenceExtractor' import type { Graph, GraphEdge, GraphNode } from './core/models' import { SCHEMA_VERSION, validateGraph } from './core/schema' -import { - classifyNode, - extractStructuralEdges, - makeFileNode, -} from './structureExtractor' +import { classifyNode, extractStructuralEdges } from './structureExtractor' export type { EdgeType, @@ -61,10 +60,8 @@ export function parseProject(root: string): Graph { (sourceFile) => !sourceFile.isDeclarationFile(), ) - // Pass 1 — collect files, symbols, and the ts-morph-declaration → id map. - const nodes: GraphNode[] = sourceFiles.map((sourceFile) => - makeFileNode(root, sourceFile), - ) + // Pass 1 — collect symbols and the ts-morph-declaration → id map. + const nodes: GraphNode[] = [] const declarationMap = new Map() for (const sourceFile of sourceFiles) { @@ -73,6 +70,7 @@ export function parseProject(root: string): Graph { ...extractFunctions(sourceFile, relativePath), ...extractClasses(sourceFile, relativePath), ...extractObjects(sourceFile, relativePath), + ...extractBindings(sourceFile, relativePath), ] for (const { graphNode, declaration } of collected) { @@ -82,15 +80,19 @@ export function parseProject(root: string): Graph { } } - // Pass 2 — resolve structure-first relationships. We intentionally do not - // emit direct call edges here; the graph is organized by app/module shape. + // Pass 2 — resolve structural relationships (ownership, JSX, hooks, + // instantiation, inheritance) and append plain function-call edges. const edges: GraphEdge[] = extractStructuralEdges( - root, sourceFiles, declarationMap, nodes, ) + for (const sourceFile of sourceFiles) { + edges.push(...extractCalls(sourceFile, declarationMap)) + edges.push(...extractReferences(sourceFile, declarationMap)) + } + // Pass 3 — annotate each node with its in/out degree annotateDegrees(nodes, edges) diff --git a/src/modules/parser/referenceExtractor.ts b/src/modules/parser/referenceExtractor.ts new file mode 100644 index 0000000..c161e0b --- /dev/null +++ b/src/modules/parser/referenceExtractor.ts @@ -0,0 +1,69 @@ +import { SyntaxKind } from 'ts-morph' +import type { SourceFile, Node } from 'ts-morph' + +import type { GraphEdge } from './core/models' + +export function extractReferences( + sourceFile: SourceFile, + declarationMap: Map, +): GraphEdge[] { + const edges: GraphEdge[] = [] + const seen = new Set() + + for (const identifier of sourceFile.getDescendantsOfKind( + SyntaxKind.Identifier, + )) { + let targetId: string | undefined + let sourceId: string | undefined + try { + targetId = resolveTargetId(identifier, declarationMap) + if (!targetId) continue + sourceId = resolveReferenceSourceId(identifier, declarationMap) + } catch { + // ts-morph's checker can throw on partially-resolved symbols. Skip. + continue + } + if (!sourceId || sourceId === targetId) continue + + const key = `${sourceId}->${targetId}` + if (seen.has(key)) continue + seen.add(key) + + edges.push({ source: sourceId, target: targetId, type: 'references' }) + } + + return edges +} + +function resolveTargetId( + identifier: Node, + declarationMap: Map, +): string | undefined { + const symbol = identifier.getSymbol() + if (!symbol) return undefined + + const candidates = [symbol] + const aliased = symbol.getAliasedSymbol() + if (aliased) candidates.push(aliased) + + for (const candidate of candidates) { + for (const declaration of candidate.getDeclarations()) { + const id = declarationMap.get(declaration) + if (id) return id + } + } + return undefined +} + +function resolveReferenceSourceId( + node: Node, + declarationMap: Map, +): string | undefined { + let current = node.getParent() + while (current) { + const id = declarationMap.get(current) + if (id) return id + current = current.getParent() + } + return undefined +} diff --git a/src/modules/parser/structureExtractor.ts b/src/modules/parser/structureExtractor.ts index d6759ec..7ebeba2 100644 --- a/src/modules/parser/structureExtractor.ts +++ b/src/modules/parser/structureExtractor.ts @@ -2,52 +2,21 @@ import { Node } from 'ts-morph' import type { GraphEdge, GraphNode } from './core/models' import { makeNodeId } from './core/models' import type { SourceFile } from 'ts-morph' -import path from 'node:path' - -export function makeFileNode(root: string, sourceFile: SourceFile): GraphNode { - const file = sourceFile.getFilePath().slice(root.length + 1) - const statements = sourceFile.getStatements() - const endLine = - statements.length > 0 - ? (statements[statements.length - 1]?.getEndLineNumber() ?? 1) - : 1 - - return { - id: fileNodeId(file), - name: file.split('/').at(-1) ?? file, - type: file.startsWith('src/routes/') ? 'route' : 'file', - file, - line: 1, - endLine, - signature: '', - isAsync: false, - isExported: false, - isStatic: false, - bodyLines: endLine, - inDegree: 0, - outDegree: 0, - } -} export function extractStructuralEdges( - root: string, sourceFiles: SourceFile[], declarationMap: Map, nodes: GraphNode[], ): GraphEdge[] { - const nodeIds = new Set(nodes.map((node) => node.id)) const edges: GraphEdge[] = [] const seen = new Set() + addOwnershipEdges(edges, seen, nodes) + for (const sourceFile of sourceFiles) { - const file = relativePath(root, sourceFile) - const sourceFileId = fileNodeId(file) - - addOwnershipEdges(edges, seen, sourceFileId, nodes) - addImportEdges(edges, seen, root, sourceFile, sourceFileId, nodeIds) - addJsxEdges(edges, seen, sourceFile, sourceFileId, declarationMap) - addHookEdges(edges, seen, sourceFile, sourceFileId, declarationMap) - addInstantiationEdges(edges, seen, sourceFile, sourceFileId, declarationMap) + addJsxEdges(edges, seen, sourceFile, declarationMap) + addHookEdges(edges, seen, sourceFile, declarationMap) + addInstantiationEdges(edges, seen, sourceFile, declarationMap) addInheritanceEdges(edges, seen, sourceFile, declarationMap) } @@ -71,35 +40,14 @@ export function classifyNode(node: GraphNode): GraphNode { function addOwnershipEdges( edges: GraphEdge[], seen: Set, - fileId: string, nodes: GraphNode[], ): void { - const file = fileId.slice('file:'.length) + const nodeIds = new Set(nodes.map((node) => node.id)) for (const node of nodes) { - if (node.id === fileId || node.file !== file) continue - const ownerId = ownerNodeId(node) - addEdge(edges, seen, ownerId ?? fileId, node.id, 'owns') - } -} - -function addImportEdges( - edges: GraphEdge[], - seen: Set, - root: string, - sourceFile: SourceFile, - sourceFileId: string, - nodeIds: Set, -): void { - for (const importDeclaration of sourceFile.getImportDeclarations()) { - const target = importDeclaration.getModuleSpecifierSourceFile() - if (!target) continue - - const targetId = fileNodeId(relativePath(root, target)) - if (!nodeIds.has(targetId) || targetId === sourceFileId) continue - - addEdge(edges, seen, sourceFileId, targetId, 'imports') + if (!ownerId || !nodeIds.has(ownerId)) continue + addEdge(edges, seen, ownerId, node.id, 'owns') } } @@ -107,7 +55,6 @@ function addJsxEdges( edges: GraphEdge[], seen: Set, sourceFile: SourceFile, - sourceFileId: string, declarationMap: Map, ): void { const jsxNodes = [ @@ -116,15 +63,12 @@ function addJsxEdges( ] for (const jsx of jsxNodes) { + const sourceId = resolveSourceId(jsx, declarationMap) + if (!sourceId) continue + const targetId = resolveSymbolTargetId(jsx.getTagNameNode(), declarationMap) if (targetId) { - addEdge( - edges, - seen, - resolveSourceId(jsx, declarationMap) ?? sourceFileId, - targetId, - 'renders', - ) + addEdge(edges, seen, sourceId, targetId, 'renders') } for (const attribute of jsx.getAttributes()) { @@ -138,13 +82,7 @@ function addJsxEdges( const callbackId = resolveSymbolTargetId(identifier, declarationMap) if (!callbackId) continue - addEdge( - edges, - seen, - resolveSourceId(jsx, declarationMap) ?? sourceFileId, - callbackId, - 'passes-callback', - ) + addEdge(edges, seen, sourceId, callbackId, 'passes-callback') } } } @@ -154,7 +92,6 @@ function addHookEdges( edges: GraphEdge[], seen: Set, sourceFile: SourceFile, - sourceFileId: string, declarationMap: Map, ): void { for (const call of sourceFile @@ -164,16 +101,13 @@ function addHookEdges( const name = expression.getText() if (!isHookName(name.split('.').at(-1) ?? name)) continue + const sourceId = resolveSourceId(call, declarationMap) + if (!sourceId) continue + const targetId = resolveSymbolTargetId(expression, declarationMap) if (!targetId) continue - addEdge( - edges, - seen, - resolveSourceId(call, declarationMap) ?? sourceFileId, - targetId, - 'uses-hook', - ) + addEdge(edges, seen, sourceId, targetId, 'uses-hook') } } @@ -181,25 +115,21 @@ function addInstantiationEdges( edges: GraphEdge[], seen: Set, sourceFile: SourceFile, - sourceFileId: string, declarationMap: Map, ): void { for (const expression of sourceFile .getDescendants() .filter(Node.isNewExpression)) { + const sourceId = resolveSourceId(expression, declarationMap) + if (!sourceId) continue + const targetId = resolveSymbolTargetId( expression.getExpression(), declarationMap, ) if (!targetId) continue - addEdge( - edges, - seen, - resolveSourceId(expression, declarationMap) ?? sourceFileId, - targetId, - 'instantiates', - ) + addEdge(edges, seen, sourceId, targetId, 'instantiates') } } @@ -314,14 +244,6 @@ function addEdge( edges.push({ source, target, type }) } -function fileNodeId(file: string): string { - return `file:${file}` -} - -function relativePath(root: string, sourceFile: SourceFile): string { - return path.relative(root, sourceFile.getFilePath()) -} - function isComponentName(name: string): boolean { return /^[A-Z]/.test(name) } diff --git a/src/shared/lib/desktop.ts b/src/shared/lib/desktop.ts index e1b02ce..0362eed 100644 --- a/src/shared/lib/desktop.ts +++ b/src/shared/lib/desktop.ts @@ -14,27 +14,6 @@ export interface GraphPayload { export interface InitialState extends ProjectPayload, GraphPayload {} -export interface ReadFunctionSourcePayload { - root: string - file: string - startLine: number - endLine: number -} - -export interface ReadFunctionSourceResult { - source: string - startLine: number - endLine: number -} - -export interface WriteFunctionSourcePayload extends ReadFunctionSourcePayload { - source: string -} - -export interface WriteFunctionSourceResult { - endLine: number -} - export interface FileNode { name: string path: string @@ -53,12 +32,6 @@ export interface GraphyDesktop { clearRecents: () => Promise onProject: (handler: (payload: ProjectPayload) => void) => () => void onGraph: (handler: (payload: GraphPayload) => void) => () => void - readFunctionSource: ( - payload: ReadFunctionSourcePayload, - ) => Promise - writeFunctionSource: ( - payload: WriteFunctionSourcePayload, - ) => Promise getFileTree: () => Promise readFile: (filePath: string) => Promise writeFile: (filePath: string, content: string) => Promise From af32b8d77d7e2629f32e1e15ba39405288bd220b Mon Sep 17 00:00:00 2001 From: Maty MILLIEN <183350938+maty-millien@users.noreply.github.com> Date: Tue, 19 May 2026 14:12:53 +0200 Subject: [PATCH 06/12] refactor(ui): remove unused components from shared UI library --- bun.lock | 698 +++++++++--------- package.json | 34 +- src/app/styles.css | 16 - src/modules/graph/components/canvas-edges.tsx | 205 ----- src/modules/graph/components/graph-canvas.tsx | 34 +- src/modules/graph/components/summary-node.tsx | 53 -- src/modules/graph/lib/to-xyflow.ts | 189 +---- src/modules/graph/types.ts | 12 +- src/shared/lib/active-panel.ts | 6 - src/shared/ui/accordion.tsx | 85 --- src/shared/ui/alert-dialog.tsx | 197 ----- src/shared/ui/alert.tsx | 77 -- src/shared/ui/aspect-ratio.tsx | 11 - src/shared/ui/avatar.tsx | 110 --- src/shared/ui/badge.tsx | 50 -- src/shared/ui/button-group.tsx | 84 --- src/shared/ui/calendar.tsx | 225 ------ src/shared/ui/card.tsx | 103 --- src/shared/ui/carousel.tsx | 239 ------ src/shared/ui/chart.tsx | 371 ---------- src/shared/ui/checkbox.tsx | 30 - src/shared/ui/collapsible.tsx | 33 - src/shared/ui/combobox.tsx | 302 -------- src/shared/ui/command.tsx | 190 ----- src/shared/ui/context-menu.tsx | 265 ------- src/shared/ui/direction.tsx | 22 - src/shared/ui/drawer.tsx | 129 ---- src/shared/ui/empty.tsx | 105 --- src/shared/ui/field.tsx | 239 ------ src/shared/ui/hover-card.tsx | 42 -- src/shared/ui/input-otp.tsx | 86 --- src/shared/ui/item.tsx | 197 ----- src/shared/ui/menubar.tsx | 284 ------- src/shared/ui/native-select.tsx | 65 -- src/shared/ui/navigation-menu.tsx | 167 ----- src/shared/ui/pagination.tsx | 132 ---- src/shared/ui/progress.tsx | 31 - src/shared/ui/radio-group.tsx | 42 -- src/shared/ui/resizable.tsx | 50 -- src/shared/ui/scroll-area.tsx | 53 -- src/shared/ui/select.tsx | 195 ----- src/shared/ui/sidebar.tsx | 653 ---------------- src/shared/ui/slider.tsx | 59 -- src/shared/ui/sonner.tsx | 44 -- src/shared/ui/spinner.tsx | 15 - src/shared/ui/switch.tsx | 33 - src/shared/ui/table.tsx | 114 --- src/shared/ui/tabs.tsx | 91 --- src/shared/ui/toggle-group.tsx | 89 --- src/shared/ui/toggle.tsx | 46 -- 50 files changed, 404 insertions(+), 6198 deletions(-) delete mode 100644 src/modules/graph/components/canvas-edges.tsx delete mode 100644 src/modules/graph/components/summary-node.tsx delete mode 100644 src/shared/ui/accordion.tsx delete mode 100644 src/shared/ui/alert-dialog.tsx delete mode 100644 src/shared/ui/alert.tsx delete mode 100644 src/shared/ui/aspect-ratio.tsx delete mode 100644 src/shared/ui/avatar.tsx delete mode 100644 src/shared/ui/badge.tsx delete mode 100644 src/shared/ui/button-group.tsx delete mode 100644 src/shared/ui/calendar.tsx delete mode 100644 src/shared/ui/card.tsx delete mode 100644 src/shared/ui/carousel.tsx delete mode 100644 src/shared/ui/chart.tsx delete mode 100644 src/shared/ui/checkbox.tsx delete mode 100644 src/shared/ui/collapsible.tsx delete mode 100644 src/shared/ui/combobox.tsx delete mode 100644 src/shared/ui/command.tsx delete mode 100644 src/shared/ui/context-menu.tsx delete mode 100644 src/shared/ui/direction.tsx delete mode 100644 src/shared/ui/drawer.tsx delete mode 100644 src/shared/ui/empty.tsx delete mode 100644 src/shared/ui/field.tsx delete mode 100644 src/shared/ui/hover-card.tsx delete mode 100644 src/shared/ui/input-otp.tsx delete mode 100644 src/shared/ui/item.tsx delete mode 100644 src/shared/ui/menubar.tsx delete mode 100644 src/shared/ui/native-select.tsx delete mode 100644 src/shared/ui/navigation-menu.tsx delete mode 100644 src/shared/ui/pagination.tsx delete mode 100644 src/shared/ui/progress.tsx delete mode 100644 src/shared/ui/radio-group.tsx delete mode 100644 src/shared/ui/resizable.tsx delete mode 100644 src/shared/ui/scroll-area.tsx delete mode 100644 src/shared/ui/select.tsx delete mode 100644 src/shared/ui/sidebar.tsx delete mode 100644 src/shared/ui/slider.tsx delete mode 100644 src/shared/ui/sonner.tsx delete mode 100644 src/shared/ui/spinner.tsx delete mode 100644 src/shared/ui/switch.tsx delete mode 100644 src/shared/ui/table.tsx delete mode 100644 src/shared/ui/tabs.tsx delete mode 100644 src/shared/ui/toggle-group.tsx delete mode 100644 src/shared/ui/toggle.tsx diff --git a/bun.lock b/bun.lock index d052703..33bd4d0 100644 --- a/bun.lock +++ b/bun.lock @@ -5,87 +5,75 @@ "": { "name": "graphy", "dependencies": { - "@anthropic-ai/sdk": "^0.96.0", - "@base-ui/react": "^1.4.1", - "@codemirror/autocomplete": "^6.20.2", - "@codemirror/commands": "^6.10.3", - "@codemirror/lang-javascript": "^6.2.5", - "@codemirror/language": "^6.12.3", - "@codemirror/state": "^6.6.0", - "@codemirror/theme-one-dark": "^6.1.3", - "@codemirror/view": "^6.43.0", - "@fontsource-variable/geist": "^5.2.9", - "@openai/codex-sdk": "^0.130.0", - "@tabler/icons-react": "^3.44.0", - "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-devtools": "^0.10.5", - "@tanstack/react-router": "^1.170.4", - "@tanstack/react-router-devtools": "^1.167.0", - "@tanstack/react-router-ssr-query": "^1.167.0", - "@tanstack/react-start": "^1.168.6", - "@tanstack/router-plugin": "^1.168.6", - "@xyflow/react": "^12.10.2", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.1.1", - "codemirror": "^6.0.2", - "date-fns": "^4.2.1", - "elkjs": "^0.11.1", - "embla-carousel-react": "^8.6.0", - "input-otp": "^1.4.2", - "lucide-react": "^1.16.0", - "next-themes": "^0.4.6", - "nitro": "npm:nitro-nightly@^3.0.1-20260512-093145-0498ce70", - "radix-ui": "^1.4.3", - "react": "^19.2.6", - "react-day-picker": "^10.0.1", - "react-dom": "^19.2.6", - "react-markdown": "^10.1.0", - "react-resizable-panels": "^4.11.1", - "recharts": "3.8.0", - "remark-gfm": "^4.0.1", - "shadcn": "^4.7.0", - "simple-git": "^3.36.0", - "sonner": "^2.0.7", - "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.0", - "ts-morph": "^28.0.0", - "tw-animate-css": "^1.4.0", - "vaul": "^1.1.2", + "@anthropic-ai/sdk": "latest", + "@base-ui/react": "latest", + "@codemirror/autocomplete": "latest", + "@codemirror/commands": "latest", + "@codemirror/lang-javascript": "latest", + "@codemirror/language": "latest", + "@codemirror/state": "latest", + "@codemirror/theme-one-dark": "latest", + "@codemirror/view": "latest", + "@fontsource-variable/geist": "latest", + "@openai/codex-sdk": "latest", + "@tailwindcss/vite": "latest", + "@tanstack/react-devtools": "latest", + "@tanstack/react-router": "latest", + "@tanstack/react-router-devtools": "latest", + "@tanstack/react-router-ssr-query": "latest", + "@tanstack/react-start": "latest", + "@tanstack/router-plugin": "latest", + "@xyflow/react": "latest", + "class-variance-authority": "latest", + "clsx": "latest", + "elkjs": "latest", + "lucide-react": "latest", + "next-themes": "latest", + "nitro": "npm:nitro-nightly@latest", + "radix-ui": "latest", + "react": "latest", + "react-dom": "latest", + "react-markdown": "latest", + "react-resizable-panels": "latest", + "remark-gfm": "latest", + "shadcn": "latest", + "simple-git": "latest", + "tailwind-merge": "latest", + "tailwindcss": "latest", + "ts-morph": "latest", + "tw-animate-css": "latest", }, "devDependencies": { - "@tailwindcss/typography": "^0.5.19", - "@tanstack/devtools-vite": "^0.7.0", - "@tanstack/eslint-config": "^0.4.0", - "@types/node": "^25.8.0", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.2", - "chokidar": "^5.0.0", - "concurrently": "^9.2.1", - "cross-env": "^10.1.0", - "electron": "^42.1.0", - "electron-builder": "^25.1.8", - "eslint": "^9.20.0", - "jsdom": "^28.1.0", - "prettier": "^3.8.1", - "typescript": "^6.0.2", - "vite": "^8.0.0", - "vitest": "^4.1.5", - "wait-on": "^9.0.10", + "@tailwindcss/typography": "latest", + "@tanstack/devtools-vite": "latest", + "@tanstack/eslint-config": "latest", + "@types/node": "latest", + "@types/react": "latest", + "@types/react-dom": "latest", + "@vitejs/plugin-react": "latest", + "chokidar": "latest", + "concurrently": "latest", + "cross-env": "latest", + "electron": "latest", + "electron-builder": "latest", + "eslint": "latest", + "jsdom": "latest", + "prettier": "latest", + "typescript": "latest", + "vite": "latest", + "vitest": "latest", + "wait-on": "latest", }, }, }, "packages": { "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], - "@acemir/cssom": ["@acemir/cssom@0.9.31", "", {}, "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA=="], - - "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.96.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-KlCsODtTyb17bLUVCSDC2HtSvAbJf60sEiPEax9dInF+aDF92vS4TZJ5XD7YCQXNb1/5icYaw8Y7wMjPlIV9Zg=="], + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.97.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-124Ebx14aEFlyr2/wRtQjcQ3IRbuON6GgoRKEPGffVV0Nu5DCXs7nlkocVQ4NLI8MxDT+7ezXCwRWXoBpWEuVw=="], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@5.1.11", "", { "dependencies": { "@asamuzakjp/generational-cache": "^1.0.1", "@csstools/css-calc": "^3.2.0", "@csstools/css-color-parser": "^4.1.0", "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg=="], - "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.8.1", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.6" } }, "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ=="], + "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@7.1.1", "", { "dependencies": { "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", "is-potential-custom-element-name": "^1.0.1" } }, "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ=="], "@asamuzakjp/generational-cache": ["@asamuzakjp/generational-cache@1.0.1", "", {}, "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg=="], @@ -165,8 +153,6 @@ "@codemirror/lint": ["@codemirror/lint@6.9.6", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.42.0", "crelt": "^1.0.5" } }, "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A=="], - "@codemirror/search": ["@codemirror/search@6.7.0", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg=="], - "@codemirror/state": ["@codemirror/state@6.6.0", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ=="], "@codemirror/theme-one-dark": ["@codemirror/theme-one-dark@6.1.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/highlight": "^1.0.0" } }, "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA=="], @@ -195,15 +181,17 @@ "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], + "@electron/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", "minimist": "^1.2.5" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], + "@electron/get": ["@electron/get@5.0.0", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^3.0.0", "graceful-fs": "^4.2.11", "progress": "^2.0.3", "semver": "^7.6.3", "sumchecker": "^3.0.1" }, "optionalDependencies": { "undici": "^7.24.4" } }, "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA=="], "@electron/notarize": ["@electron/notarize@2.5.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", "promise-retry": "^2.0.1" } }, "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A=="], - "@electron/osx-sign": ["@electron/osx-sign@1.3.1", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw=="], + "@electron/osx-sign": ["@electron/osx-sign@1.3.3", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg=="], - "@electron/rebuild": ["@electron/rebuild@3.6.1", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", "fs-extra": "^10.0.0", "got": "^11.7.0", "node-abi": "^3.45.0", "node-api-version": "^0.2.0", "node-gyp": "^9.0.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", "tar": "^6.0.5", "yargs": "^17.0.1" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w=="], + "@electron/rebuild": ["@electron/rebuild@4.0.4", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.1.1", "node-abi": "^4.2.0", "node-api-version": "^0.2.1", "node-gyp": "^12.2.0", "read-binary-file-arch": "^1.0.6" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-Rzc39XPdk/+/wBG8MfwAHohXflep0ITUfulb6Rgz3R0NeSB1noE+E9/M/cb8ftCAiyDD9PPhLuuWgE1GaInbKg=="], - "@electron/universal": ["@electron/universal@2.0.1", "", { "dependencies": { "@electron/asar": "^3.2.7", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA=="], + "@electron/universal": ["@electron/universal@2.0.3", "", { "dependencies": { "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g=="], "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], @@ -217,19 +205,17 @@ "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], - "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + "@eslint/config-array": ["@eslint/config-array@0.23.5", "", { "dependencies": { "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", "minimatch": "^10.2.4" } }, "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA=="], - "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + "@eslint/config-helpers": ["@eslint/config-helpers@0.6.0", "", { "dependencies": { "@eslint/core": "^1.2.1" } }, "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA=="], - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], + "@eslint/core": ["@eslint/core@1.2.1", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ=="], "@eslint/js": ["@eslint/js@10.0.1", "", { "peerDependencies": { "eslint": "^10.0.0" }, "optionalPeers": ["eslint"] }, "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA=="], - "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + "@eslint/object-schema": ["@eslint/object-schema@3.0.5", "", {}, "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw=="], - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.7.1", "", { "dependencies": { "@eslint/core": "^1.2.1", "levn": "^0.4.1" } }, "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ=="], "@exodus/bytes": ["@exodus/bytes@1.15.0", "", { "peerDependencies": { "@noble/hashes": "^1.8.0 || ^2.0.0" }, "optionalPeers": ["@noble/hashes"] }, "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ=="], @@ -281,6 +267,8 @@ "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -345,21 +333,21 @@ "@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="], - "@openai/codex": ["@openai/codex@0.130.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.130.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.130.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.130.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.130.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.130.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.130.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-WGDj+RZ3TXWC/7MlwprgLWOqzpwatPIINPhP3IRzHA0ni+o3QZ4i4xrS2uWwGmHUJ395J5JHwoZAAZYyfJyz6w=="], + "@openai/codex": ["@openai/codex@0.131.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.131.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.131.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.131.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.131.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.131.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.131.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-5/fNFAotnPaNSX1jGAAGgWk65HGZupWPnka+DzXdoNzl78RGw0eGpOjpowF+dtPRTEvdwt0U8qoptUjtefitBQ=="], - "@openai/codex-darwin-arm64": ["@openai/codex@0.130.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R9pkGC7kwC8yQ8el5hvBlmugQlcsG/pHMEFgZluu03X9fD2TezGxdq3KqRDRCZuMYl07ILamVEoqknuJ0cq7MA=="], + "@openai/codex-darwin-arm64": ["@openai/codex@0.131.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-e4EZ7XjK1zrkW65nZdhCqQFVKd/zt/of26w4L32wcfibzKE15/Lw2i3FGTD9ufUUqVzF+gowu/lEiBRvDoh21w=="], - "@openai/codex-darwin-x64": ["@openai/codex@0.130.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-gJ+7J8djevgtdra+NgDAiQQPW+O3KTsgGfE3E5dpDfww3zS5OCeV0V2dhxqnJdlOjOSDw99o0P2LqBv19mhpRw=="], + "@openai/codex-darwin-x64": ["@openai/codex@0.131.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-BkFwUVU+yJhw5a85p1oagiSjkRvBs9Xp1b1q1Qbvg4Y9Chtatj4SjI7HRjH5uespNs/Wnh48cMnTsxkAILqlBw=="], - "@openai/codex-linux-arm64": ["@openai/codex@0.130.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-tFtH0V9/hEI3d9y7zP92BXI9FM4Z3+STNQaOR52Czv18TRtCFUp7CbIUYaToopuq6UBfnE1VKr8RLhwT5FcbmA=="], + "@openai/codex-linux-arm64": ["@openai/codex@0.131.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-I12Ou5I5oR/nfUyMJ/D95OMm83HoXMBHdl+4YrPay/XGd9KkyMhvZxp9Es/h9x/xt8yiBIk+k0Ehtr093r8AFw=="], - "@openai/codex-linux-x64": ["@openai/codex@0.130.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-3VcNlez99xdnEf+kB1IOpWv9fICYV9PiGj4sLCO4TCcShLnyxe+YBGa3poknkvXLnMG0qiN9SMnYS2FGrMxQcA=="], + "@openai/codex-linux-x64": ["@openai/codex@0.131.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-Fj9P7h3iBgjAQKzoEyUkb1Q8QMVLqaf62UzlL1jYeDhIzbDMI/gaV0tOackIGXPcfguzzORJC1g5pD9SMWqU5g=="], - "@openai/codex-sdk": ["@openai/codex-sdk@0.130.0", "", { "dependencies": { "@openai/codex": "0.130.0" } }, "sha512-ICKaZ5zrIDg71AiQcsUToVoe5Icmrc3LwSM5+2z7Cf8F1x6nOaY7/ucpFlr4aH8oDe7t3dangc+MsWZTkdvDFw=="], + "@openai/codex-sdk": ["@openai/codex-sdk@0.131.0", "", { "dependencies": { "@openai/codex": "0.131.0" } }, "sha512-fSIJKPGkxVsKu5TsU9pcCvGfYxiPLtfuJOkuk9VIqeZHQwlhVByZ8MVTiBhsd4mr5hxgyeyPSiofUONULdaPWQ=="], - "@openai/codex-win32-arm64": ["@openai/codex@0.130.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-vdpmiNp57L/arZabltLXn8TyEtNa7W1meOEkr+3R6W/8ZyBt++wuqz1Orv134OT2grrcFJsIVCAIPiqUxCvBkA=="], + "@openai/codex-win32-arm64": ["@openai/codex@0.131.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-aGXsk8GYNFCjHYH61mVG0PulheBq6ZxZWM2BLYAJabzGarzRQpPknc60mx8mSm93BebjPkX0Wpf+0qInBPbF0w=="], - "@openai/codex-win32-x64": ["@openai/codex@0.130.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-FzMznm7fr5/nbjZgOujZ9Y9AbdGm7ji1FOoWiY3U+srqauvZaTgn6o6aCheSL7kuymu7nTLOO/cAyWV6NuesqQ=="], + "@openai/codex-win32-x64": ["@openai/codex@0.131.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-RlIRs0hi6xIaBXWFhiPTPlz+Dfibc3pXrnVXjJtpbeYcNyBOO+SIMMVuQUswpz3RnJpsxA70dQA+05hKYraKhA=="], "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.120.0", "", { "os": "android", "cpu": "arm" }, "sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg=="], @@ -473,7 +461,7 @@ "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], @@ -527,8 +515,6 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], - "@reduxjs/toolkit": ["@reduxjs/toolkit@2.12.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw=="], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.1", "", { "os": "android", "cpu": "arm64" }, "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg=="], "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg=="], @@ -587,16 +573,10 @@ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], - "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], - "@stylistic/eslint-plugin": ["@stylistic/eslint-plugin@5.10.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/types": "^8.56.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "estraverse": "^5.3.0", "picomatch": "^4.0.3" }, "peerDependencies": { "eslint": "^9.0.0 || ^10.0.0" } }, "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ=="], "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], - "@tabler/icons": ["@tabler/icons@3.44.0", "", {}, "sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA=="], - - "@tabler/icons-react": ["@tabler/icons-react@3.44.0", "", { "dependencies": { "@tabler/icons": "3.44.0" }, "peerDependencies": { "react": ">= 16" } }, "sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg=="], - "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="], "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="], @@ -703,28 +683,14 @@ "@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="], - "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], - "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], - "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], - "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], - "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], - - "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "*" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], - "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], - "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "*" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], - - "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], - - "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], - "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], @@ -733,6 +699,8 @@ "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="], + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], @@ -751,7 +719,7 @@ "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + "@types/node": ["@types/node@25.9.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ=="], "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], @@ -767,8 +735,6 @@ "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], - "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], - "@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="], "@types/verror": ["@types/verror@1.10.11", "", {}, "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg=="], @@ -851,13 +817,13 @@ "@vitest/utils": ["@vitest/utils@4.1.6", "", { "dependencies": { "@vitest/pretty-format": "4.1.6", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ=="], - "@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.13", "", {}, "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw=="], "@xyflow/react": ["@xyflow/react@12.10.2", "", { "dependencies": { "@xyflow/system": "0.0.76", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ=="], "@xyflow/system": ["@xyflow/system@0.0.76", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-interpolate": "^3.0.4", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-interpolate": "^3.0.1", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-hvwvnRS1B3REwVDlWexsq7YQaPZeG3/mKo1jv38UmnpWmxihp14bW6VtEOuHEwJX2FvzFw8k77LyKSk/wiZVNA=="], - "abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="], + "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], @@ -885,9 +851,9 @@ "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "app-builder-bin": ["app-builder-bin@5.0.0-alpha.10", "", {}, "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw=="], + "app-builder-bin": ["app-builder-bin@5.0.0-alpha.12", "", {}, "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w=="], - "app-builder-lib": ["app-builder-lib@25.1.8", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.1", "@electron/rebuild": "3.6.1", "@electron/universal": "2.0.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chromium-pickle-js": "^0.2.0", "config-file-ts": "0.2.8-rc1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "25.1.7", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.0", "resedit": "^1.7.0", "sanitize-filename": "^1.6.3", "semver": "^7.3.8", "tar": "^6.1.12", "temp-file": "^3.4.0" }, "peerDependencies": { "dmg-builder": "25.1.8", "electron-builder-squirrel-windows": "25.1.8" } }, "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg=="], + "app-builder-lib": ["app-builder-lib@26.8.1", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "^4.0.3", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "26.8.1", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.3", "plist": "3.1.0", "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "which": "^5.0.0" }, "peerDependencies": { "dmg-builder": "26.8.1", "electron-builder-squirrel-windows": "26.8.1" } }, "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw=="], "aproba": ["aproba@2.1.0", "", {}, "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="], @@ -923,7 +889,7 @@ "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], @@ -943,7 +909,9 @@ "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], - "brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], + "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], + + "brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -955,9 +923,9 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "builder-util": ["builder-util@25.1.7", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "5.0.0-alpha.10", "bluebird-lst": "^1.0.9", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0" } }, "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww=="], + "builder-util": ["builder-util@26.8.1", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "5.0.0-alpha.12", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.1.0", "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0" } }, "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw=="], - "builder-util-runtime": ["builder-util-runtime@9.2.10", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw=="], + "builder-util-runtime": ["builder-util-runtime@9.5.1", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], @@ -997,11 +965,11 @@ "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], - "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="], - "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], @@ -1025,12 +993,8 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], - "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], - "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], - "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], - "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -1099,12 +1063,8 @@ "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], - "cssstyle": ["cssstyle@6.2.0", "", { "dependencies": { "@asamuzakjp/css-color": "^5.0.1", "@csstools/css-syntax-patches-for-csstree": "^1.0.28", "css-tree": "^3.1.0", "lru-cache": "^11.2.6" } }, "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig=="], - "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], - "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], @@ -1113,22 +1073,10 @@ "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], - "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], - "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], - "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], - - "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", "d3-interpolate": "1.2.0 - 3", "d3-time": "2.1.1 - 3", "d3-time-format": "2 - 4" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], - "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], - "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "^3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], - - "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "2 - 3" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], - - "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "1 - 3" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], - "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], @@ -1149,8 +1097,6 @@ "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], - "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], - "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], @@ -1169,8 +1115,12 @@ "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], @@ -1181,6 +1131,8 @@ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -1189,7 +1141,7 @@ "dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "^3.0.5", "p-limit": "^3.1.0 " } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], - "dmg-builder": ["dmg-builder@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ=="], + "dmg-builder": ["dmg-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg=="], "dmg-license": ["dmg-license@1.0.11", "", { "dependencies": { "@types/plist": "^3.0.1", "@types/verror": "^1.10.3", "ajv": "^6.10.0", "crc": "^3.8.0", "iconv-corefoundation": "^1.1.7", "plist": "^3.0.4", "smart-buffer": "^4.0.2", "verror": "^1.10.0" }, "os": "darwin", "bin": { "dmg-license": "bin/dmg-license.js" } }, "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q=="], @@ -1217,22 +1169,16 @@ "electron": ["electron@42.1.0", "", { "dependencies": { "@electron/get": "^5.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js", "install-electron": "install.js" } }, "sha512-0szNwC/0dWtkvNce5j3ThiuL0TxBNrZN/BZhdOiGwbLreiD/+u3MGpkct4hA5Ycagb8MXjpEr5/oosi+FwuKRQ=="], - "electron-builder": ["electron-builder@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "dmg-builder": "25.1.8", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig=="], + "electron-builder": ["electron-builder@26.8.1", "", { "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.8.1", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw=="], "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "archiver": "^5.3.1", "builder-util": "25.1.7", "fs-extra": "^10.1.0" } }, "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg=="], - "electron-publish": ["electron-publish@25.1.7", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg=="], + "electron-publish": ["electron-publish@26.8.1", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w=="], "electron-to-chromium": ["electron-to-chromium@1.5.357", "", {}, "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g=="], "elkjs": ["elkjs@0.11.1", "", {}, "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg=="], - "embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="], - - "embla-carousel-react": ["embla-carousel-react@8.6.0", "", { "dependencies": { "embla-carousel": "8.6.0", "embla-carousel-reactive-utils": "8.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.1 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA=="], - - "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], - "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], @@ -1265,7 +1211,7 @@ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - "es-toolkit": ["es-toolkit@1.46.1", "", {}, "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ=="], + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -1273,7 +1219,7 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], + "eslint": ["eslint@10.4.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.6.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^9.1.2", "eslint-visitor-keys": "^5.0.1", "espree": "^11.2.0", "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "minimatch": "^10.2.4", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ=="], "eslint-compat-utils": ["eslint-compat-utils@0.5.1", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q=="], @@ -1285,11 +1231,11 @@ "eslint-plugin-n": ["eslint-plugin-n@17.24.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.5.0", "enhanced-resolve": "^5.17.1", "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", "globals": "^15.11.0", "globrex": "^0.1.2", "ignore": "^5.3.2", "semver": "^7.6.3", "ts-declaration-location": "^1.0.6" }, "peerDependencies": { "eslint": ">=8.23.0" } }, "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw=="], - "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + "eslint-scope": ["eslint-scope@9.1.2", "", { "dependencies": { "@types/esrecurse": "^4.3.1", "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ=="], - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + "eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], - "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + "espree": ["espree@11.2.0", "", { "dependencies": { "acorn": "^8.16.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^5.0.1" } }, "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], @@ -1307,8 +1253,6 @@ "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], - "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], - "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], "eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], @@ -1421,12 +1365,16 @@ "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], - "glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + "globals": ["globals@17.6.0", "", {}, "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA=="], + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + "globrex": ["globrex@0.1.2", "", {}, "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg=="], "goober": ["goober@2.1.19", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg=="], @@ -1445,6 +1393,8 @@ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], @@ -1511,10 +1461,6 @@ "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], - "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], - - "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], - "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -1591,7 +1537,7 @@ "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], - "jsdom": ["jsdom@28.1.0", "", { "dependencies": { "@acemir/cssom": "^0.9.31", "@asamuzakjp/dom-selector": "^6.8.1", "@bramus/specificity": "^2.4.2", "@exodus/bytes": "^1.11.0", "cssstyle": "^6.0.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug=="], + "jsdom": ["jsdom@29.1.1", "", { "dependencies": { "@asamuzakjp/css-color": "^5.1.11", "@asamuzakjp/dom-selector": "^7.1.1", "@bramus/specificity": "^2.4.2", "@csstools/css-syntax-patches-for-csstree": "^1.1.3", "@exodus/bytes": "^1.15.0", "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.3.5", "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.1", "undici": "^7.25.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.1", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -1607,6 +1553,8 @@ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], @@ -1661,8 +1609,6 @@ "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - "lodash.union": ["lodash.union@4.6.0", "", {}, "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="], "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], @@ -1681,6 +1627,8 @@ "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], @@ -1793,11 +1741,11 @@ "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], "minipass-collect": ["minipass-collect@1.0.2", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA=="], @@ -1809,7 +1757,7 @@ "minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="], - "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], @@ -1831,9 +1779,9 @@ "nf3": ["nf3@0.3.17", "", {}, "sha512-N9zEWySuJFw+gR0lhS5863YsvNeudOdqRyFvNb+jMXbeTJOdrjDqkCpDginIZfUm0LzT1t1nCRiDeqQm/8kirQ=="], - "nitro": ["nitro-nightly@3.0.1-20260512-093145-0498ce70", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.5", "db0": "^0.3.4", "env-runner": "^0.1.7", "h3": "^2.0.1-rc.22", "hookable": "^6.1.1", "nf3": "^0.3.17", "ocache": "^0.1.4", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "rolldown": "^1.0.0", "srvx": "^0.11.15", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.7" }, "peerDependencies": { "@vercel/queue": "^0.1.6", "dotenv": "*", "giget": "*", "jiti": "^2.6.1", "rollup": "^4.60.3", "vite": "^7 || ^8", "xml2js": "^0.6.2", "zephyr-agent": "^0.2.0" }, "optionalPeers": ["@vercel/queue", "dotenv", "giget", "jiti", "rollup", "vite", "xml2js", "zephyr-agent"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-5vIbEn1ORiNIymy9RtRx3AavX4CAQqWNnsh1vOLag/fzsEQRD2wLBhR+ZcMeVTUbQb0mo8fIbMH2NkSeiGu6fw=="], + "nitro": ["nitro-nightly@3.0.1-20260518-130639-31265391", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.5", "db0": "^0.3.4", "env-runner": "^0.1.7", "h3": "^2.0.1-rc.22", "hookable": "^6.1.1", "nf3": "^0.3.17", "ocache": "^0.1.4", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "rolldown": "^1.0.0", "srvx": "^0.11.15", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.7" }, "peerDependencies": { "@vercel/queue": "^0.1.6", "dotenv": "*", "giget": "*", "jiti": "^2.6.1", "rollup": "^4.60.3", "vite": "^7 || ^8", "xml2js": "^0.6.2", "zephyr-agent": "^0.2.0" }, "optionalPeers": ["@vercel/queue", "dotenv", "giget", "jiti", "rollup", "vite", "xml2js", "zephyr-agent"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-JhmqcyNdah1zLNeHzAIeNcTqNT1GW5UveEdK39hGB776K4ydPlijTsm821MTDNZjdEmSTs8Pzxzr+xmi7lBgdw=="], - "node-abi": ["node-abi@3.92.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ=="], + "node-abi": ["node-abi@4.31.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-Erq5w/t3syw3s4sDsUaX4QttIdBPsGKTT1DTRsCkTonGggczhlDKm/wDX3o+HPJpQ41EjXCbcmXf0tgr5YZJXw=="], "node-addon-api": ["node-addon-api@1.7.2", "", {}, "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="], @@ -1843,11 +1791,11 @@ "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], - "node-gyp": ["node-gyp@9.4.1", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^10.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.2", "which": "^2.0.2" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ=="], + "node-gyp": ["node-gyp@12.3.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "undici": "^6.25.0", "which": "^6.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg=="], "node-releases": ["node-releases@2.0.44", "", {}, "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ=="], - "nopt": ["nopt@6.0.0", "", { "dependencies": { "abbrev": "^1.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g=="], + "nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -1863,6 +1811,8 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + "object-treeify": ["object-treeify@1.1.33", "", {}, "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A=="], "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], @@ -1939,7 +1889,7 @@ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], - "plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], + "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], "postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="], @@ -1953,6 +1903,8 @@ "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], + "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], @@ -1963,6 +1915,8 @@ "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], @@ -1987,16 +1941,10 @@ "react": ["react@19.2.6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="], - "react-day-picker": ["react-day-picker@10.0.1", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "date-fns": "^4.1.0" }, "peerDependencies": { "@types/react": ">=16.8.0", "react": ">=16.8.0" }, "optionalPeers": ["@types/react"] }, "sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w=="], - "react-dom": ["react-dom@19.2.6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="], - "react-is": ["react-is@19.2.6", "", {}, "sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw=="], - "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="], - "react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="], - "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], @@ -2015,12 +1963,6 @@ "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], - "recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="], - - "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], - - "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], - "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], @@ -2055,6 +1997,8 @@ "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], + "rolldown": ["rolldown@1.0.1", "", { "dependencies": { "@oxc-project/types": "=0.130.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.1", "@rolldown/binding-darwin-arm64": "1.0.1", "@rolldown/binding-darwin-x64": "1.0.1", "@rolldown/binding-freebsd-x64": "1.0.1", "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", "@rolldown/binding-linux-arm64-gnu": "1.0.1", "@rolldown/binding-linux-arm64-musl": "1.0.1", "@rolldown/binding-linux-ppc64-gnu": "1.0.1", "@rolldown/binding-linux-s390x-gnu": "1.0.1", "@rolldown/binding-linux-x64-gnu": "1.0.1", "@rolldown/binding-linux-x64-musl": "1.0.1", "@rolldown/binding-openharmony-arm64": "1.0.1", "@rolldown/binding-wasm32-wasi": "1.0.1", "@rolldown/binding-win32-arm64-msvc": "1.0.1", "@rolldown/binding-win32-x64-msvc": "1.0.1" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ=="], "rou3": ["rou3@0.8.1", "", {}, "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA=="], @@ -2081,8 +2025,12 @@ "semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="], + "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], + "seroval": ["seroval@1.5.4", "", {}, "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw=="], "seroval-plugins": ["seroval-plugins@1.5.4", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw=="], @@ -2131,8 +2079,6 @@ "solid-js": ["solid-js@1.9.13", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-6hJeJMOcEX8ktqjpDoJZEmld3ijvcvWBDtiXBm7f4332SiFN66QeAQI1REQshvyUoISsSeJ4PHDauKYbwao9JQ=="], - "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], - "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -2141,6 +2087,8 @@ "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + "srvx": ["srvx@0.11.15", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg=="], "ssri": ["ssri@9.0.1", "", { "dependencies": { "minipass": "^3.1.1" } }, "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q=="], @@ -2179,8 +2127,6 @@ "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], @@ -2201,12 +2147,14 @@ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], - "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + "tar": ["tar@7.5.15", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ=="], "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], + "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], @@ -2321,16 +2269,12 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], - "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], - "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], - "vite": ["vite@8.0.13", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.14", "rolldown": "1.0.1", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw=="], "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], @@ -2387,7 +2331,7 @@ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -2435,23 +2379,25 @@ "@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], - "@electron/asar/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "@electron/asar/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "@electron/fuses/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@electron/fuses/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], - "@electron/rebuild/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "@electron/rebuild/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + "@electron/osx-sign/plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], "@electron/universal/fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], "@electron/universal/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + "@electron/universal/plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], - "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -2463,87 +2409,9 @@ "@mswjs/interceptors/@open-draft/deferred-promise": ["@open-draft/deferred-promise@2.2.0", "", {}, "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA=="], - "@radix-ui/react-accordion/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-alert-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-aspect-ratio/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-avatar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-checkbox/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-collapsible/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-context-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-dropdown-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-form/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-hover-card/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-menubar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-navigation-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-one-time-password-field/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-password-toggle-field/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-popover/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-popper/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], - - "@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-radio-group/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-roving-focus/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-scroll-area/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-select/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-slider/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-switch/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-tabs/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-toast/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-toggle/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-toggle-group/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-toolbar/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-tooltip/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], - - "@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + "@stylistic/eslint-plugin/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], - "@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="], + "@stylistic/eslint-plugin/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], @@ -2561,15 +2429,21 @@ "@tanstack/start-plugin-core/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.40", "", {}, "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w=="], - "@ts-morph/common/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "@types/cacheable-request/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], - "@types/yauzl/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + "@types/fs-extra/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "@types/keyv/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + + "@types/plist/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], + + "@types/responselike/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "@types/set-cookie-parser/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="], - "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + "@types/yauzl/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], @@ -2579,9 +2453,13 @@ "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "app-builder-lib/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "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-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], - "archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "app-builder-lib/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + + "app-builder-lib/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], "archiver-utils/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], @@ -2591,12 +2469,16 @@ "builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + "cacache/glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="], "cacache/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], "cacache/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "cacache/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + "cheerio/parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], @@ -2607,23 +2489,27 @@ "concurrently/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "config-file-ts/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "config-file-ts/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "cosmiconfig/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "dir-compare/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "dmg-license/plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "electron/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], "electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "electron-publish/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - - "eslint/@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], + "electron-builder-squirrel-windows/app-builder-lib": ["app-builder-lib@25.1.8", "", { "dependencies": { "@develar/schema-utils": "~2.6.5", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.1", "@electron/rebuild": "3.6.1", "@electron/universal": "2.0.1", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chromium-pickle-js": "^0.2.0", "config-file-ts": "0.2.8-rc1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "25.1.7", "form-data": "^4.0.0", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.0.0", "resedit": "^1.7.0", "sanitize-filename": "^1.6.3", "semver": "^7.3.8", "tar": "^6.1.12", "temp-file": "^3.4.0" }, "peerDependencies": { "dmg-builder": "25.1.8", "electron-builder-squirrel-windows": "25.1.8" } }, "sha512-pCqe7dfsQFBABC1jeKZXQWhGcCPF3rPCXDdfqVKjIeWBcXzyC1iOWZdfFhGl+S9MyE/k//DFmC6FzuGAUudNDg=="], - "eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "electron-builder-squirrel-windows/builder-util": ["builder-util@25.1.7", "", { "dependencies": { "7zip-bin": "~5.2.0", "@types/debug": "^4.1.6", "app-builder-bin": "5.0.0-alpha.10", "bluebird-lst": "^1.0.9", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0" } }, "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww=="], - "eslint-plugin-import-x/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "electron-publish/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "eslint-plugin-n/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], @@ -2643,14 +2529,14 @@ "gauge/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - - "glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + "is-ci/ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], @@ -2673,17 +2559,19 @@ "minipass-fetch/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "minipass-fetch/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "node-gyp/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], - "node-gyp/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "node-gyp/undici": ["undici@6.25.0", "", {}, "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg=="], + + "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], @@ -2699,11 +2587,9 @@ "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], - "radix-ui/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "raw-body/iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], @@ -2713,14 +2599,14 @@ "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], - "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "rolldown/@oxc-project/types": ["@oxc-project/types@0.130.0", "", {}, "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q=="], "router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], "send/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], + "shadcn/fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], "shadcn/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="], @@ -2741,10 +2627,18 @@ "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], "type-is/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + "vue-eslint-parser/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "vue-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "vue-eslint-parser/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -2767,20 +2661,16 @@ "@dotenvx/dotenvx/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "@electron/rebuild/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - - "@electron/rebuild/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], - - "@electron/rebuild/ora/is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + "@electron/asar/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], - "@electron/rebuild/ora/is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + "@electron/fuses/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "@electron/rebuild/ora/log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], - - "@electron/rebuild/ora/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@electron/osx-sign/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], "@electron/universal/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + "@electron/universal/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], @@ -2791,17 +2681,19 @@ "@tanstack/router-plugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], - "@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], - "@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], - "accepts/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "app-builder-lib/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + "app-builder-lib/@electron/get/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "app-builder-lib/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], "archiver-utils/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -2811,29 +2703,63 @@ "cacache/glob/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], + "cacache/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "cacache/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "cacache/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "cacache/tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "cheerio/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "concurrently/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "config-file-ts/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "dir-compare/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], + + "dmg-license/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/osx-sign": ["@electron/osx-sign@1.3.1", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild": ["@electron/rebuild@3.6.1", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", "fs-extra": "^10.0.0", "got": "^11.7.0", "node-abi": "^3.45.0", "node-api-version": "^0.2.0", "node-gyp": "^9.0.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", "tar": "^6.0.5", "yargs": "^17.0.1" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal": ["@electron/universal@2.0.1", "", { "dependencies": { "@electron/asar": "^3.2.7", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA=="], + + "electron-builder-squirrel-windows/app-builder-lib/builder-util-runtime": ["builder-util-runtime@9.2.10", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw=="], + + "electron-builder-squirrel-windows/app-builder-lib/dmg-builder": ["dmg-builder@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" } }, "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/electron-publish": ["electron-publish@25.1.7", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "electron-builder-squirrel-windows/builder-util/app-builder-bin": ["app-builder-bin@5.0.0-alpha.10", "", {}, "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw=="], + + "electron-builder-squirrel-windows/builder-util/builder-util-runtime": ["builder-util-runtime@9.2.10", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw=="], + + "electron-builder-squirrel-windows/builder-util/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "electron-builder/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "electron-publish/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "electron/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - "eslint-plugin-import-x/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], - - "eslint/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "express/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "filelist/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + "fs-minipass/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "gauge/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + "glob/minimatch/brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], + + "hosted-git-info/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -2841,6 +2767,22 @@ "make-fetch-happen/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + "make-fetch-happen/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-collect/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-fetch/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-fetch/minizlib/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "node-gyp/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + "ora/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "parse5-htmlparser2-tree-adapter/parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], @@ -2853,6 +2795,8 @@ "shadcn/ts-morph/@ts-morph/common": ["@ts-morph/common@0.27.0", "", { "dependencies": { "fast-glob": "^3.3.3", "minimatch": "^10.0.1", "path-browserify": "^1.0.1" } }, "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ=="], + "ssri/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], @@ -2863,30 +2807,98 @@ "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "zip-stream/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - - "@electron/rebuild/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "@electron/rebuild/ora/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@electron/universal/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "@tanstack/router-plugin/chokidar/readdirp/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "app-builder-lib/@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "app-builder-lib/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], - "eslint-plugin-import-x/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "cacache/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "config-file-ts/glob/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + + "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/osx-sign/plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/node-abi": ["node-abi@3.92.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/node-gyp": ["node-gyp@9.4.1", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^10.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.2", "which": "^2.0.2" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], + + "electron-builder-squirrel-windows/app-builder-lib/electron-publish/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "electron-builder-squirrel-windows/builder-util/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "readdir-glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "config-file-ts/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/osx-sign/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/node-gyp/env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/node-gyp/nopt": ["nopt@6.0.0", "", { "dependencies": { "abbrev": "^1.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/minimatch/brace-expansion": ["brace-expansion@2.1.0", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + + "electron-builder-squirrel-windows/app-builder-lib/electron-publish/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "electron-builder-squirrel-windows/app-builder-lib/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/node-gyp/nopt/abbrev": ["abbrev@1.1.1", "", {}, "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="], - "shadcn/ts-morph/@ts-morph/common/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], - "@electron/rebuild/ora/cli-cursor/restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "shadcn/ts-morph/@ts-morph/common/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + "electron-builder-squirrel-windows/app-builder-lib/@electron/universal/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "shadcn/ts-morph/@ts-morph/common/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "electron-builder-squirrel-windows/app-builder-lib/@electron/rebuild/ora/cli-cursor/restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], } } diff --git a/package.json b/package.json index 51b40bd..d1cdc8e 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ } }, "dependencies": { - "@anthropic-ai/sdk": "^0.96.0", + "@anthropic-ai/sdk": "^0.97.0", "@base-ui/react": "^1.4.1", "@codemirror/autocomplete": "^6.20.2", "@codemirror/commands": "^6.10.3", @@ -86,8 +86,7 @@ "@codemirror/theme-one-dark": "^6.1.3", "@codemirror/view": "^6.43.0", "@fontsource-variable/geist": "^5.2.9", - "@openai/codex-sdk": "^0.130.0", - "@tabler/icons-react": "^3.44.0", + "@openai/codex-sdk": "^0.131.0", "@tailwindcss/vite": "^4.3.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-router": "^1.170.4", @@ -98,37 +97,28 @@ "@xyflow/react": "^12.10.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "cmdk": "^1.1.1", - "codemirror": "^6.0.2", - "date-fns": "^4.2.1", "elkjs": "^0.11.1", - "embla-carousel-react": "^8.6.0", - "input-otp": "^1.4.2", "lucide-react": "^1.16.0", "next-themes": "^0.4.6", - "nitro": "npm:nitro-nightly@^3.0.1-20260512-093145-0498ce70", + "nitro": "npm:nitro-nightly@^3.0.1-20260518-130639-31265391", "radix-ui": "^1.4.3", "react": "^19.2.6", - "react-day-picker": "^10.0.1", "react-dom": "^19.2.6", "react-markdown": "^10.1.0", "react-resizable-panels": "^4.11.1", - "recharts": "3.8.0", "remark-gfm": "^4.0.1", "shadcn": "^4.7.0", "simple-git": "^3.36.0", - "sonner": "^2.0.7", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.0", "ts-morph": "^28.0.0", - "tw-animate-css": "^1.4.0", - "vaul": "^1.1.2" + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@tailwindcss/typography": "^0.5.19", "@tanstack/devtools-vite": "^0.7.0", "@tanstack/eslint-config": "^0.4.0", - "@types/node": "^25.8.0", + "@types/node": "^25.9.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.2", @@ -136,13 +126,13 @@ "concurrently": "^9.2.1", "cross-env": "^10.1.0", "electron": "^42.1.0", - "electron-builder": "^25.1.8", - "eslint": "^9.20.0", - "jsdom": "^28.1.0", - "prettier": "^3.8.1", - "typescript": "^6.0.2", - "vite": "^8.0.0", - "vitest": "^4.1.5", + "electron-builder": "^26.8.1", + "eslint": "^10.4.0", + "jsdom": "^29.1.1", + "prettier": "^3.8.3", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vitest": "^4.1.6", "wait-on": "^9.0.10" }, "pnpm": { diff --git a/src/app/styles.css b/src/app/styles.css index 8c657c6..a42e484 100644 --- a/src/app/styles.css +++ b/src/app/styles.css @@ -263,22 +263,6 @@ body { --xy-selection-border-default: 1px dashed var(--primary); } -.react-flow__edge.graph-edge .react-flow__edge-path { - stroke: color-mix(in oklab, var(--muted-foreground) 46%, transparent); - stroke-width: 1; - stroke-linecap: square; - shape-rendering: optimizeSpeed; -} - -.react-flow__edge.graph-edge:hover .react-flow__edge-path, -.react-flow__edge.graph-edge.selected .react-flow__edge-path { - stroke: color-mix(in oklab, var(--muted-foreground) 60%, transparent); -} - -.graph-canvas-edges { - color: color-mix(in oklab, var(--muted-foreground) 62%, transparent); -} - .react-flow__node-code, .react-flow__node-section, .react-flow__node-summary { diff --git a/src/modules/graph/components/canvas-edges.tsx b/src/modules/graph/components/canvas-edges.tsx deleted file mode 100644 index 3395125..0000000 --- a/src/modules/graph/components/canvas-edges.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { useStore } from '@xyflow/react' -import type { Edge, Node } from '@xyflow/react' -import { useEffect, useMemo, useRef } from 'react' - -import type { GraphNodeData } from '@/modules/graph/types' - -const CODE_NODE_WIDTH = 240 -const CODE_NODE_HEIGHT = 54 - -type CanvasEdgesProps = { - edges: Edge[] - nodes: Array> -} - -type EdgeEndpoint = { - sourceX: number - sourceY: number - targetX: number - targetY: number -} - -type AbsoluteNode = { - x: number - y: number - width: number - height: number -} - -export function CanvasEdges({ edges, nodes }: CanvasEdgesProps) { - const canvasRef = useRef(null) - const transform = useStore((state) => state.transform) - const width = useStore((state) => state.width) - const height = useStore((state) => state.height) - const edgeEndpoints = useMemo( - () => buildEdgeEndpoints(nodes, edges), - [edges, nodes], - ) - - useEffect(() => { - const canvas = canvasRef.current - if (!canvas) return - - const context = canvas.getContext('2d') - if (!context) return - - const frame = window.requestAnimationFrame(() => { - const ratio = window.devicePixelRatio || 1 - const pixelWidth = Math.max(1, Math.floor(width * ratio)) - const pixelHeight = Math.max(1, Math.floor(height * ratio)) - - if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) { - canvas.width = pixelWidth - canvas.height = pixelHeight - } - - canvas.style.width = `${width}px` - canvas.style.height = `${height}px` - - context.setTransform(ratio, 0, 0, ratio, 0, 0) - context.clearRect(0, 0, width, height) - - if (edgeEndpoints.length === 0) return - - const edgeColor = getComputedStyle(canvas).color - - context.save() - context.translate(transform[0], transform[1]) - context.scale(transform[2], transform[2]) - context.strokeStyle = edgeColor || 'rgba(148, 163, 184, 0.46)' - context.globalAlpha = 0.58 - context.lineWidth = Math.max(1 / transform[2], 0.7) - context.lineCap = 'square' - - const viewLeft = -transform[0] / transform[2] - const viewTop = -transform[1] / transform[2] - const viewRight = viewLeft + width / transform[2] - const viewBottom = viewTop + height / transform[2] - - const arrowLength = 14 - const arrowAngle = Math.PI / 7 - - context.beginPath() - for (const endpoint of edgeEndpoints) { - if ( - !isEdgeVisible(endpoint, viewLeft, viewTop, viewRight, viewBottom) - ) { - continue - } - - context.moveTo(endpoint.sourceX, endpoint.sourceY) - context.lineTo(endpoint.targetX, endpoint.targetY) - - const angle = Math.atan2( - endpoint.targetY - endpoint.sourceY, - endpoint.targetX - endpoint.sourceX, - ) - const wing1X = - endpoint.targetX - arrowLength * Math.cos(angle - arrowAngle) - const wing1Y = - endpoint.targetY - arrowLength * Math.sin(angle - arrowAngle) - const wing2X = - endpoint.targetX - arrowLength * Math.cos(angle + arrowAngle) - const wing2Y = - endpoint.targetY - arrowLength * Math.sin(angle + arrowAngle) - - context.moveTo(wing1X, wing1Y) - context.lineTo(endpoint.targetX, endpoint.targetY) - context.moveTo(wing2X, wing2Y) - context.lineTo(endpoint.targetX, endpoint.targetY) - } - context.stroke() - context.restore() - }) - - return () => window.cancelAnimationFrame(frame) - }, [edgeEndpoints, height, transform, width]) - - return ( -
- ) -} - -export const SummaryNode = memo(SummaryNodeImpl) diff --git a/src/modules/graph/lib/to-xyflow.ts b/src/modules/graph/lib/to-xyflow.ts index cf6af4c..ddc2f59 100644 --- a/src/modules/graph/lib/to-xyflow.ts +++ b/src/modules/graph/lib/to-xyflow.ts @@ -3,12 +3,7 @@ import ELK from 'elkjs/lib/elk.bundled.js' import type { ElkExtendedEdge, ElkNode } from 'elkjs/lib/elk.bundled.js' import type { Graph } from '@/modules/parser' -import type { - CodeNodeData, - GraphNodeData, - SectionNodeData, - SummaryNodeData, -} from '@/modules/graph/types' +import type { GraphNodeData, SectionNodeData } from '@/modules/graph/types' const NODE_WIDTH = 240 const NODE_HEIGHT = 54 @@ -34,17 +29,8 @@ export interface XYFlowGraph { edges: Array } -export interface XYFlowOptions { - expandedGroups?: Iterable -} - -export async function toXYFlow( - graph: Graph, - options: XYFlowOptions = {}, -): Promise { - const summarized = summarizeGraph(graph, options) - const nodes = summarized.nodes - const edges = summarized.edges +export async function toXYFlow(graph: Graph): Promise { + const { nodes, edges } = graphToFlow(graph) if (nodes.length === 0) return { nodes, edges } @@ -293,7 +279,6 @@ function sectionLabel( const firstEntry = entries.length > 0 ? entries[0] : undefined let title = 'Entry flow' if (firstEntry?.data.kind === 'code') title = firstEntry.data.displayName - if (firstEntry?.data.kind === 'summary') title = firstEntry.data.label const suffix = entries.length > 1 ? ` + ${entries.length - 1} more` : '' return { @@ -539,156 +524,44 @@ function qualifiedName(id: string, fallback: string): string { return idx >= 0 ? id.slice(idx + 2) : fallback } -function summarizeGraph(graph: Graph, options: XYFlowOptions): XYFlowGraph { - const expandedGroups = new Set(options.expandedGroups ?? []) - const groups = new Map< - string, - { - data: Omit - memberIds: Set - files: Set - } - >() - const visibleIdByOriginalId = new Map() - const visibleNodes: Array> = [] - - for (const node of graph.nodes) { - const group = groupForNode(node) - if (!group || expandedGroups.has(group.id)) { - visibleIdByOriginalId.set(node.id, node.id) - visibleNodes.push({ - id: node.id, - type: 'code', - position: { x: 0, y: 0 }, - data: { - kind: 'code', - displayName: qualifiedName(node.id, node.name), - type: node.type, - signature: node.signature, - file: node.file, - line: node.line, - endLine: node.endLine, - isAsync: node.isAsync, - isExported: node.isExported, - isStatic: node.isStatic, - bodyLines: node.bodyLines, - inDegree: node.inDegree, - outDegree: node.outDegree, - }, - }) - continue - } - - const existing = groups.get(group.id) ?? { - data: { - kind: 'summary' as const, - label: group.label, - subtitle: group.subtitle, - count: 0, - fileCount: 0, - }, - memberIds: new Set(), - files: new Set(), - } - existing.data.count += 1 - existing.memberIds.add(node.id) - existing.files.add(node.file) - groups.set(group.id, existing) - visibleIdByOriginalId.set(node.id, group.id) - } +function graphToFlow(graph: Graph): XYFlowGraph { + const nodes: Array> = graph.nodes.map((node) => ({ + id: node.id, + type: 'code', + position: { x: 0, y: 0 }, + data: { + kind: 'code', + displayName: qualifiedName(node.id, node.name), + type: node.type, + signature: node.signature, + file: node.file, + line: node.line, + endLine: node.endLine, + isAsync: node.isAsync, + isExported: node.isExported, + isStatic: node.isStatic, + bodyLines: node.bodyLines, + inDegree: node.inDegree, + outDegree: node.outDegree, + }, + })) const edgeKeys = new Set() - const visibleEdges: Edge[] = [] + const edges: Edge[] = [] for (const edge of graph.edges) { - const source = visibleIdByOriginalId.get(edge.source) - const target = visibleIdByOriginalId.get(edge.target) - if (!source || !target || source === target) continue - - const key = `${source}->${target}` + if (edge.source === edge.target) continue + const key = `${edge.source}->${edge.target}` if (edgeKeys.has(key)) continue edgeKeys.add(key) - visibleEdges.push({ + edges.push({ id: key, - source, - target, + source: edge.source, + target: edge.target, type: 'straight', - className: 'graph-edge', - interactionWidth: 0, - selectable: false, - focusable: false, - }) - } - - const degreeById = new Map() - for (const edge of visibleEdges) { - const sourceDegree = degreeById.get(edge.source) ?? { - inDegree: 0, - outDegree: 0, - } - sourceDegree.outDegree += 1 - degreeById.set(edge.source, sourceDegree) - - const targetDegree = degreeById.get(edge.target) ?? { - inDegree: 0, - outDegree: 0, - } - targetDegree.inDegree += 1 - degreeById.set(edge.target, targetDegree) - } - - for (const [id, group] of groups) { - const degree = degreeById.get(id) ?? { inDegree: 0, outDegree: 0 } - visibleNodes.push({ - id, - type: 'summary', - position: { x: 0, y: 0 }, - data: { - ...group.data, - fileCount: group.files.size, - subtitle: `${group.data.subtitle} · ${group.data.count} symbols`, - inDegree: degree.inDegree, - outDegree: degree.outDegree, - }, }) } - return { nodes: visibleNodes, edges: visibleEdges } -} - -function groupForNode(node: Graph['nodes'][number]): - | { - id: string - label: string - subtitle: string - } - | undefined { - if (node.file.startsWith('src/shared/ui/')) { - return { - id: 'summary:src/shared/ui', - label: 'UI primitives', - subtitle: 'src/shared/ui', - } - } - - if (node.inDegree === 0 && node.outDegree === 0) { - const folder = summaryFolder(node.file) - return { - id: `summary:isolated:${folder}`, - label: 'Unconnected symbols', - subtitle: folder, - } - } - - return undefined -} - -function summaryFolder(file: string): string { - const parts = file.split('/') - if (parts.length <= 1) return file - if (parts[0] === 'src' && parts.length >= 3) { - return parts.slice(0, 3).join('/') - } - return parts.slice(0, 2).join('/') + return { nodes, edges } } diff --git a/src/modules/graph/types.ts b/src/modules/graph/types.ts index f72bd20..b47edf8 100644 --- a/src/modules/graph/types.ts +++ b/src/modules/graph/types.ts @@ -16,16 +16,6 @@ export type CodeNodeData = { outDegree: number } -export type SummaryNodeData = { - kind: 'summary' - label: string - subtitle: string - count: number - fileCount: number - inDegree: number - outDegree: number -} - export type SectionNodeData = { kind: 'section' label: string @@ -34,4 +24,4 @@ export type SectionNodeData = { height: number } -export type GraphNodeData = CodeNodeData | SummaryNodeData | SectionNodeData +export type GraphNodeData = CodeNodeData | SectionNodeData diff --git a/src/shared/lib/active-panel.ts b/src/shared/lib/active-panel.ts index 6575764..eb8851c 100644 --- a/src/shared/lib/active-panel.ts +++ b/src/shared/lib/active-panel.ts @@ -20,12 +20,6 @@ export function useActivePanel() { return useSyncExternalStore(subscribe, getSnapshot, getSnapshot) } -export function setActivePanel(next: ActivePanel) { - if (active === next) return - active = next - for (const listener of listeners) listener() -} - export function toggleActivePanel(id: Exclude) { active = active === id ? null : id for (const listener of listeners) listener() diff --git a/src/shared/ui/accordion.tsx b/src/shared/ui/accordion.tsx deleted file mode 100644 index c8c4f83..0000000 --- a/src/shared/ui/accordion.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import * as React from 'react' -import { Accordion as AccordionPrimitive } from 'radix-ui' - -import { cn } from '@/shared/lib/utils' -import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react' - -function Accordion({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AccordionItem({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AccordionTrigger({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - - - {children} - - - - - ) -} - -function AccordionContent({ - className, - children, - ...props -}: React.ComponentProps) { - return ( - -
- {children} -
-
- ) -} - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/shared/ui/alert-dialog.tsx b/src/shared/ui/alert-dialog.tsx deleted file mode 100644 index 92533ed..0000000 --- a/src/shared/ui/alert-dialog.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import * as React from 'react' -import { AlertDialog as AlertDialogPrimitive } from 'radix-ui' - -import { cn } from '@/shared/lib/utils' -import { Button } from '@/shared/ui/button' - -function AlertDialog({ - ...props -}: React.ComponentProps) { - return -} - -function AlertDialogTrigger({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AlertDialogPortal({ - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AlertDialogOverlay({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AlertDialogContent({ - className, - size = 'default', - ...props -}: React.ComponentProps & { - size?: 'default' | 'sm' -}) { - return ( - - - - - ) -} - -function AlertDialogHeader({ - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function AlertDialogFooter({ - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function AlertDialogMedia({ - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function AlertDialogTitle({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AlertDialogDescription({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AlertDialogAction({ - className, - variant = 'default', - size = 'default', - ...props -}: React.ComponentProps & - Pick, 'variant' | 'size'>) { - return ( - - ) -} - -function AlertDialogCancel({ - className, - variant = 'outline', - size = 'default', - ...props -}: React.ComponentProps & - Pick, 'variant' | 'size'>) { - return ( - - ) -} - -export { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogMedia, - AlertDialogOverlay, - AlertDialogPortal, - AlertDialogTitle, - AlertDialogTrigger, -} diff --git a/src/shared/ui/alert.tsx b/src/shared/ui/alert.tsx deleted file mode 100644 index 0d5475c..0000000 --- a/src/shared/ui/alert.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import * as React from 'react' -import { cva } from 'class-variance-authority' -import type { VariantProps } from 'class-variance-authority' - -import { cn } from '@/shared/lib/utils' - -const alertVariants = cva( - "group/alert relative grid w-full gap-0.5 rounded-lg border px-4 py-3 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", - { - variants: { - variant: { - default: 'bg-card text-card-foreground', - destructive: - 'bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current', - }, - }, - defaultVariants: { - variant: 'default', - }, - }, -) - -function Alert({ - className, - variant, - ...props -}: React.ComponentProps<'div'> & VariantProps) { - return ( -
- ) -} - -function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground', - className, - )} - {...props} - /> - ) -} - -function AlertDescription({ - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function AlertAction({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -export { Alert, AlertTitle, AlertDescription, AlertAction } diff --git a/src/shared/ui/aspect-ratio.tsx b/src/shared/ui/aspect-ratio.tsx deleted file mode 100644 index 47732b8..0000000 --- a/src/shared/ui/aspect-ratio.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { AspectRatio as AspectRatioPrimitive } from 'radix-ui' - -function AspectRatio({ - ...props -}: React.ComponentProps) { - return -} - -export { AspectRatio } diff --git a/src/shared/ui/avatar.tsx b/src/shared/ui/avatar.tsx deleted file mode 100644 index 626e22c..0000000 --- a/src/shared/ui/avatar.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import * as React from 'react' -import { Avatar as AvatarPrimitive } from 'radix-ui' - -import { cn } from '@/shared/lib/utils' - -function Avatar({ - className, - size = 'default', - ...props -}: React.ComponentProps & { - size?: 'default' | 'sm' | 'lg' -}) { - return ( - - ) -} - -function AvatarImage({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AvatarFallback({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AvatarBadge({ className, ...props }: React.ComponentProps<'span'>) { - return ( - svg]:hidden', - 'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2', - 'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2', - className, - )} - {...props} - /> - ) -} - -function AvatarGroup({ className, ...props }: React.ComponentProps<'div'>) { - return ( -
- ) -} - -function AvatarGroupCount({ - className, - ...props -}: React.ComponentProps<'div'>) { - return ( -
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3', - className, - )} - {...props} - /> - ) -} - -export { - Avatar, - AvatarImage, - AvatarFallback, - AvatarGroup, - AvatarGroupCount, - AvatarBadge, -} diff --git a/src/shared/ui/badge.tsx b/src/shared/ui/badge.tsx deleted file mode 100644 index 43f0780..0000000 --- a/src/shared/ui/badge.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import * as React from 'react' -import { cva } from 'class-variance-authority' -import type { VariantProps } from 'class-variance-authority' -import { Slot } from 'radix-ui' - -import { cn } from '@/shared/lib/utils' - -const badgeVariants = cva( - 'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!', - { - variants: { - variant: { - default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80', - secondary: - 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80', - destructive: - 'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20', - outline: - 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground', - ghost: - 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50', - link: 'text-primary underline-offset-4 hover:underline', - }, - }, - defaultVariants: { - variant: 'default', - }, - }, -) - -function Badge({ - className, - variant = 'default', - asChild = false, - ...props -}: React.ComponentProps<'span'> & - VariantProps & { asChild?: boolean }) { - const Comp = asChild ? Slot.Root : 'span' - - return ( - - ) -} - -export { Badge, badgeVariants } diff --git a/src/shared/ui/button-group.tsx b/src/shared/ui/button-group.tsx deleted file mode 100644 index 5b96347..0000000 --- a/src/shared/ui/button-group.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { cva } from 'class-variance-authority' -import type { VariantProps } from 'class-variance-authority' -import { Slot } from 'radix-ui' - -import { cn } from '@/shared/lib/utils' -import { Separator } from '@/shared/ui/separator' - -const buttonGroupVariants = cva( - "group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1", - { - variants: { - orientation: { - horizontal: - '[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-md!', - vertical: - 'flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-md!', - }, - }, - defaultVariants: { - orientation: 'horizontal', - }, - }, -) - -function ButtonGroup({ - className, - orientation, - ...props -}: React.ComponentProps<'div'> & VariantProps) { - return ( -
- ) -} - -function ButtonGroupText({ - className, - asChild = false, - ...props -}: React.ComponentProps<'div'> & { - asChild?: boolean -}) { - const Comp = asChild ? Slot.Root : 'div' - - return ( - - ) -} - -function ButtonGroupSeparator({ - className, - orientation = 'vertical', - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { - ButtonGroup, - ButtonGroupSeparator, - ButtonGroupText, - buttonGroupVariants, -} diff --git a/src/shared/ui/calendar.tsx b/src/shared/ui/calendar.tsx deleted file mode 100644 index bda6481..0000000 --- a/src/shared/ui/calendar.tsx +++ /dev/null @@ -1,225 +0,0 @@ -'use client' - -import * as React from 'react' -import { DayPicker, getDefaultClassNames } from 'react-day-picker' -import type { DayButton, Locale } from 'react-day-picker' - -import { cn } from '@/shared/lib/utils' -import { Button, buttonVariants } from '@/shared/ui/button' -import { - ChevronLeftIcon, - ChevronRightIcon, - ChevronDownIcon, -} from 'lucide-react' - -function Calendar({ - className, - classNames, - showOutsideDays = true, - captionLayout = 'label', - buttonVariant = 'ghost', - locale, - formatters, - components, - ...props -}: React.ComponentProps & { - buttonVariant?: React.ComponentProps['variant'] -}) { - const defaultClassNames = getDefaultClassNames() - - return ( - svg]:rotate-180`, - String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`, - className, - )} - captionLayout={captionLayout} - locale={locale} - formatters={{ - formatMonthDropdown: (date) => - date.toLocaleString(locale?.code, { month: 'short' }), - ...formatters, - }} - classNames={{ - root: cn('w-fit', defaultClassNames.root), - months: cn( - 'relative flex flex-col gap-4 md:flex-row', - defaultClassNames.months, - ), - month: cn('flex w-full flex-col gap-4', defaultClassNames.month), - nav: cn( - 'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1', - defaultClassNames.nav, - ), - button_previous: cn( - buttonVariants({ variant: buttonVariant }), - 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50', - defaultClassNames.button_previous, - ), - button_next: cn( - buttonVariants({ variant: buttonVariant }), - 'size-(--cell-size) p-0 select-none aria-disabled:opacity-50', - defaultClassNames.button_next, - ), - month_caption: cn( - 'flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)', - defaultClassNames.month_caption, - ), - dropdowns: cn( - 'flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium', - defaultClassNames.dropdowns, - ), - dropdown_root: cn( - 'relative rounded-(--cell-radius)', - defaultClassNames.dropdown_root, - ), - dropdown: cn( - 'absolute inset-0 bg-popover opacity-0', - defaultClassNames.dropdown, - ), - caption_label: cn( - 'font-medium select-none', - captionLayout === 'label' - ? 'text-sm' - : 'flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground', - defaultClassNames.caption_label, - ), - table: 'w-full border-collapse', - weekdays: cn('flex', defaultClassNames.weekdays), - weekday: cn( - 'flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none', - defaultClassNames.weekday, - ), - week: cn('mt-2 flex w-full', defaultClassNames.week), - week_number_header: cn( - 'w-(--cell-size) select-none', - defaultClassNames.week_number_header, - ), - week_number: cn( - 'text-[0.8rem] text-muted-foreground select-none', - defaultClassNames.week_number, - ), - day: cn( - 'group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)', - props.showWeekNumber - ? '[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)' - : '[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)', - defaultClassNames.day, - ), - range_start: cn( - 'relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted', - defaultClassNames.range_start, - ), - range_middle: cn('rounded-none', defaultClassNames.range_middle), - range_end: cn( - 'relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted', - defaultClassNames.range_end, - ), - today: cn( - 'rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none', - defaultClassNames.today, - ), - outside: cn( - 'text-muted-foreground aria-selected:text-muted-foreground', - defaultClassNames.outside, - ), - disabled: cn( - 'text-muted-foreground opacity-50', - defaultClassNames.disabled, - ), - hidden: cn('invisible', defaultClassNames.hidden), - ...classNames, - }} - components={{ - Root: ({ className, rootRef, ...props }) => { - return ( -
- ) - }, - Chevron: ({ className, orientation, ...props }) => { - if (orientation === 'left') { - return ( - - ) - } - - if (orientation === 'right') { - return ( - - ) - } - - return ( - - ) - }, - DayButton: ({ ...props }) => ( - - ), - WeekNumber: ({ children, ...props }) => { - return ( - -
- {children} -
- - ) - }, - ...components, - }} - {...props} - /> - ) -} - -function CalendarDayButton({ - className, - day, - modifiers, - locale, - ...props -}: React.ComponentProps & { locale?: Partial }) { - const defaultClassNames = getDefaultClassNames() - - const ref = React.useRef(null) - React.useEffect(() => { - if (modifiers.focused) ref.current?.focus() - }, [modifiers.focused]) - - return ( - - ) -} - -function CarouselNext({ - className, - variant = 'outline', - size = 'icon-sm', - ...props -}: React.ComponentProps) { - const { orientation, scrollNext, canScrollNext } = useCarousel() - - return ( - - ) -} - -export { - type CarouselApi, - Carousel, - CarouselContent, - CarouselItem, - CarouselPrevious, - CarouselNext, - useCarousel, -} diff --git a/src/shared/ui/chart.tsx b/src/shared/ui/chart.tsx deleted file mode 100644 index eddaa2d..0000000 --- a/src/shared/ui/chart.tsx +++ /dev/null @@ -1,371 +0,0 @@ -'use client' - -import * as React from 'react' -import * as RechartsPrimitive from 'recharts' -import type { TooltipValueType } from 'recharts' - -import { cn } from '@/shared/lib/utils' - -// Format: { THEME_NAME: CSS_SELECTOR } -const THEMES = { light: '', dark: '.dark' } as const - -const INITIAL_DIMENSION = { width: 320, height: 200 } as const -type TooltipNameType = number | string - -export type ChartConfig = Record< - string, - { - label?: React.ReactNode - icon?: React.ComponentType - } & ( - | { color?: string; theme?: never } - | { color?: never; theme: Record } - ) -> - -type ChartContextProps = { - config: ChartConfig -} - -const ChartContext = React.createContext(null) - -function useChart() { - const context = React.useContext(ChartContext) - - if (!context) { - throw new Error('useChart must be used within a ') - } - - return context -} - -function ChartContainer({ - id, - className, - children, - config, - initialDimension = INITIAL_DIMENSION, - ...props -}: React.ComponentProps<'div'> & { - config: ChartConfig - children: React.ComponentProps< - typeof RechartsPrimitive.ResponsiveContainer - >['children'] - initialDimension?: { - width: number - height: number - } -}) { - const uniqueId = React.useId() - const chartId = `chart-${id ?? uniqueId.replace(/:/g, '')}` - - return ( - -
- - - {children} - -
-
- ) -} - -const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => { - const colorConfig = Object.entries(config).filter( - ([, config]) => config.theme ?? config.color, - ) - - if (!colorConfig.length) { - return null - } - - return ( -