From fb7a8b8536148eca2f52f6d2affca233b805d8f9 Mon Sep 17 00:00:00 2001 From: Alex K <1955195+AlexKlim@users.noreply.github.com> Date: Fri, 21 Aug 2026 11:59:26 +0300 Subject: [PATCH] feat: add Excalidraw diagram editor widget --- .gitignore | 2 + cmd/wsh/cmd/wshcmd-excalidraw.go | 180 +++ docs/docs/wsh-reference.mdx | 67 + electron.vite.config.ts | 5 + frontend/app/block/blockregistry.ts | 2 + frontend/app/block/blockutil.tsx | 6 + frontend/app/store/wshclientapi.ts | 6 + .../app/view/excalidraw/excalidraw-model.ts | 247 +++ frontend/app/view/excalidraw/excalidraw.tsx | 36 + frontend/types/gotypes.d.ts | 7 + frontend/types/waveevent.d.ts | 4 +- package-lock.json | 1415 ++++++++++++++++- package.json | 1 + pkg/aiusechat/usechat-prompts.go | 16 + pkg/tsgen/tsgenevent.go | 1 + pkg/wps/wpstypes.go | 2 + pkg/wshrpc/wshclient/wshclient.go | 6 + pkg/wshrpc/wshrpctypes.go | 7 + pkg/wshrpc/wshserver/wshserver.go | 22 + postinstall.cjs | 19 + 20 files changed, 2049 insertions(+), 2 deletions(-) create mode 100644 cmd/wsh/cmd/wshcmd-excalidraw.go create mode 100644 frontend/app/view/excalidraw/excalidraw-model.ts create mode 100644 frontend/app/view/excalidraw/excalidraw.tsx diff --git a/.gitignore b/.gitignore index 7bd717e540..c8c4ed2589 100644 --- a/.gitignore +++ b/.gitignore @@ -39,8 +39,10 @@ storybook-static/ test-results.xml docsite/ +public/excalidraw/ .kilo-format-temp-* .superpowers docs/superpowers .claude +.planning/ diff --git a/cmd/wsh/cmd/wshcmd-excalidraw.go b/cmd/wsh/cmd/wshcmd-excalidraw.go new file mode 100644 index 0000000000..2be5d9c936 --- /dev/null +++ b/cmd/wsh/cmd/wshcmd-excalidraw.go @@ -0,0 +1,180 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "time" + + "github.com/spf13/cobra" + "github.com/wavetermdev/waveterm/pkg/waveobj" + "github.com/wavetermdev/waveterm/pkg/wshrpc" + "github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient" +) + +var excalidrawMagnified bool + +var excalidrawCmd = &cobra.Command{ + Use: "excalidraw [file]", + Short: "open an Excalidraw diagram", + Args: cobra.MaximumNArgs(1), + RunE: excalidrawRun, + PreRunE: preRunSetupRpcClient, +} + +var excalidrawPushCmd = &cobra.Command{ + Use: "push [file]", + Short: "push Excalidraw JSON into a block's scene", + Args: cobra.RangeArgs(1, 2), + RunE: excalidrawPushRun, + PreRunE: preRunSetupRpcClient, +} + +var excalidrawMermaidCmd = &cobra.Command{ + Use: "mermaid [blockid] [file]", + Short: "open or push a Mermaid diagram as Excalidraw", + Args: cobra.RangeArgs(0, 2), + RunE: excalidrawMermaidRun, + PreRunE: preRunSetupRpcClient, +} + +func init() { + excalidrawCmd.Flags().BoolVarP(&excalidrawMagnified, "magnified", "m", false, "open in magnified mode") + excalidrawCmd.AddCommand(excalidrawPushCmd) + excalidrawCmd.AddCommand(excalidrawMermaidCmd) + rootCmd.AddCommand(excalidrawCmd) +} + +func excalidrawRun(cmd *cobra.Command, args []string) (rtnErr error) { + defer func() { + sendActivity("excalidraw", rtnErr == nil) + }() + tabId := getTabIdFromEnv() + if tabId == "" { + return fmt.Errorf("no WAVETERM_TABID env var set") + } + meta := map[string]any{ + waveobj.MetaKey_View: "excalidraw", + } + if len(args) > 0 { + absFile, err := filepath.Abs(args[0]) + if err != nil { + return fmt.Errorf("getting absolute path: %w", err) + } + meta[waveobj.MetaKey_File] = absFile + } + wshCmd := &wshrpc.CommandCreateBlockData{ + TabId: tabId, + BlockDef: &waveobj.BlockDef{ + Meta: meta, + }, + Magnified: excalidrawMagnified, + Focused: true, + } + _, err := wshclient.CreateBlockCommand(RpcClient, *wshCmd, &wshrpc.RpcOpts{Timeout: 2000}) + if err != nil { + return fmt.Errorf("creating excalidraw block: %w", err) + } + return nil +} + +func excalidrawPushRun(cmd *cobra.Command, args []string) (rtnErr error) { + defer func() { + sendActivity("excalidraw:push", rtnErr == nil) + }() + blockId := args[0] + var jsonData []byte + var err error + if len(args) > 1 { + jsonData, err = os.ReadFile(args[1]) + } else { + jsonData, err = io.ReadAll(os.Stdin) + } + if err != nil { + return fmt.Errorf("reading input: %w", err) + } + var sceneData any + if err := json.Unmarshal(jsonData, &sceneData); err != nil { + return fmt.Errorf("invalid JSON: %w", err) + } + pushData := wshrpc.CommandExcalidrawPushData{ + BlockId: blockId, + SceneData: sceneData, + } + err = wshclient.ExcalidrawPushCommand(RpcClient, pushData, &wshrpc.RpcOpts{Timeout: 5000}) + if err != nil { + return fmt.Errorf("push failed: %w", err) + } + return nil +} + +func excalidrawMermaidRun(cmd *cobra.Command, args []string) (rtnErr error) { + defer func() { + sendActivity("excalidraw:mermaid", rtnErr == nil) + }() + tabId := getTabIdFromEnv() + if tabId == "" { + return fmt.Errorf("no WAVETERM_TABID env var set") + } + var blockId string + var mermaidData []byte + var err error + switch len(args) { + case 0: + mermaidData, err = io.ReadAll(os.Stdin) + if err != nil { + return fmt.Errorf("reading stdin: %w", err) + } + case 1: + mermaidData, err = os.ReadFile(args[0]) + if err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("reading file: %w", err) + } + blockId = args[0] + mermaidData, err = io.ReadAll(os.Stdin) + if err != nil { + return fmt.Errorf("reading stdin: %w", err) + } + } + case 2: + blockId = args[0] + mermaidData, err = os.ReadFile(args[1]) + if err != nil { + return fmt.Errorf("reading file: %w", err) + } + } + if blockId == "" { + createData := &wshrpc.CommandCreateBlockData{ + TabId: tabId, + BlockDef: &waveobj.BlockDef{ + Meta: map[string]any{ + waveobj.MetaKey_View: "excalidraw", + }, + }, + Magnified: excalidrawMagnified, + Focused: true, + } + oref, err := wshclient.CreateBlockCommand(RpcClient, *createData, &wshrpc.RpcOpts{Timeout: 2000}) + if err != nil { + return fmt.Errorf("creating excalidraw block: %w", err) + } + blockId = oref.OID + time.Sleep(500 * time.Millisecond) + } + pushData := wshrpc.CommandExcalidrawPushData{ + BlockId: blockId, + SceneData: string(mermaidData), + Format: "mermaid", + } + err = wshclient.ExcalidrawPushCommand(RpcClient, pushData, &wshrpc.RpcOpts{Timeout: 5000}) + if err != nil { + return fmt.Errorf("mermaid push failed: %w", err) + } + return nil +} diff --git a/docs/docs/wsh-reference.mdx b/docs/docs/wsh-reference.mdx index 6ed1bcaa3f..225aa2cd28 100644 --- a/docs/docs/wsh-reference.mdx +++ b/docs/docs/wsh-reference.mdx @@ -195,6 +195,73 @@ wsh editconfig presets/ai.json --- +## excalidraw + +Open an Excalidraw diagram in a new block. + +```sh +wsh excalidraw [file] +``` + +Opens the specified `.excalidraw` file for editing. If the file does not exist, creates an empty canvas with that file path set for autosave. If no file is specified, opens a blank canvas. + +Flags: + +- `-m, --magnified` - open the block in magnified mode + +Examples: + +```sh +# Open an existing diagram +wsh excalidraw diagram.excalidraw + +# Create a new diagram (file will be created on first save) +wsh excalidraw ~/diagrams/new-design.excalidraw + +# Open a blank canvas (no file path) +wsh excalidraw + +# Open in magnified mode +wsh excalidraw -m architecture.excalidraw +``` + +### push + +```sh +wsh excalidraw push [file] +``` + +Replaces the scene in an existing Excalidraw block with Excalidraw JSON read from `file`, or from stdin if no file is given. If the block is backed by a file, the pushed scene is autosaved to it. + +```sh +# Replace a block's scene from a file +wsh excalidraw push diagram.excalidraw + +# Pipe a generated scene into a block +cat scene.json | wsh excalidraw push +``` + +### mermaid + +```sh +wsh excalidraw mermaid [blockid] [file] +``` + +Converts a Mermaid diagram to Excalidraw. With no `blockid`, opens the result in a new block. The Mermaid source is read from `file`, or from stdin if no file is given. + +```sh +# Convert a Mermaid file and open in a new block +wsh excalidraw mermaid flowchart.mmd + +# Push a converted Mermaid diagram into an existing block +wsh excalidraw mermaid flowchart.mmd + +# Pipe Mermaid source into an existing block +echo "graph TD; A-->B" | wsh excalidraw mermaid +``` + +--- + ## setbg The `setbg` command allows you to set a background image or color for the current tab with various customization options. diff --git a/electron.vite.config.ts b/electron.vite.config.ts index d94a166659..702585d1e2 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -123,6 +123,9 @@ export default defineConfig({ }, renderer: { root: ".", + define: { + "process.env.IS_PREACT": JSON.stringify("false"), + }, build: { target: CHROME, sourcemap: true, @@ -142,6 +145,8 @@ export default defineConfig({ } if (p.includes("node_modules/cytoscape") || p.includes("node_modules/@cytoscape")) return "cytoscape"; + if (p.includes("node_modules/excalidraw") || p.includes("node_modules/@excalidraw")) + return "excalidraw"; return undefined; }, }, diff --git a/frontend/app/block/blockregistry.ts b/frontend/app/block/blockregistry.ts index 5de7e05bd3..ee26f52811 100644 --- a/frontend/app/block/blockregistry.ts +++ b/frontend/app/block/blockregistry.ts @@ -6,6 +6,7 @@ import type { TabModel } from "@/app/store/tab-model"; import { AiFileDiffViewModel } from "@/app/view/aifilediff/aifilediff"; import { LauncherViewModel } from "@/app/view/launcher/launcher"; import { PreviewModel } from "@/app/view/preview/preview-model"; +import { ExcalidrawModel } from "@/app/view/excalidraw/excalidraw-model"; import { ProcessViewerViewModel } from "@/app/view/processviewer/processviewer"; import { SysinfoViewModel } from "@/app/view/sysinfo/sysinfo"; import { TsunamiViewModel } from "@/app/view/tsunami/tsunami"; @@ -35,6 +36,7 @@ BlockRegistry.set("tsunami", TsunamiViewModel); BlockRegistry.set("aifilediff", AiFileDiffViewModel); BlockRegistry.set("waveconfig", WaveConfigViewModel); BlockRegistry.set("processviewer", ProcessViewerViewModel); +BlockRegistry.set("excalidraw", ExcalidrawModel); function makeDefaultViewModel(viewType: string): ViewModel { const viewModel: ViewModel = { diff --git a/frontend/app/block/blockutil.tsx b/frontend/app/block/blockutil.tsx index 3ef4d39821..30e2d28b26 100644 --- a/frontend/app/block/blockutil.tsx +++ b/frontend/app/block/blockutil.tsx @@ -45,6 +45,9 @@ export function blockViewToIcon(view: string): string { if (view == "processviewer") { return "microchip"; } + if (view == "excalidraw") { + return "pen-ruler"; + } return "square"; } @@ -73,6 +76,9 @@ export function blockViewToName(view: string): string { if (view == "processviewer") { return "Processes"; } + if (view == "excalidraw") { + return "Excalidraw"; + } return view; } diff --git a/frontend/app/store/wshclientapi.ts b/frontend/app/store/wshclientapi.ts index 8482be260d..b051fa7a88 100644 --- a/frontend/app/store/wshclientapi.ts +++ b/frontend/app/store/wshclientapi.ts @@ -294,6 +294,12 @@ export class RpcApiType { return client.wshRpcCall("eventunsuball", null, opts); } + // command "excalidrawpush" [call] + ExcalidrawPushCommand(client: WshClient, data: CommandExcalidrawPushData, opts?: RpcOpts): Promise { + if (this.mockClient) return this.mockClient.mockWshRpcCall(client, "excalidrawpush", data, opts); + return client.wshRpcCall("excalidrawpush", data, opts); + } + // command "fetchsuggestions" [call] FetchSuggestionsCommand(client: WshClient, data: FetchSuggestionsData, opts?: RpcOpts): Promise { if (this.mockClient) return this.mockClient.mockWshRpcCall(client, "fetchsuggestions", data, opts); diff --git a/frontend/app/view/excalidraw/excalidraw-model.ts b/frontend/app/view/excalidraw/excalidraw-model.ts new file mode 100644 index 0000000000..696b4c4d2e --- /dev/null +++ b/frontend/app/view/excalidraw/excalidraw-model.ts @@ -0,0 +1,247 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { BlockNodeModel } from "@/app/block/blocktypes"; +import { globalStore } from "@/app/store/jotaiStore"; +import { waveEventSubscribeSingle } from "@/app/store/wps"; +import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { base64ToString, stringToBase64 } from "@/util/util"; +import { CaptureUpdateAction, convertToExcalidrawElements, getSceneVersion, THEME } from "@excalidraw/excalidraw"; +import { parseMermaidToExcalidraw } from "@excalidraw/mermaid-to-excalidraw"; +import { atom, type Atom, type PrimitiveAtom } from "jotai"; +import { loadable } from "jotai/utils"; + +import type { WaveEnv } from "@/app/waveenv/waveenv"; +import { ExcalidrawView } from "./excalidraw"; + +const AutosaveDebounceMs = 1500; + +export class ExcalidrawModel implements ViewModel { + viewType = "excalidraw"; + blockId: string; + nodeModel: BlockNodeModel; + viewComponent: ViewComponent = ExcalidrawView; + + noPadding = atom(true); + isDirtyAtom = atom(false) as PrimitiveAtom; + + viewIcon!: Atom; + viewName!: Atom; + themeAtom!: Atom; + filePathAtom!: Atom; + sceneAtom!: Atom>; + loadableSceneAtom!: Atom>; + errorMsgAtom!: PrimitiveAtom; + + blockAtom!: Atom; + + private env: WaveEnv; + private excalidrawAPI: any = null; + private lastSavedVersion: number = 0; + private pendingElements: readonly any[] = []; + private pendingAppState: any = null; + private pendingFiles: any = null; + private pushSceneUnsubFn: (() => void) | null = null; + private saveTimeoutId: ReturnType | null = null; + private saveChain: Promise = Promise.resolve(); + private pendingPushScene: { elements: any[]; appState?: any; files?: any } | null = null; + + constructor({ blockId, nodeModel, waveEnv }: ViewModelInitType) { + this.blockId = blockId; + this.nodeModel = nodeModel; + this.env = waveEnv; + + this.blockAtom = waveEnv.wos.getWaveObjectAtom(`block:${blockId}`); + this.errorMsgAtom = atom(null) as PrimitiveAtom; + this.viewIcon = atom("pen-ruler"); + + this.filePathAtom = atom((get) => { + return get(this.blockAtom)?.meta?.file ?? null; + }); + + this.viewName = atom((get) => { + const filePath = get(this.filePathAtom); + const isDirty = get(this.isDirtyAtom); + const name = filePath ? filePath.split("/").pop() ?? "Excalidraw" : "Excalidraw"; + return isDirty ? `${name} *` : name; + }); + + this.themeAtom = atom(() => { + return THEME.DARK; + }); + + this.sceneAtom = atom(async (get) => { + const filePath = get(this.filePathAtom); + if (!filePath) { + return null; + } + try { + const fileData = await waveEnv.rpc.FileReadCommand(TabRpcClient, { + info: { path: filePath }, + }); + const content = base64ToString(fileData?.data64); + try { + return JSON.parse(content); + } catch { + globalStore.set(this.errorMsgAtom, { + status: "Invalid Diagram File", + text: "The file does not contain valid Excalidraw JSON. The file may be corrupted.", + }); + return null; + } + } catch (e) { + const errStr = `${e}`; + const isNotFound = errStr.includes("not found") || errStr.includes("no such file"); + globalStore.set(this.errorMsgAtom, { + status: isNotFound ? "File Not Found" : "File Read Failed", + text: errStr, + }); + return null; + } + }); + + this.loadableSceneAtom = loadable(this.sceneAtom); + + this.pushSceneUnsubFn = waveEventSubscribeSingle({ + eventType: "excalidraw:pushscene", + scope: `block:${blockId}`, + handler: async (event) => { + const pushData = event.data as any; + if (!pushData) return; + + let elements: any[]; + let appState: any = {}; + let files: any = undefined; + + if (pushData.format === "mermaid") { + try { + const mermaidText = pushData.scenedata as string; + const result = await parseMermaidToExcalidraw(mermaidText); + elements = convertToExcalidrawElements(result.elements); + files = result.files; + } catch (e) { + globalStore.set(this.errorMsgAtom, { + status: "Mermaid Conversion Failed", + text: `${e}`, + }); + return; + } + } else { + const sceneData = pushData.scenedata ?? pushData; + if (sceneData?.type === "excalidraw") { + elements = sceneData.elements || []; + appState = sceneData.appState || {}; + } else if (Array.isArray(sceneData)) { + elements = sceneData; + } else { + return; + } + } + + const sceneUpdate = { elements, appState, files }; + if (!this.excalidrawAPI) { + this.pendingPushScene = sceneUpdate; + return; + } + this.applyRemoteScene(sceneUpdate); + }, + }); + } + + setExcalidrawAPI(api: any) { + this.excalidrawAPI = api; + if (this.pendingPushScene && api) { + this.applyRemoteScene(this.pendingPushScene); + this.pendingPushScene = null; + } + } + + // updateScene() does not accept binary file data, so image files must go + // through addFiles() separately or fileId references render as skeletons + private applyRemoteScene(scene: { elements: any[]; appState?: any; files?: any }) { + if (scene.files != null && Object.keys(scene.files).length > 0) { + this.excalidrawAPI.addFiles(Object.values(scene.files)); + } + this.excalidrawAPI.updateScene({ + elements: scene.elements, + appState: scene.appState, + captureUpdate: CaptureUpdateAction.IMMEDIATELY, + }); + this.pendingElements = scene.elements; + this.pendingAppState = scene.appState; + this.pendingFiles = scene.files; + globalStore.set(this.isDirtyAtom, true); + this.debouncedSave(); + } + + handleChange(elements: readonly any[], appState: any, files: any) { + const newVersion = getSceneVersion(elements); + if (newVersion === this.lastSavedVersion) { + return; + } + globalStore.set(this.isDirtyAtom, true); + this.pendingElements = elements; + this.pendingAppState = appState; + this.pendingFiles = files; + this.debouncedSave(); + } + + private debouncedSave() { + if (this.saveTimeoutId != null) { + clearTimeout(this.saveTimeoutId); + } + this.saveTimeoutId = setTimeout(() => this.performSave(), AutosaveDebounceMs); + } + + async performSave() { + const filePath = globalStore.get(this.filePathAtom); + if (!filePath) { + return; + } + // snapshot the scene as JSON now: excalidraw mutates elements in place, + // and writes are chained so an older queued write cannot clobber a newer one + const version = getSceneVersion(this.pendingElements as any[]); + const sceneJson = JSON.stringify( + { + type: "excalidraw", + version: 2, + elements: this.pendingElements, + appState: { + viewBackgroundColor: this.pendingAppState?.viewBackgroundColor, + }, + files: this.pendingFiles, + }, + null, + 2 + ); + this.saveChain = this.saveChain.then(async () => { + try { + await this.env.rpc.FileWriteCommand(TabRpcClient, { + info: { path: filePath }, + data64: stringToBase64(sceneJson), + }); + this.lastSavedVersion = version; + if (getSceneVersion(this.pendingElements as any[]) === version) { + globalStore.set(this.isDirtyAtom, false); + } + } catch (e) { + console.error("excalidraw autosave failed:", e); + } + }); + return this.saveChain; + } + + dispose() { + if (this.pushSceneUnsubFn) { + this.pushSceneUnsubFn(); + this.pushSceneUnsubFn = null; + } + if (this.saveTimeoutId != null) { + clearTimeout(this.saveTimeoutId); + this.saveTimeoutId = null; + } + if (globalStore.get(this.isDirtyAtom)) { + this.performSave(); + } + } +} diff --git a/frontend/app/view/excalidraw/excalidraw.tsx b/frontend/app/view/excalidraw/excalidraw.tsx new file mode 100644 index 0000000000..0439c1d252 --- /dev/null +++ b/frontend/app/view/excalidraw/excalidraw.tsx @@ -0,0 +1,36 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import "@excalidraw/excalidraw/index.css"; + +import { ErrorOverlay } from "@/app/view/preview/preview-error-overlay"; +import { Excalidraw } from "@excalidraw/excalidraw"; +import { useAtom, useAtomValue } from "jotai"; + +import { ExcalidrawModel } from "./excalidraw-model"; + +(window as any).EXCALIDRAW_ASSET_PATH = "/excalidraw/"; + +export const ExcalidrawView: React.FC> = ({ model }) => { + const theme = useAtomValue(model.themeAtom); + const sceneLoadable = useAtomValue(model.loadableSceneAtom); + const [errorMsg, setErrorMsg] = useAtom(model.errorMsgAtom); + + if (sceneLoadable.state === "loading") { + return
; + } + + const scene = sceneLoadable.state === "hasData" ? sceneLoadable.data : null; + + return ( +
+ {errorMsg && setErrorMsg(null)} />} + model.handleChange(elements, appState, files)} + excalidrawAPI={(api) => model.setExcalidrawAPI(api)} + /> +
+ ); +}; diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index c5b870d7ed..0a3bafd632 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -378,6 +378,13 @@ declare global { maxitems: number; }; + // wshrpc.CommandExcalidrawPushData + type CommandExcalidrawPushData = { + blockid: string; + scenedata: any; + format?: string; + }; + // wshrpc.CommandFileCopyData type CommandFileCopyData = { srcuri: string; diff --git a/frontend/types/waveevent.d.ts b/frontend/types/waveevent.d.ts index c3e5bd7822..1d192bc2e9 100644 --- a/frontend/types/waveevent.d.ts +++ b/frontend/types/waveevent.d.ts @@ -26,6 +26,7 @@ declare global { | "waveai:modeconfig" | "block:jobstatus" | "badge" + | "excalidraw:pushscene" ; type WaveEvent = { @@ -53,7 +54,8 @@ declare global { { event: "tsunami:updatemeta"; data?: AppMeta; } | { event: "waveai:modeconfig"; data?: AIModeConfigUpdate; } | { event: "block:jobstatus"; data?: BlockJobStatusData; } | - { event: "badge"; data?: BadgeEvent; } + { event: "badge"; data?: BadgeEvent; } | + { event: "excalidraw:pushscene"; data?: CommandExcalidrawPushData; } ); } diff --git a/package-lock.json b/package-lock.json index 9e35b8b85b..83f9676aba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ ], "dependencies": { "@ai-sdk/react": "^2.0.104", + "@excalidraw/excalidraw": "^0.18.1", "@floating-ui/react": "^0.27.16", "@observablehq/plot": "^0.6.17", "@react-hook/resize-observer": "^2.0.2", @@ -2282,12 +2283,69 @@ "integrity": "sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==", "license": "MIT" }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/cst-dts-gen/node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast/node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/gast/node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, "node_modules/@chevrotain/types": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", "license": "Apache-2.0" }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -5383,6 +5441,522 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@excalidraw/excalidraw": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.18.1.tgz", + "integrity": "sha512-6i5Gt7IDTOH//qa0Z315Ly5iVRhjWpu2whrlQFqkuwrkKUWgRsMk0P5qdE7bpyDpai7jeLeWYkyj1eVAfni1lw==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "6.0.2", + "@excalidraw/laser-pointer": "1.3.1", + "@excalidraw/mermaid-to-excalidraw": "2.2.2", + "@excalidraw/random-username": "1.1.0", + "@radix-ui/react-popover": "1.1.6", + "@radix-ui/react-tabs": "1.0.2", + "browser-fs-access": "0.29.1", + "canvas-roundrect-polyfill": "0.0.1", + "clsx": "1.1.1", + "cross-env": "7.0.3", + "es6-promise-pool": "2.5.0", + "fractional-indexing": "3.2.0", + "fuzzy": "0.1.3", + "image-blob-reduce": "3.0.1", + "jotai": "2.11.0", + "jotai-scope": "0.7.2", + "lodash.debounce": "4.0.8", + "lodash.throttle": "4.1.1", + "nanoid": "3.3.3", + "open-color": "1.9.1", + "pako": "2.0.3", + "perfect-freehand": "1.2.0", + "pica": "7.1.1", + "png-chunk-text": "1.0.0", + "png-chunks-encode": "1.0.0", + "png-chunks-extract": "1.0.0", + "points-on-curve": "1.0.1", + "pwacompat": "2.0.17", + "roughjs": "4.6.4", + "sass": "1.51.0", + "tunnel-rat": "0.1.2" + }, + "peerDependencies": { + "react": "^17.0.2 || ^18.2.0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.2.0 || ^19.0.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@braintree/sanitize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz", + "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==", + "license": "MIT" + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/primitive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", + "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz", + "integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-roving-focus": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", + "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-direction": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz", + "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", + "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-id/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", + "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", + "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz", + "integrity": "sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", + "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.2.tgz", + "integrity": "sha512-HLK+CqD/8pN6GfJm3U+cqpqhSKYAWiOJDe+A+8MfxBnOue39QEeMa43csUn2CXCHQT0/mewh1LrrG4tfkM9DMA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.1.tgz", + "integrity": "sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz", + "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", + "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", + "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-use-controllable-state/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", + "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/immutable": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.9.tgz", + "integrity": "sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==", + "license": "MIT" + }, + "node_modules/@excalidraw/excalidraw/node_modules/jotai": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.11.0.tgz", + "integrity": "sha512-zKfoBBD1uDw3rljwHkt0fWuja1B76R7CjznuBO+mSX6jpsO1EBeWNRKpeaQho9yPI/pvCv4recGfgOXGxwPZvQ==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/points-on-curve": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-1.0.1.tgz", + "integrity": "sha512-3nmX4/LIiyuwGLwuUrfhTlDeQFlAhi7lyK/zcRNGhalwapDWgAGR82bUpmn2mA03vII3fvNCG8jAONzKXwpxAg==", + "license": "MIT" + }, + "node_modules/@excalidraw/excalidraw/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/roughjs": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.4.tgz", + "integrity": "sha512-s6EZ0BntezkFYMf/9mGn7M8XGIoaav9QQBCnJROWB3brUWQ683Q2LbRD/hq0Z3bAJ/9NVpU/5LpiTWvQMyLDhw==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/@excalidraw/excalidraw/node_modules/roughjs/node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/@excalidraw/excalidraw/node_modules/sass": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.51.0.tgz", + "integrity": "sha512-haGdpTgywJTvHC2b91GSq+clTKGbtkkZmVAb82jZQN/wTy6qs8DdFm2lhEQbEwrY0QDRgSQ3xDurqM977C3noA==", + "license": "MIT", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@excalidraw/laser-pointer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@excalidraw/laser-pointer/-/laser-pointer-1.3.1.tgz", + "integrity": "sha512-psA1z1N2qeAfsORdXc9JmD2y4CmDwmuMRxnNdJHZexIcPwaNEyIpNcelw+QkL9rz9tosaN9krXuKaRqYpRAR6g==", + "license": "MIT" + }, + "node_modules/@excalidraw/markdown-to-text": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@excalidraw/markdown-to-text/-/markdown-to-text-0.1.2.tgz", + "integrity": "sha512-1nDXBNAojfi3oSFwJswKREkFm5wrSjqay81QlyRv2pkITG/XYB5v+oChENVBQLcxQwX4IUATWvXM5BcaNhPiIg==", + "license": "MIT" + }, + "node_modules/@excalidraw/mermaid-to-excalidraw": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@excalidraw/mermaid-to-excalidraw/-/mermaid-to-excalidraw-2.2.2.tgz", + "integrity": "sha512-5VKQq5CdRocC82vOIUpQ5ufJOVV9FpBTdHGA+ULqazeIVV+cr299877omQCibsdS3Bpitz2fsnTwnIXEmLVDSg==", + "license": "MIT", + "dependencies": { + "@excalidraw/markdown-to-text": "0.1.2", + "@mermaid-js/parser": "^0.6.3", + "mermaid": "^11.12.1", + "nanoid": "4.0.2" + } + }, + "node_modules/@excalidraw/mermaid-to-excalidraw/node_modules/@mermaid-js/parser": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.6.3.tgz", + "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==", + "license": "MIT", + "dependencies": { + "langium": "3.3.1" + } + }, + "node_modules/@excalidraw/mermaid-to-excalidraw/node_modules/nanoid": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", + "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/@excalidraw/random-username": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@excalidraw/random-username/-/random-username-1.1.0.tgz", + "integrity": "sha512-nULYsQxkWHnbmHvcs+efMkJ4/9TtvNyFeLyHdeGxW0zHs6P+jYVqcRff9A6Vq9w9JXeDRnRh2VKvTtS19GW2qA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/@floating-ui/core": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", @@ -7325,6 +7899,416 @@ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "license": "MIT" }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", + "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz", + "integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", + "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz", + "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", + "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-escape-keydown": "1.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", + "integrity": "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz", + "integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz", + "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.6.tgz", + "integrity": "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.5", + "@radix-ui/react-focus-guards": "1.1.1", + "@radix-ui/react-focus-scope": "1.1.2", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-popper": "1.2.2", + "@radix-ui/react-portal": "1.1.4", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-slot": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.1.0", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz", + "integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-callback-ref": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0", + "@radix-ui/react-use-rect": "1.1.0", + "@radix-ui/react-use-size": "1.1.0", + "@radix-ui/rect": "1.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", + "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.0.2", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", + "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", + "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.1.2" + }, + "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" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", + "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", + "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz", + "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", + "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz", + "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz", + "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz", + "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", + "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", + "license": "MIT" + }, "node_modules/@react-dnd/asap": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", @@ -9853,7 +10837,7 @@ "version": "19.1.9", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -11408,6 +12392,18 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -11944,6 +12940,12 @@ "node": ">=8" } }, + "node_modules/browser-fs-access": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.29.1.tgz", + "integrity": "sha512-LSvVX5e21LRrXqVMhqtAwj5xPgDb+fXAIH80NsnCQ9xuZPs2xWsOREi24RKgZa1XOiQRbcmVrv87+ulOKsgjxw==", + "license": "Apache-2.0" + }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", @@ -12335,6 +13337,12 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas-roundrect-polyfill": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/canvas-roundrect-polyfill/-/canvas-roundrect-polyfill-0.0.1.tgz", + "integrity": "sha512-yWq+R3U3jE+coOeEb3a3GgE2j/0MMiDKM/QpLb6h9ihf5fGY9UXtvK9o4vNqjWXoZz7/3EaSVU3IX53TvFFUOw==", + "license": "MIT" + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -12475,6 +13483,44 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chevrotain/node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/chevrotain/node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -13294,6 +14340,15 @@ "buffer": "^5.1.0" } }, + "node_modules/crc-32": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-0.3.0.tgz", + "integrity": "sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -13310,6 +14365,24 @@ "optional": true, "peer": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -14578,6 +15651,12 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "license": "MIT" }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, "node_modules/detect-port": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", @@ -15424,6 +16503,15 @@ "license": "MIT", "optional": true }, + "node_modules/es6-promise-pool": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/es6-promise-pool/-/es6-promise-pool-2.5.0.tgz", + "integrity": "sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -16723,6 +17811,15 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fractional-indexing": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fractional-indexing/-/fractional-indexing-3.2.0.tgz", + "integrity": "sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==", + "license": "CC0-1.0", + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -16795,6 +17892,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuzzy": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", + "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -16850,6 +17955,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -17075,6 +18189,12 @@ "dev": true, "license": "MIT" }, + "node_modules/glur": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/glur/-/glur-1.1.2.tgz", + "integrity": "sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA==", + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -18102,6 +19222,15 @@ "node": ">= 4" } }, + "node_modules/image-blob-reduce": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/image-blob-reduce/-/image-blob-reduce-3.0.1.tgz", + "integrity": "sha512-/VmmWgIryG/wcn4TVrV7cC4mlfUC/oyiKIfSg5eVM3Ten/c1c34RJhMYKCWTnoSMHSqXLt3tsrBR4Q2HInvN+Q==", + "license": "MIT", + "dependencies": { + "pica": "^7.1.0" + } + }, "node_modules/image-size": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", @@ -18867,6 +19996,16 @@ } } }, + "node_modules/jotai-scope": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/jotai-scope/-/jotai-scope-0.7.2.tgz", + "integrity": "sha512-Gwed97f3dDObrO43++2lRcgOqw4O2sdr4JCjP/7eHK1oPACDJ7xKHGScpJX9XaflU+KBHXF+VhwECnzcaQiShg==", + "license": "MIT", + "peerDependencies": { + "jotai": ">=2.9.2", + "react": ">=17.0.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -19029,6 +20168,28 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, + "node_modules/langium": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-3.3.1.tgz", + "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.0.3", + "chevrotain-allstar": "~0.3.0", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.0.8" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/langium/node_modules/vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "license": "MIT" + }, "node_modules/latest-version": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", @@ -19476,6 +20637,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -22779,6 +23946,16 @@ "multicast-dns": "cli.js" } }, + "node_modules/multimath": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/multimath/-/multimath-2.0.0.tgz", + "integrity": "sha512-toRx66cAMJ+Ccz7pMIg38xSIrtnbozk0dchXezwQDMgQmbGpfxjtv68H+L00iFL8hxDaVjrmwAFSb3I6bg8Q2g==", + "license": "MIT", + "dependencies": { + "glur": "^1.1.2", + "object-assign": "^4.1.1" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -23336,6 +24513,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open-color": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/open-color/-/open-color-1.9.1.tgz", + "integrity": "sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw==", + "license": "MIT" + }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -23716,6 +24899,12 @@ "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", "license": "MIT" }, + "node_modules/pako": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.3.tgz", + "integrity": "sha512-WjR1hOeg+kki3ZIOjaf4b5WVcay1jaliKSYiEaB1XzwhMQZJxRdQRv0V31EKBYlxb4T7SK3hjfc/jxyU64BoSw==", + "license": "(MIT AND Zlib)" + }, "node_modules/papaparse": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", @@ -23989,6 +25178,25 @@ "dev": true, "license": "MIT" }, + "node_modules/perfect-freehand": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/perfect-freehand/-/perfect-freehand-1.2.0.tgz", + "integrity": "sha512-h/0ikF1M3phW7CwpZ5MMvKnfpHficWoOEyr//KVNTxV4F6deRK1eYMtHyBKEAKFK0aXIEUK9oBvlF6PNXMDsAw==", + "license": "MIT" + }, + "node_modules/pica": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/pica/-/pica-7.1.1.tgz", + "integrity": "sha512-WY73tMvNzXWEld2LicT9Y260L43isrZ85tPuqRyvtkljSDLmnNFQmZICt4xUJMVulmcc6L9O7jbBrtx3DOz/YQ==", + "license": "MIT", + "dependencies": { + "glur": "^1.1.2", + "inherits": "^2.0.3", + "multimath": "^2.0.0", + "object-assign": "^4.1.1", + "webworkify": "^1.5.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -24147,6 +25355,31 @@ "node": ">=4" } }, + "node_modules/png-chunk-text": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunk-text/-/png-chunk-text-1.0.0.tgz", + "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", + "license": "MIT" + }, + "node_modules/png-chunks-encode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunks-encode/-/png-chunks-encode-1.0.0.tgz", + "integrity": "sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA==", + "license": "MIT", + "dependencies": { + "crc-32": "^0.3.0", + "sliced": "^1.0.1" + } + }, + "node_modules/png-chunks-extract": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", + "integrity": "sha512-ZiVwF5EJ0DNZyzAqld8BP1qyJBaGOFaq9zl579qfbkcmOwWLLO4I9L8i2O4j3HkI6/35i0nKG2n+dZplxiT89Q==", + "license": "MIT", + "dependencies": { + "crc-32": "^0.3.0" + } + }, "node_modules/pngjs": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", @@ -26086,6 +27319,12 @@ "node": ">=16.0.0" } }, + "node_modules/pwacompat": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/pwacompat/-/pwacompat-2.0.17.tgz", + "integrity": "sha512-6Du7IZdIy7cHiv7AhtDy4X2QRM8IAD5DII69mt5qWibC2d15ZU8DmBG1WdZKekG11cChSu4zkSUGPF9sweOl6w==", + "license": "Apache-2.0" + }, "node_modules/qs": { "version": "6.15.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", @@ -26387,6 +27626,53 @@ "react": ">=18" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-resizable-panels": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/react-resizable-panels/-/react-resizable-panels-3.0.6.tgz", @@ -26469,6 +27755,28 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -29244,6 +30552,13 @@ "node": ">=8" } }, + "node_modules/sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==", + "deprecated": "Unsupported", + "license": "MIT" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -31052,6 +32367,15 @@ "node": "*" } }, + "node_modules/tunnel-rat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz", + "integrity": "sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==", + "license": "MIT", + "dependencies": { + "zustand": "^4.3.2" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -31806,6 +33130,27 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-device-pixel-ratio": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-device-pixel-ratio/-/use-device-pixel-ratio-1.1.2.tgz", @@ -31815,6 +33160,28 @@ "react": ">=16.8.0" } }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -32389,6 +33756,18 @@ "node": ">=14.0.0" } }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, "node_modules/vscode-languageserver-protocol": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", @@ -32936,6 +34315,12 @@ "node": ">=0.8.0" } }, + "node_modules/webworkify": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/webworkify/-/webworkify-1.5.0.tgz", + "integrity": "sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==", + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -33375,6 +34760,34 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index be03d9451b..1f5deda212 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ }, "dependencies": { "@ai-sdk/react": "^2.0.104", + "@excalidraw/excalidraw": "^0.18.1", "@floating-ui/react": "^0.27.16", "@observablehq/plot": "^0.6.17", "@react-hook/resize-observer": "^2.0.2", diff --git a/pkg/aiusechat/usechat-prompts.go b/pkg/aiusechat/usechat-prompts.go index 2d479c5246..7aeb845bb6 100644 --- a/pkg/aiusechat/usechat-prompts.go +++ b/pkg/aiusechat/usechat-prompts.go @@ -39,6 +39,14 @@ var SystemPromptText_OpenAI = strings.Join([]string{ `If the user asks you to execute commands or run code, or deal with remote files say that these features aren't available yet AND make sure to say that they are coming soon (stay tuned for updates).`, `Instead, show them exactly what command or code they could copy-paste to run manually.`, + // Excalidraw diagrams + `Wave Terminal has a built-in Excalidraw editor for diagrams. Users can run these wsh commands in the terminal:`, + `"wsh excalidraw" opens a blank canvas, "wsh excalidraw FILE" opens or creates a .excalidraw file,`, + `"wsh excalidraw push BLOCKID" pipes Excalidraw JSON from stdin into an existing block (full scene replacement),`, + `"wsh excalidraw mermaid FILE" converts a Mermaid diagram file to Excalidraw and opens it in a new block,`, + `"wsh excalidraw mermaid BLOCKID FILE" pushes converted Mermaid into an existing block.`, + `When a user asks to create or visualize a diagram, suggest the appropriate wsh excalidraw command.`, + // Final reminder `You have NO API access to widgets or Wave unless provided via an explicit tool.`, }, " ") @@ -76,6 +84,14 @@ var SystemPromptText_NoTools = strings.Join([]string{ `When users ask for code or commands, provide ready-to-use examples they can copy and execute themselves.`, `If they need file modifications, show the exact changes they should make.`, + // Excalidraw diagrams + `Wave Terminal has a built-in Excalidraw editor for diagrams. Users can run these wsh commands in the terminal:`, + `"wsh excalidraw" opens a blank canvas, "wsh excalidraw FILE" opens or creates a .excalidraw file,`, + `"wsh excalidraw push BLOCKID" pipes Excalidraw JSON from stdin into an existing block (full scene replacement),`, + `"wsh excalidraw mermaid FILE" converts a Mermaid diagram file to Excalidraw and opens it in a new block,`, + `"wsh excalidraw mermaid BLOCKID FILE" pushes converted Mermaid into an existing block.`, + `When a user asks to create or visualize a diagram, suggest the appropriate wsh excalidraw command.`, + // Final reminder `You have NO API access to widgets or Wave Terminal internals.`, }, " ") diff --git a/pkg/tsgen/tsgenevent.go b/pkg/tsgen/tsgenevent.go index 6e1c08e981..a14e89be52 100644 --- a/pkg/tsgen/tsgenevent.go +++ b/pkg/tsgen/tsgenevent.go @@ -41,6 +41,7 @@ var WaveEventDataTypes = map[string]reflect.Type{ wps.Event_AIModeConfig: reflect.TypeOf(wconfig.AIModeConfigUpdate{}), wps.Event_BlockJobStatus: reflect.TypeOf(wshrpc.BlockJobStatusData{}), wps.Event_Badge: reflect.TypeOf(baseds.BadgeEvent{}), + wps.Event_ExcalidrawPushScene: reflect.TypeOf(wshrpc.CommandExcalidrawPushData{}), } func getWaveEventDataTSType(eventName string, tsTypesMap map[reflect.Type]string) string { diff --git a/pkg/wps/wpstypes.go b/pkg/wps/wpstypes.go index 0077ec9d5e..4e32946de9 100644 --- a/pkg/wps/wpstypes.go +++ b/pkg/wps/wpstypes.go @@ -34,6 +34,7 @@ const ( Event_AIModeConfig = "waveai:modeconfig" // type: wconfig.AIModeConfigUpdate Event_BlockJobStatus = "block:jobstatus" // type: wshrpc.BlockJobStatusData Event_Badge = "badge" // type: baseds.BadgeEvent + Event_ExcalidrawPushScene = "excalidraw:pushscene" // type: any ) var AllEvents []string = []string{ @@ -56,6 +57,7 @@ var AllEvents []string = []string{ Event_AIModeConfig, Event_BlockJobStatus, Event_Badge, + Event_ExcalidrawPushScene, } type WaveEvent struct { diff --git a/pkg/wshrpc/wshclient/wshclient.go b/pkg/wshrpc/wshclient/wshclient.go index d5333aec2b..4d69afc29f 100644 --- a/pkg/wshrpc/wshclient/wshclient.go +++ b/pkg/wshrpc/wshclient/wshclient.go @@ -293,6 +293,12 @@ func EventUnsubAllCommand(w *wshutil.WshRpc, opts *wshrpc.RpcOpts) error { return err } +// command "excalidrawpush", wshserver.ExcalidrawPushCommand +func ExcalidrawPushCommand(w *wshutil.WshRpc, data wshrpc.CommandExcalidrawPushData, opts *wshrpc.RpcOpts) error { + _, err := sendRpcRequestCallHelper[any](w, "excalidrawpush", data, opts) + return err +} + // command "fetchsuggestions", wshserver.FetchSuggestionsCommand func FetchSuggestionsCommand(w *wshutil.WshRpc, data wshrpc.FetchSuggestionsData, opts *wshrpc.RpcOpts) (*wshrpc.FetchSuggestionsResponse, error) { resp, err := sendRpcRequestCallHelper[*wshrpc.FetchSuggestionsResponse](w, "fetchsuggestions", data, opts) diff --git a/pkg/wshrpc/wshrpctypes.go b/pkg/wshrpc/wshrpctypes.go index 51e2338ba8..0e42dbf80a 100644 --- a/pkg/wshrpc/wshrpctypes.go +++ b/pkg/wshrpc/wshrpctypes.go @@ -97,6 +97,7 @@ type WshRpcInterface interface { UpdateTabNameCommand(ctx context.Context, tabId string, newName string) error UpdateWorkspaceTabIdsCommand(ctx context.Context, workspaceId string, tabIds []string) error GetAllBadgesCommand(ctx context.Context) ([]baseds.BadgeEvent, error) + ExcalidrawPushCommand(ctx context.Context, data CommandExcalidrawPushData) error // connection functions ConnStatusCommand(ctx context.Context) ([]ConnStatus, error) @@ -925,3 +926,9 @@ type CommandRemoteProcessSignalData struct { Pid int32 `json:"pid"` Signal string `json:"signal"` } + +type CommandExcalidrawPushData struct { + BlockId string `json:"blockid"` + SceneData any `json:"scenedata"` + Format string `json:"format,omitempty"` +} diff --git a/pkg/wshrpc/wshserver/wshserver.go b/pkg/wshrpc/wshserver/wshserver.go index 38006fd9a8..caae726b09 100644 --- a/pkg/wshrpc/wshserver/wshserver.go +++ b/pkg/wshrpc/wshserver/wshserver.go @@ -1574,3 +1574,25 @@ func (ws *WshServer) JobControllerDetachJobCommand(ctx context.Context, jobId st func (ws *WshServer) BlockJobStatusCommand(ctx context.Context, blockId string) (*wshrpc.BlockJobStatusData, error) { return jobcontroller.GetBlockJobStatus(ctx, blockId) } + +func (ws *WshServer) ExcalidrawPushCommand(ctx context.Context, data wshrpc.CommandExcalidrawPushData) error { + if data.BlockId == "" { + return fmt.Errorf("blockid is required") + } + if data.SceneData == nil { + return fmt.Errorf("scenedata is required") + } + block, err := wstore.DBMustGet[*waveobj.Block](ctx, data.BlockId) + if err != nil { + return fmt.Errorf("block not found: %w", err) + } + if block.Meta.GetString(waveobj.MetaKey_View, "") != "excalidraw" { + return fmt.Errorf("block %s is not an excalidraw view", data.BlockId) + } + wps.Broker.Publish(wps.WaveEvent{ + Event: wps.Event_ExcalidrawPushScene, + Scopes: []string{waveobj.MakeORef(waveobj.OType_Block, data.BlockId).String()}, + Data: data, + }) + return nil +} diff --git a/postinstall.cjs b/postinstall.cjs index 6748c8232c..d1601d21f9 100644 --- a/postinstall.cjs +++ b/postinstall.cjs @@ -1,3 +1,6 @@ +const fs = require("fs"); +const path = require("path"); + const skip = process.env.WAVETERM_SKIP_APP_DEPS === "1" || process.env.CF_PAGES === "1" || process.env.CF_PAGES === "true"; @@ -6,6 +9,22 @@ if (skip) { process.exit(0); } +function copyExcalidrawAssets() { + const fontsSource = path.join(__dirname, "node_modules/@excalidraw/excalidraw/dist/prod/fonts"); + const fontsDest = path.join(__dirname, "public/excalidraw/fonts"); + + if (!fs.existsSync(fontsSource)) { + console.log("postinstall: @excalidraw/excalidraw not installed, skipping font copy"); + return; + } + + fs.mkdirSync(fontsDest, { recursive: true }); + fs.cpSync(fontsSource, fontsDest, { recursive: true }); + console.log("postinstall: copied excalidraw fonts to public/excalidraw/fonts/"); +} + +copyExcalidrawAssets(); + import("child_process").then(({ execSync }) => { execSync("electron-builder install-app-deps", { stdio: "inherit" }); });