diff --git a/.gitignore b/.gitignore index 2111b1182d..3717b1b796 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ frontend/dist dist/ dist-dev/ +.waveterm-dev/ frontend/node_modules node_modules/ frontend/bindings diff --git a/CLAUDE.md b/CLAUDE.md index ea0daa9425..e25177f547 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,3 +16,19 @@ This project uses a set of "skill" guides — focused how-to documents for commo | electron-api | `.kilocode/skills/electron-api/SKILL.md` | Guide for adding new Electron APIs to Wave Terminal. Use when implementing new frontend-to-electron communications via preload/IPC. | | waveenv | `.kilocode/skills/waveenv/SKILL.md` | Guide for creating WaveEnv narrowings in Wave Terminal. Use when writing a named subset type of WaveEnv for a component tree, documenting environmental dependencies, or enabling mock environments for preview/test server usage. | | wps-events | `.kilocode/skills/wps-events/SKILL.md` | Guide for working with Wave Terminal's WPS (Wave PubSub) event system. Use when implementing new event types, publishing events, subscribing to events, or adding asynchronous communication between components. | + +--- + +## Dev Build & Packaging + +- **App ID & Name**: Changed to `dev.commandline.waveterm.custom` and productName to `Wave Dev` in `package.json` so the dev build appears as a completely separate app to macOS (avoids Electron single-instance lock conflict and Launch Services confusion). +- **Build**: `task package` (requires `PATH="/opt/homebrew/bin:$PATH"` for Go/Task). Builds as `Wave Dev.app` in `make/mac-arm64/`. +- **Launch**: Use `launch_wave_dev.command` or run directly: + ```bash + WAVETERM_HOME=~/.waveterm-dev \ + WAVETERM_CONFIG_HOME=~/.waveterm-dev/config \ + WAVETERM_DATA_HOME=~/.waveterm-dev/data \ + make/mac-arm64/Wave\ Dev.app/Contents/MacOS/Wave\ Dev + ``` + These variables create isolated config and data directories for the dev build. Note: `getWaveHomeDir()` only honors `WAVETERM_HOME` after `wave.lock` exists, so explicit `CONFIG/DATA` overrides are needed for clean installs and newly launched dev instances. +- **Do not modify Info.plist or re-sign** the built app bundle — it breaks code signing on macOS and causes crashes. diff --git a/frontend/app/block/blockframe-header.tsx b/frontend/app/block/blockframe-header.tsx index a70f323e71..9b436ed5df 100644 --- a/frontend/app/block/blockframe-header.tsx +++ b/frontend/app/block/blockframe-header.tsx @@ -21,6 +21,7 @@ import { import { globalStore } from "@/app/store/jotaiStore"; import { uxCloseBlock } from "@/app/store/keymodel"; import { TabRpcClient } from "@/app/store/wshrpcutil"; +import { renamingBlockIdAtom, startBlockRename, stopBlockRename } from "@/app/block/blockrenamestate"; import { useWaveEnv } from "@/app/waveenv/waveenv"; import { IconButton } from "@/element/iconbutton"; import { NodeModel } from "@/layout/index"; @@ -36,12 +37,24 @@ function handleHeaderContextMenu( blockId: string, viewModel: ViewModel, nodeModel: NodeModel, - blockEnv: BlockEnv + blockEnv: BlockEnv, + preview: boolean ) { e.preventDefault(); e.stopPropagation(); const magnified = globalStore.get(nodeModel.isMagnified); - const menu: ContextMenuItem[] = [ + const ephemeral = globalStore.get(nodeModel.isEphemeral); + const useTermHeader = viewModel?.useTermHeader ? globalStore.get(viewModel.useTermHeader) : false; + const menu: ContextMenuItem[] = []; + + if (!ephemeral && !preview && useTermHeader) { + menu.push({ + label: "Rename Block", + click: () => startBlockRename(blockId), + }); + } + + menu.push( { label: magnified ? "Un-Magnify Block" : "Magnify Block", click: () => { @@ -54,8 +67,8 @@ function handleHeaderContextMenu( click: () => { navigator.clipboard.writeText(blockId); }, - }, - ]; + } + ); const extraItems = viewModel?.getSettingsMenuItems?.(); if (extraItems && extraItems.length > 0) menu.push({ type: "separator" }, ...extraItems); menu.push( @@ -78,11 +91,89 @@ type HeaderTextElemsProps = { const HeaderTextElems = React.memo(({ viewModel, blockId, preview, error }: HeaderTextElemsProps) => { const waveEnv = useWaveEnv(); const frameTextAtom = waveEnv.getBlockMetaKeyAtom(blockId, "frame:text"); + const frameTitleAtom = waveEnv.getBlockMetaKeyAtom(blockId, "frame:title"); const frameText = jotai.useAtomValue(frameTextAtom); + const frameTitle = jotai.useAtomValue(frameTitleAtom); + const renamingBlockId = jotai.useAtomValue(renamingBlockIdAtom); + const isRenaming = renamingBlockId === blockId; + const useTermHeader = util.useAtomValueSafe(viewModel?.useTermHeader); let headerTextUnion = util.useAtomValueSafe(viewModel?.viewText); headerTextUnion = frameText ?? headerTextUnion; + const cancelRef = React.useRef(false); + const sessionIdRef = React.useRef(0); + + const saveRename = React.useCallback( + async (newTitle: string, sessionId: number) => { + const val = newTitle.trim() || null; + try { + await waveEnv.rpc.SetMetaCommand(TabRpcClient, { + oref: WOS.makeORef("block", blockId), + meta: { "frame:title": val }, + }); + if (sessionIdRef.current === sessionId) { + stopBlockRename(); + } + } catch (error) { + console.error("Failed to save block rename:", error); + } + }, + [blockId, waveEnv] + ); + + React.useEffect(() => { + if (isRenaming) { + sessionIdRef.current++; + cancelRef.current = false; + } + }, [isRenaming]); + + if (isRenaming) { + return ( +
+ e.currentTarget.select()} + onBlur={(e) => { + if (cancelRef.current) { + cancelRef.current = false; + stopBlockRename(); + return; + } + saveRename(e.currentTarget.value, sessionIdRef.current); + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + cancelRef.current = true; + saveRename(e.currentTarget.value, sessionIdRef.current); + } else if (e.key === "Escape") { + cancelRef.current = true; + stopBlockRename(); + } + }} + onClick={(e) => e.stopPropagation()} + /> +
+ ); + } const headerTextElems: React.ReactElement[] = []; + + // For terminal blocks, show frame:title as a name badge in the text area + if (useTermHeader && frameTitle) { + headerTextElems.push( +
+ {frameTitle} +
+ ); + } + if (typeof headerTextUnion === "string") { if (!util.isBlank(headerTextUnion)) { headerTextElems.push( @@ -116,9 +207,10 @@ type HeaderEndIconsProps = { viewModel: ViewModel; nodeModel: NodeModel; blockId: string; + preview: boolean; }; -const HeaderEndIcons = React.memo(({ viewModel, nodeModel, blockId }: HeaderEndIconsProps) => { +const HeaderEndIcons = React.memo(({ viewModel, nodeModel, blockId, preview }: HeaderEndIconsProps) => { const blockEnv = useWaveEnv(); const endIconButtons = util.useAtomValueSafe(viewModel?.endIconButtons); const magnified = jotai.useAtomValue(nodeModel.isMagnified); @@ -168,7 +260,7 @@ const HeaderEndIcons = React.memo(({ viewModel, nodeModel, blockId }: HeaderEndI elemtype: "iconbutton", icon: "cog", title: "Settings", - click: (e) => handleHeaderContextMenu(e, blockId, viewModel, nodeModel, blockEnv), + click: (e) => handleHeaderContextMenu(e, blockId, viewModel, nodeModel, blockEnv, preview), }; endIconsElem.push(); if (ephemeral) { @@ -251,7 +343,7 @@ const BlockFrame_Header = ({ className={cn("block-frame-default-header", useTermHeader && "!pl-[2px]")} data-role="block-header" ref={dragHandleRef} - onContextMenu={(e) => handleHeaderContextMenu(e, nodeModel.blockId, viewModel, nodeModel, waveEnv)} + onContextMenu={(e) => handleHeaderContextMenu(e, nodeModel.blockId, viewModel, nodeModel, waveEnv, preview)} > {!useTermHeader && ( <> @@ -286,7 +378,7 @@ const BlockFrame_Header = ({ )} - + ); }; diff --git a/frontend/app/block/blockrenamestate.ts b/frontend/app/block/blockrenamestate.ts new file mode 100644 index 0000000000..93fe2c49c9 --- /dev/null +++ b/frontend/app/block/blockrenamestate.ts @@ -0,0 +1,15 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { globalStore } from "@/app/store/jotaiStore"; +import * as jotai from "jotai"; + +export const renamingBlockIdAtom = jotai.atom(null); + +export function startBlockRename(blockId: string) { + globalStore.set(renamingBlockIdAtom, blockId); +} + +export function stopBlockRename() { + globalStore.set(renamingBlockIdAtom, null); +} diff --git a/frontend/app/view/preview/preview-model.tsx b/frontend/app/view/preview/preview-model.tsx index 8315e48b2a..f71c8a4176 100644 --- a/frontend/app/view/preview/preview-model.tsx +++ b/frontend/app/view/preview/preview-model.tsx @@ -170,6 +170,11 @@ export class PreviewModel implements ViewModel { codeEditKeyDownHandler: (waveEvent: WaveKeyboardEvent) => boolean; env: PreviewEnv; + followTermIdAtom: Atom; + followTermCwdAtom: Atom; + followTermBidirAtom: Atom; + followTermMenuDataAtom: PrimitiveAtom<{ pos: { x: number; y: number }; terms: { blockId: string; title: string }[]; currentFollowId: string | null; bidir: boolean } | null>; + constructor({ blockId, nodeModel, tabModel, waveEnv }: ViewModelInitType) { this.viewType = "preview"; this.blockId = blockId; @@ -334,6 +339,7 @@ export class PreviewModel implements ViewModel { const isCeView = loadableSV.state == "hasData" && loadableSV.data.specializedView == "codeedit"; if (mimeType == "directory") { const showHiddenFiles = get(this.showHiddenFiles); + const followTermId = get(this.followTermIdAtom); return [ { elemtype: "iconbutton", @@ -343,6 +349,13 @@ export class PreviewModel implements ViewModel { globalStore.set(this.showHiddenFiles, (prev) => !prev); }, }, + { + elemtype: "iconbutton", + icon: "link", + title: followTermId ? "Following Terminal (click to change or unlink)" : "Follow a Terminal", + iconColor: followTermId ? "var(--success-color)" : undefined, + click: (e: React.MouseEvent) => this.showFollowTermMenu(e), + }, { elemtype: "iconbutton", icon: "arrows-rotate", @@ -489,6 +502,48 @@ export class PreviewModel implements ViewModel { }); this.noPadding = atom(true); + this.followTermIdAtom = atom((get) => { + return (get(this.blockAtom)?.meta?.["preview:followtermid"] as string) ?? null; + }); + this.followTermCwdAtom = atom((get) => { + const termId = get(this.followTermIdAtom); + if (!termId) return null; + const termBlock = WOS.getObjectValue(WOS.makeORef("block", termId), get); + return (termBlock?.meta?.["cmd:cwd"] as string) ?? null; + }); + this.followTermBidirAtom = atom((get) => { + return (get(this.blockAtom)?.meta?.["preview:followterm:bidir"] as boolean) ?? false; + }); + this.followTermMenuDataAtom = atom(null) as PrimitiveAtom<{ pos: { x: number; y: number }; terms: { blockId: string; title: string }[]; currentFollowId: string | null; bidir: boolean } | null>; + } + + showFollowTermMenu(e: React.MouseEvent) { + const tabData = globalStore.get(this.tabModel.tabAtom); + const blockIds = tabData?.blockids ?? []; + + const terms: { blockId: string; title: string }[] = []; + let termIndex = 1; + for (const bid of blockIds) { + if (bid === this.blockId) continue; + const block = WOS.getObjectValue(WOS.makeORef("block", bid), globalStore.get); + if (block?.meta?.view === "term") { + terms.push({ + blockId: bid, + title: (block?.meta?.["frame:title"] as string) || `Terminal ${termIndex}`, + }); + termIndex++; + } + } + + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + const currentFollowId = globalStore.get(this.followTermIdAtom); + const bidir = globalStore.get(this.followTermBidirAtom); + globalStore.set(this.followTermMenuDataAtom, { + pos: { x: rect.left, y: rect.bottom + 4 }, + terms, + currentFollowId, + bidir, + }); } markdownShowTocToggle() { @@ -577,7 +632,7 @@ export class PreviewModel implements ViewModel { this.updateOpenFileModalAndError(!modalOpen); } - async goHistory(newPath: string) { + async goHistory(newPath: string): Promise { let fileName = globalStore.get(this.metaFilePath); if (fileName == null) { fileName = ""; @@ -585,7 +640,7 @@ export class PreviewModel implements ViewModel { const blockMeta = globalStore.get(this.blockAtom)?.meta; const updateMeta = goHistory("file", fileName, newPath, blockMeta); if (updateMeta == null) { - return; + return false; } const blockOref = WOS.makeORef("block", this.blockId); await this.env.services.object.UpdateObjectMeta(blockOref, updateMeta); @@ -593,6 +648,7 @@ export class PreviewModel implements ViewModel { // Clear the saved file buffers globalStore.set(this.fileContentSaved, null); globalStore.set(this.newFileContent, null); + return true; } async goParentDirectory({ fileInfo = null }: { fileInfo?: FileInfo | null }) { diff --git a/frontend/app/view/preview/preview.test.ts b/frontend/app/view/preview/preview.test.ts new file mode 100644 index 0000000000..14065dcfed --- /dev/null +++ b/frontend/app/view/preview/preview.test.ts @@ -0,0 +1,128 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from "vitest"; +import { buildCdCommand, cmdEscapePath, posixEscapePath, pwshEscapePath } from "./shellescape"; + +describe("posixEscapePath", () => { + it("handles tilde-only path", () => { + expect(posixEscapePath("~")).toBe("~"); + }); + + it("handles tilde-prefixed path", () => { + expect(posixEscapePath("~/Documents")).toBe("~/'Documents'"); + }); + + it("handles tilde-prefixed path with single quotes", () => { + expect(posixEscapePath("~/Documents/Bob's Files")).toBe("~/'Documents/Bob'\\''s Files'"); + }); + + it("handles plain path", () => { + expect(posixEscapePath("/usr/local/bin")).toBe("'/usr/local/bin'"); + }); + + it("handles path with spaces", () => { + expect(posixEscapePath("/path/with spaces")).toBe("'/path/with spaces'"); + }); + + it("handles path with single quotes", () => { + expect(posixEscapePath("/path/with'quotes")).toBe("'/path/with'\\''quotes'"); + }); + + it("handles path with multiple single quotes", () => { + expect(posixEscapePath("/a'b'c")).toBe("'/a'\\''b'\\''c'"); + }); + + it("handles path with backticks", () => { + expect(posixEscapePath("/path/with`backtick")).toBe("'/path/with`backtick'"); + }); + + it("handles path with semicolons", () => { + expect(posixEscapePath("/path;with;semicolons")).toBe("'/path;with;semicolons'"); + }); + + it("handles empty string", () => { + expect(posixEscapePath("")).toBe("''"); + }); +}); + +describe("pwshEscapePath", () => { + it("handles plain path", () => { + expect(pwshEscapePath("C:\\Users\\Bob")).toBe("'C:\\Users\\Bob'"); + }); + + it("handles path with single quotes", () => { + expect(pwshEscapePath("C:\\Bob's Files")).toBe("'C:\\Bob''s Files'"); + }); + + it("handles path with multiple single quotes", () => { + expect(pwshEscapePath("C:\\a'b'c")).toBe("'C:\\a''b''c'"); + }); + + it("handles path with spaces", () => { + expect(pwshEscapePath("C:\\Program Files")).toBe("'C:\\Program Files'"); + }); + + it("handles empty string", () => { + expect(pwshEscapePath("")).toBe("''"); + }); +}); + +describe("cmdEscapePath", () => { + it("handles plain path", () => { + expect(cmdEscapePath("C:\\Users\\Bob")).toBe('"C:\\Users\\Bob"'); + }); + + it("handles path with double quotes", () => { + expect(cmdEscapePath('C:\\Bob"s Files')).toBe('"C:\\Bob""s Files"'); + }); + + it("handles path with spaces", () => { + expect(cmdEscapePath("C:\\Program Files")).toBe('"C:\\Program Files"'); + }); + + it("handles path with percent signs in cmd.exe", () => { + expect(cmdEscapePath("C:\\100%complete")).toBe('"C:\\100%%complete"'); + }); + + it("handles empty string", () => { + expect(cmdEscapePath("")).toBe('""'); + }); +}); + +describe("buildCdCommand", () => { + it("builds POSIX cd command with Ctrl-U prefix", () => { + const cmd = buildCdCommand("bash", "/home/user"); + expect(cmd).toBe("\x15cd '/home/user'\r"); + }); + + it("builds PowerShell Set-Location with Escape prefix", () => { + const cmd = buildCdCommand("pwsh", "C:\\Users\\Bob"); + expect(cmd).toBe("\x1bSet-Location -LiteralPath 'C:\\Users\\Bob'\r"); + }); + + it("builds cmd.exe cd command with Escape prefix", () => { + const cmd = buildCdCommand("cmd", "C:\\Users\\Bob"); + expect(cmd).toBe("\x1bcd /d \"C:\\Users\\Bob\"\r"); + }); + + it("handles path with single quotes in POSIX", () => { + const cmd = buildCdCommand("zsh", "/path/Bob's Files"); + expect(cmd).toBe("\x15cd '/path/Bob'\\''s Files'\r"); + }); + + it("handles path with single quotes in PowerShell", () => { + const cmd = buildCdCommand("powershell", "C:\\Bob's Files"); + expect(cmd).toBe("\x1bSet-Location -LiteralPath 'C:\\Bob''s Files'\r"); + }); + + it("defaults to POSIX for unknown shell types", () => { + const cmd = buildCdCommand("fish", "/home/user"); + expect(cmd).toBe("\x15cd '/home/user'\r"); + }); + + it("handles tilde expansion in POSIX shells", () => { + const cmd = buildCdCommand("bash", "~"); + expect(cmd).toBe("\x15cd ~\r"); + }); +}); diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx index 87cf44678a..6205897d59 100644 --- a/frontend/app/view/preview/preview.tsx +++ b/frontend/app/view/preview/preview.tsx @@ -3,12 +3,16 @@ import { CenteredDiv } from "@/app/element/quickelems"; import { globalStore } from "@/app/store/jotaiStore"; +import { RpcApi } from "@/app/store/wshclientapi"; import { TabRpcClient } from "@/app/store/wshrpcutil"; import { BlockHeaderSuggestionControl } from "@/app/suggestion/suggestion"; import { useWaveEnv } from "@/app/waveenv/waveenv"; -import { isBlank, makeConnRoute } from "@/util/util"; +import { BlockModel } from "@/app/block/block-model"; +import * as WOS from "@/store/wos"; +import { fireAndForget, isBlank, makeConnRoute, stringToBase64 } from "@/util/util"; import { useAtom, useAtomValue, useSetAtom } from "jotai"; -import { memo, useEffect } from "react"; +import React, { memo, useEffect, useRef } from "react"; +import ReactDOM from "react-dom"; import { CSVView } from "./csvview"; import { DirectoryPreview } from "./preview-directory"; import { CodeEditPreview } from "./preview-edit"; @@ -17,6 +21,25 @@ import { MarkdownPreview } from "./preview-markdown"; import type { PreviewModel } from "./preview-model"; import { StreamingPreview } from "./preview-streaming"; import type { PreviewEnv } from "./previewenv"; +import { buildCdCommand } from "./shellescape"; + +async function sendCdToTerminal(termBlockId: string, path: string) { + const block = WOS.getObjectValue(WOS.makeORef("block", termBlockId), globalStore.get); + if (block?.meta?.view !== "term") { + return; + } + let shellType = ""; + try { + const rtInfo = await RpcApi.GetRTInfoCommand(TabRpcClient, { + oref: WOS.makeORef("block", termBlockId), + }); + shellType = rtInfo?.["shell:type"] ?? ""; + } catch { + // fall through with empty shellType, defaults to POSIX + } + const command = buildCdCommand(shellType, path); + await RpcApi.ControllerInputCommand(TabRpcClient, { blockid: termBlockId, inputdata64: stringToBase64(command) }); +} export type SpecializedViewProps = { model: PreviewModel; @@ -96,6 +119,171 @@ const fetchSuggestions = async ( }); }; +function FollowTermDropdown({ model }: { model: PreviewModel }) { + const menuData = useAtomValue(model.followTermMenuDataAtom); + const menuRef = useRef(null); + const previousActiveElement = useRef(null); + + const restoreFocus = React.useCallback(() => { + if (previousActiveElement.current instanceof HTMLElement) { + previousActiveElement.current.focus(); + } + previousActiveElement.current = null; + }, []); + + const closeMenu = React.useCallback(() => { + BlockModel.getInstance().setBlockHighlight(null); + globalStore.set(model.followTermMenuDataAtom, null); + restoreFocus(); + }, [model.followTermMenuDataAtom, restoreFocus]); + + useEffect(() => { + if (!menuData) return; + if (previousActiveElement.current === null) { + previousActiveElement.current = document.activeElement; + } + const handleEscape = (e: KeyboardEvent) => { + if (e.key === "Escape") { + closeMenu(); + } + }; + document.addEventListener("keydown", handleEscape); + if (menuRef.current) { + const firstItem = menuRef.current.querySelector('[role="menuitem"]'); + if (firstItem instanceof HTMLElement) { + firstItem.focus(); + } + } + return () => { + document.removeEventListener("keydown", handleEscape); + }; + }, [menuData, closeMenu]); + + if (!menuData) return null; + + const { pos, terms, currentFollowId, bidir } = menuData; + const linkTerm = (blockId: string) => { + fireAndForget(async () => { + const updates: Record = { "preview:followtermid": blockId }; + if (blockId !== currentFollowId) { + updates["preview:followterm:bidir"] = false; + } + await model.env.services.object.UpdateObjectMeta(WOS.makeORef("block", model.blockId), updates); + closeMenu(); + }); + }; + const toggleBidir = () => { + fireAndForget(async () => { + await model.env.services.object.UpdateObjectMeta(WOS.makeORef("block", model.blockId), { + "preview:followterm:bidir": !bidir, + }); + }); + globalStore.set(model.followTermMenuDataAtom, { ...menuData, bidir: !bidir }); + }; + const unlink = () => { + fireAndForget(async () => { + await model.env.services.object.UpdateObjectMeta(WOS.makeORef("block", model.blockId), { + "preview:followtermid": null, + "preview:followterm:bidir": null, + }); + closeMenu(); + }); + }; + + const dropdownStyle: React.CSSProperties = { + left: pos.x, + top: pos.y, + background: "var(--modal-bg-color)", + border: "1px solid var(--border-color)", + boxShadow: "0px 8px 24px 0px rgba(0,0,0,0.4)", + borderRadius: "var(--modal-border-radius)", + }; + const dividerStyle: React.CSSProperties = { borderTop: "1px solid var(--border-color)" }; + + return ReactDOM.createPortal( + <> +
+
+ {terms.length === 0 ? ( +
No terminals on this tab
+ ) : ( + terms.map(({ blockId, title }) => ( +
+ BlockModel.getInstance().setBlockHighlight({ blockId, icon: "terminal" }) + } + onMouseLeave={() => BlockModel.getInstance().setBlockHighlight(null)} + onMouseDown={(e) => e.stopPropagation()} + onClick={() => linkTerm(blockId)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + linkTerm(blockId); + } + }} + > + + {title} +
+ )) + )} + {currentFollowId && ( + <> +
+
e.stopPropagation()} + onClick={toggleBidir} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + toggleBidir(); + } + }} + > + + Bidirectional +
+
+
e.stopPropagation()} + onClick={unlink} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + unlink(); + } + }} + > + Stop Following +
+ + )} +
+ , + document.body + ); +} + function PreviewView({ blockRef, contentRef, @@ -111,6 +299,11 @@ function PreviewView({ const [errorMsg, setErrorMsg] = useAtom(model.errorMsgAtom); const connection = useAtomValue(model.connectionImmediate); const fileInfo = useAtomValue(model.statFile); + const followTermId = useAtomValue(model.followTermIdAtom); + const followTermCwd = useAtomValue(model.followTermCwdAtom); + const followTermBidir = useAtomValue(model.followTermBidirAtom); + const loadableFileInfo = useAtomValue(model.loadableFileInfo); + const suppressBidirRef = useRef(false); useEffect(() => { console.log("fileInfo or connection changed", fileInfo, connection); @@ -120,6 +313,40 @@ function PreviewView({ setErrorMsg(null); }, [connection, fileInfo]); + useEffect(() => { + if (!followTermId || !followTermCwd) return; + const currentPath = globalStore.get(model.metaFilePath) ?? ""; + if (followTermCwd !== currentPath) { + fireAndForget(async () => { + const updated = await model.goHistory(followTermCwd); + if (updated) { + suppressBidirRef.current = true; + setTimeout(() => { + suppressBidirRef.current = false; + }, 400); + } + }); + } + }, [followTermCwd, followTermId, model]); + + useEffect(() => { + if (!followTermBidir) { + suppressBidirRef.current = false; + } + }, [followTermBidir]); + + useEffect(() => { + if (!followTermId || !followTermBidir) return; + if (suppressBidirRef.current) { + suppressBidirRef.current = false; + return; + } + if (loadableFileInfo.state !== "hasData") return; + const fi = loadableFileInfo.data; + if (!fi || fi.mimetype !== "directory" || !fi.path) return; + fireAndForget(() => sendCdToTerminal(followTermId, fi.path)); + }, [loadableFileInfo, followTermId, followTermBidir]); + if (connStatus?.status != "connected") { return null; } @@ -148,6 +375,7 @@ function PreviewView({ return ( <> +
{errorMsg && setErrorMsg(null)} />}
diff --git a/frontend/app/view/preview/shellescape.ts b/frontend/app/view/preview/shellescape.ts new file mode 100644 index 0000000000..e5a12f625c --- /dev/null +++ b/frontend/app/view/preview/shellescape.ts @@ -0,0 +1,29 @@ +// Copyright 2026, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +export function posixEscapePath(path: string): string { + if (path === "~") return "~"; + if (path.startsWith("~/")) { + return "~/" + "'" + path.slice(2).replace(/'/g, "'\\''") + "'"; + } + return "'" + path.replace(/'/g, "'\\''") + "'"; +} + +export function pwshEscapePath(path: string): string { + return "'" + path.replace(/'/g, "''") + "'"; +} + +export function cmdEscapePath(path: string): string { + return '"' + path.replace(/%/g, "%%").replace(/"/g, '""') + '"'; +} + +export function buildCdCommand(shellType: string, path: string): string { + const normalizedShellType = (shellType || "").toLowerCase(); + if (normalizedShellType === "pwsh" || normalizedShellType === "powershell") { + return "\x1bSet-Location -LiteralPath " + pwshEscapePath(path) + "\r"; + } + if (normalizedShellType === "cmd") { + return "\x1bcd /d " + cmdEscapePath(path) + "\r"; + } + return "\x15cd " + posixEscapePath(path) + "\r"; +} diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index c5b870d7ed..87a8d4efbc 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -1196,6 +1196,8 @@ declare global { "web:useragenttype"?: string; "markdown:fontsize"?: number; "markdown:fixedfontsize"?: number; + "preview:followtermid"?: string; + "preview:followterm:bidir"?: boolean; "tsunami:*"?: boolean; "tsunami:sdkreplacepath"?: string; "tsunami:apppath"?: string; diff --git a/launch_wave_dev.command b/launch_wave_dev.command new file mode 100755 index 0000000000..dd3d1b0af9 --- /dev/null +++ b/launch_wave_dev.command @@ -0,0 +1,9 @@ +#!/bin/bash +# Launch Wave (dev build) with a separate data directory +# Double-click this file in Finder to launch, or run from terminal. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WAVETERM_HOME="$SCRIPT_DIR/.waveterm-dev" +WAVETERM_CONFIG_HOME="$WAVETERM_HOME/config" +WAVETERM_DATA_HOME="$WAVETERM_HOME/data" +export WAVETERM_HOME WAVETERM_CONFIG_HOME WAVETERM_DATA_HOME +exec "$SCRIPT_DIR/make/mac-arm64/Wave Dev.app/Contents/MacOS/Wave Dev" diff --git a/package-lock.json b/package-lock.json index b219e6cc92..f3a4a0502e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -178,6 +178,7 @@ "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -198,6 +199,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -457,6 +459,7 @@ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.37.0.tgz", "integrity": "sha512-DAFVUvEg+u7jUs6BZiVz9zdaUebYULPiQ4LM2R4n8Nujzyj7BZzGr2DCd85ip4p/cx7nAZWKM8pLcGtkTRTdsg==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/client-common": "5.37.0", "@algolia/requester-browser-xhr": "5.37.0", @@ -610,6 +613,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2468,6 +2472,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -2490,6 +2495,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2599,6 +2605,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3020,6 +3027,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -4071,6 +4079,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", "license": "MIT", + "peer": true, "dependencies": { "@docusaurus/core": "3.9.2", "@docusaurus/logger": "3.9.2", @@ -4833,7 +4842,6 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, - "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -4848,18 +4856,6 @@ "node": ">=14.14" } }, - "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -5576,468 +5572,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", - "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", - "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", - "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", - "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", - "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", - "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", - "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", - "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", - "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", - "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", - "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", - "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", - "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", - "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.0" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", - "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", - "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", - "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.0" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", - "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/runtime": "^1.4.4" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", - "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", - "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", - "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -6407,6 +5941,7 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -8248,6 +7783,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -8642,7 +8178,8 @@ "version": "0.0.7", "resolved": "https://registry.npmjs.org/@table-nav/core/-/core-0.0.7.tgz", "integrity": "sha512-pCh18jHDRe3tw9sJZXfKi4cSD6VjHbn40CYdqhp5X91SIX7rakDEQAsTx6F7Fv9TUv265l+5rUDcYNaJ0N0cqQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@table-nav/react": { "version": "0.0.7", @@ -9664,6 +9201,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.2.tgz", "integrity": "sha512-lif9hF9afNk39jMUVYk5eyYEojLZQqaYX61LfuwUJJ1+qiQbh7jVaZXskYgzyjAIFDFQRf5Sd6MVM7EyXkfiRw==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -9739,6 +9277,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -10020,6 +9559,7 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -10714,6 +10254,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -10809,6 +10350,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -10873,6 +10415,7 @@ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.37.0.tgz", "integrity": "sha512-y7gau/ZOQDqoInTQp0IwTOjkrHc4Aq4R8JgpmCleFwiLl+PbN2DMWoDUWZnrK8AhNJwT++dn28Bt4NZYNLAmuA==", "license": "MIT", + "peer": true, "dependencies": { "@algolia/abtesting": "1.3.0", "@algolia/client-abtesting": "5.37.0", @@ -11829,6 +11372,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -12337,6 +11881,7 @@ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.1.tgz", "integrity": "sha512-f0yv5CPKaFxfsPTBzX7vGuim4oIC1/gcS7LUGdBSwl2dU6+FON6LVUksdOo1qJjoUvXNn45urgh8C+0a24pACQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.1.1", "@chevrotain/gast": "11.1.1", @@ -13196,8 +12741,7 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -13365,6 +12909,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -13695,6 +13240,7 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10" } @@ -14104,6 +13650,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -14549,6 +14096,7 @@ "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "26.8.1", "builder-util": "26.8.1", @@ -15054,7 +14602,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -15075,7 +14622,6 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -15091,7 +14637,6 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -15102,7 +14647,6 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 4.0.0" } @@ -15432,6 +14976,7 @@ "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -20284,6 +19829,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -22598,7 +22144,6 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -23407,7 +22952,8 @@ "version": "2.14.0", "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.14.0.tgz", "integrity": "sha512-RjV0pqc79kYhQLC3vTcLRb5GLpI1n6qh0Oua3g+bGH4EgNOJHVBGP7u0zZtxoAa0dkHlAqTTSYRb9MMmxNLjig==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/overlayscrollbars-react": { "version": "0.5.6", @@ -24187,6 +23733,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -25090,6 +24637,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -25689,7 +25237,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -25707,7 +25254,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -25808,6 +25354,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -25959,6 +25506,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -26186,6 +25734,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -26234,6 +25783,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -26307,6 +25857,7 @@ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/react": "*" }, @@ -26372,6 +25923,7 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -28120,7 +27672,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -28135,7 +27686,6 @@ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -28157,7 +27707,6 @@ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -28196,6 +27745,7 @@ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -28365,6 +27915,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -28483,6 +28034,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -28874,61 +28426,6 @@ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", "license": "MIT" }, - "node_modules/sharp": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", - "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.4", - "semver": "^7.7.2" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.3", - "@img/sharp-darwin-x64": "0.34.3", - "@img/sharp-libvips-darwin-arm64": "1.2.0", - "@img/sharp-libvips-darwin-x64": "1.2.0", - "@img/sharp-libvips-linux-arm": "1.2.0", - "@img/sharp-libvips-linux-arm64": "1.2.0", - "@img/sharp-libvips-linux-ppc64": "1.2.0", - "@img/sharp-libvips-linux-s390x": "1.2.0", - "@img/sharp-libvips-linux-x64": "1.2.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", - "@img/sharp-libvips-linuxmusl-x64": "1.2.0", - "@img/sharp-linux-arm": "0.34.3", - "@img/sharp-linux-arm64": "0.34.3", - "@img/sharp-linux-ppc64": "0.34.3", - "@img/sharp-linux-s390x": "0.34.3", - "@img/sharp-linux-x64": "0.34.3", - "@img/sharp-linuxmusl-arm64": "0.34.3", - "@img/sharp-linuxmusl-x64": "0.34.3", - "@img/sharp-wasm32": "0.34.3", - "@img/sharp-win32-arm64": "0.34.3", - "@img/sharp-win32-ia32": "0.34.3", - "@img/sharp-win32-x64": "0.34.3" - } - }, - "node_modules/sharp/node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -29812,7 +29309,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", @@ -29840,7 +29336,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=16" } @@ -29968,7 +29463,6 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -30487,7 +29981,8 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/tsunami-frontend": { "resolved": "tsunami/frontend", @@ -31068,6 +30563,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -31166,6 +30662,7 @@ "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", + "peer": true, "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -32048,6 +31545,7 @@ "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -32208,6 +31706,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -32450,6 +31949,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz", "integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -33478,6 +32978,7 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -33527,7 +33028,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "tsunami/frontend/node_modules/redux-thunk": { "version": "3.1.0", diff --git a/package.json b/package.json index 781a6a45fe..134e8f9d70 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "name": "Command Line Inc", "email": "info@commandline.dev" }, - "productName": "Wave", + "productName": "Wave Dev", "description": "Open-Source AI-Native Terminal Built for Seamless Workflows", "license": "Apache-2.0", "version": "0.14.5", "homepage": "https://waveterm.dev", "build": { - "appId": "dev.commandline.waveterm" + "appId": "dev.commandline.waveterm.custom" }, "private": true, "main": "./dist/main/index.js", diff --git a/pkg/waveobj/metaconsts.go b/pkg/waveobj/metaconsts.go index 0ce08099d8..599b5685e2 100644 --- a/pkg/waveobj/metaconsts.go +++ b/pkg/waveobj/metaconsts.go @@ -138,6 +138,9 @@ const ( MetaKey_MarkdownFontSize = "markdown:fontsize" MetaKey_MarkdownFixedFontSize = "markdown:fixedfontsize" + MetaKey_PreviewFollowTermId = "preview:followtermid" + MetaKey_PreviewFollowTermBidir = "preview:followterm:bidir" + MetaKey_TsunamiClear = "tsunami:*" MetaKey_TsunamiSdkReplacePath = "tsunami:sdkreplacepath" MetaKey_TsunamiAppPath = "tsunami:apppath" diff --git a/pkg/waveobj/wtypemeta.go b/pkg/waveobj/wtypemeta.go index 2280b55d2d..566d8b2655 100644 --- a/pkg/waveobj/wtypemeta.go +++ b/pkg/waveobj/wtypemeta.go @@ -142,6 +142,9 @@ type MetaTSType struct { MarkdownFontSize float64 `json:"markdown:fontsize,omitempty"` MarkdownFixedFontSize float64 `json:"markdown:fixedfontsize,omitempty"` + PreviewFollowTermId string `json:"preview:followtermid,omitempty"` + PreviewFollowTermBidir *bool `json:"preview:followterm:bidir,omitempty"` + TsunamiClear bool `json:"tsunami:*,omitempty"` TsunamiSdkReplacePath string `json:"tsunami:sdkreplacepath,omitempty"` TsunamiAppPath string `json:"tsunami:apppath,omitempty"`