diff --git a/frontend/app/asset/claude-color.svg b/frontend/app/asset/claude-color.svg
new file mode 100644
index 0000000000..b70e167740
--- /dev/null
+++ b/frontend/app/asset/claude-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/app/view/term/osc-handlers.test.ts b/frontend/app/view/term/osc-handlers.test.ts
new file mode 100644
index 0000000000..11e6ed387c
--- /dev/null
+++ b/frontend/app/view/term/osc-handlers.test.ts
@@ -0,0 +1,22 @@
+import { describe, expect, it } from "vitest";
+
+import { isClaudeCodeCommand } from "./osc-handlers";
+
+describe("isClaudeCodeCommand", () => {
+ it("matches direct Claude Code invocations", () => {
+ expect(isClaudeCodeCommand("claude")).toBe(true);
+ expect(isClaudeCodeCommand("claude --dangerously-skip-permissions")).toBe(true);
+ expect(isClaudeCodeCommand("/usr/local/bin/claude chat")).toBe(true);
+ });
+
+ it("matches Claude Code invocations wrapped with env assignments", () => {
+ expect(isClaudeCodeCommand('ANTHROPIC_API_KEY="test" claude')).toBe(true);
+ expect(isClaudeCodeCommand("FOO=bar env claude --print")).toBe(true);
+ });
+
+ it("ignores other commands", () => {
+ expect(isClaudeCodeCommand("claudes")).toBe(false);
+ expect(isClaudeCodeCommand("echo claude")).toBe(false);
+ expect(isClaudeCodeCommand("")).toBe(false);
+ });
+});
diff --git a/frontend/app/view/term/osc-handlers.ts b/frontend/app/view/term/osc-handlers.ts
index f44659d2c6..e4c067728d 100644
--- a/frontend/app/view/term/osc-handlers.ts
+++ b/frontend/app/view/term/osc-handlers.ts
@@ -25,6 +25,8 @@ const Osc52MaxRawLength = 128 * 1024; // includes selector + base64 + whitespace
// See aiprompts/wave-osc-16162.md for full documentation
export type ShellIntegrationStatus = "ready" | "running-command";
+const ClaudeCodeRegex = /(?:^|\/)claude\b/;
+
type Osc16162Command =
| { command: "A"; data: Record }
| { command: "C"; data: { cmd64?: string } }
@@ -43,41 +45,56 @@ type Osc16162Command =
| { command: "I"; data: { inputempty?: boolean } }
| { command: "R"; data: Record };
+function normalizeCmd(decodedCmd: string): string {
+ let normalizedCmd = decodedCmd.trim();
+ normalizedCmd = normalizedCmd.replace(/^(?:\w+=(?:"[^"]*"|'[^']*'|\S+)\s+)*/, "");
+ normalizedCmd = normalizedCmd.replace(/^env\s+/, "");
+ return normalizedCmd;
+}
+
function checkCommandForTelemetry(decodedCmd: string) {
if (!decodedCmd) {
return;
}
- if (decodedCmd.startsWith("ssh ")) {
+ const normalizedCmd = normalizeCmd(decodedCmd);
+
+ if (normalizedCmd.startsWith("ssh ")) {
recordTEvent("conn:connect", { "conn:conntype": "ssh-manual" });
return;
}
const editorsRegex = /^(vim|vi|nano|nvim)\b/;
- if (editorsRegex.test(decodedCmd)) {
+ if (editorsRegex.test(normalizedCmd)) {
recordTEvent("action:term", { "action:type": "cli-edit" });
return;
}
const tailFollowRegex = /(^|\|\s*)tail\s+-[fF]\b/;
- if (tailFollowRegex.test(decodedCmd)) {
+ if (tailFollowRegex.test(normalizedCmd)) {
recordTEvent("action:term", { "action:type": "cli-tailf" });
return;
}
- const claudeRegex = /^claude\b/;
- if (claudeRegex.test(decodedCmd)) {
+ if (ClaudeCodeRegex.test(normalizedCmd)) {
recordTEvent("action:term", { "action:type": "claude" });
return;
}
const opencodeRegex = /^opencode\b/;
- if (opencodeRegex.test(decodedCmd)) {
+ if (opencodeRegex.test(normalizedCmd)) {
recordTEvent("action:term", { "action:type": "opencode" });
return;
}
}
+export function isClaudeCodeCommand(decodedCmd: string): boolean {
+ if (!decodedCmd) {
+ return false;
+ }
+ return ClaudeCodeRegex.test(normalizeCmd(decodedCmd));
+}
+
function handleShellIntegrationCommandStart(
termWrap: TermWrap,
blockId: string,
@@ -101,16 +118,20 @@ function handleShellIntegrationCommandStart(
const decodedCmd = base64ToString(cmd.data.cmd64);
rtInfo["shell:lastcmd"] = decodedCmd;
globalStore.set(termWrap.lastCommandAtom, decodedCmd);
+ const isCC = isClaudeCodeCommand(decodedCmd);
+ globalStore.set(termWrap.claudeCodeActiveAtom, isCC);
checkCommandForTelemetry(decodedCmd);
} catch (e) {
console.error("Error decoding cmd64:", e);
rtInfo["shell:lastcmd"] = null;
globalStore.set(termWrap.lastCommandAtom, null);
+ globalStore.set(termWrap.claudeCodeActiveAtom, false);
}
}
} else {
rtInfo["shell:lastcmd"] = null;
globalStore.set(termWrap.lastCommandAtom, null);
+ globalStore.set(termWrap.claudeCodeActiveAtom, false);
}
rtInfo["shell:lastcmdexitcode"] = null;
}
@@ -287,6 +308,7 @@ export function handleOsc16162Command(data: string, blockId: string, loaded: boo
case "A": {
rtInfo["shell:state"] = "ready";
globalStore.set(termWrap.shellIntegrationStatusAtom, "ready");
+ globalStore.set(termWrap.claudeCodeActiveAtom, false);
const marker = terminal.registerMarker(0);
if (marker) {
termWrap.promptMarkers.push(marker);
@@ -324,6 +346,7 @@ export function handleOsc16162Command(data: string, blockId: string, loaded: boo
}
break;
case "D":
+ globalStore.set(termWrap.claudeCodeActiveAtom, false);
if (cmd.data.exitcode != null) {
rtInfo["shell:lastcmdexitcode"] = cmd.data.exitcode;
} else {
@@ -337,6 +360,7 @@ export function handleOsc16162Command(data: string, blockId: string, loaded: boo
break;
case "R":
globalStore.set(termWrap.shellIntegrationStatusAtom, null);
+ globalStore.set(termWrap.claudeCodeActiveAtom, false);
if (terminal.buffer.active.type === "alternate") {
terminal.write("\x1b[?1049l");
}
diff --git a/frontend/app/view/term/term-model.ts b/frontend/app/view/term/term-model.ts
index 9cb1c58720..8507394535 100644
--- a/frontend/app/view/term/term-model.ts
+++ b/frontend/app/view/term/term-model.ts
@@ -10,7 +10,7 @@ import { waveEventSubscribeSingle } from "@/app/store/wps";
import { RpcApi } from "@/app/store/wshclientapi";
import { makeFeBlockRouteId } from "@/app/store/wshrouter";
import { DefaultRouter, TabRpcClient } from "@/app/store/wshrpcutil";
-import { TerminalView } from "@/app/view/term/term";
+import { TermClaudeIcon, TerminalView } from "@/app/view/term/term";
import { TermWshClient } from "@/app/view/term/term-wsh";
import { VDomModel } from "@/app/view/vdom/vdom-model";
import { WorkspaceLayoutModel } from "@/app/workspace/workspace-layout-model";
@@ -155,7 +155,7 @@ export class TermViewModel implements ViewModel {
if (isCmd) {
const blockMeta = get(this.blockAtom)?.meta;
let cmdText = blockMeta?.["cmd"];
- let cmdArgs = blockMeta?.["cmd:args"];
+ const cmdArgs = blockMeta?.["cmd:args"];
if (cmdArgs != null && Array.isArray(cmdArgs) && cmdArgs.length > 0) {
cmdText += " " + cmdArgs.join(" ");
}
@@ -242,7 +242,7 @@ export class TermViewModel implements ViewModel {
});
this.termTransparencyAtom = useBlockAtom(blockId, "termtransparencyatom", () => {
return jotai.atom((get) => {
- let value = get(getOverrideConfigAtom(this.blockId, "term:transparency")) ?? 0.5;
+ const value = get(getOverrideConfigAtom(this.blockId, "term:transparency")) ?? 0.5;
return boundNumber(value, 0, 1);
});
});
@@ -397,10 +397,12 @@ export class TermViewModel implements ViewModel {
return null;
}
const shellIntegrationStatus = get(this.termRef.current.shellIntegrationStatusAtom);
+ const claudeCodeActive = get(this.termRef.current.claudeCodeActiveAtom);
+ const icon = claudeCodeActive ? React.createElement(TermClaudeIcon) : "sparkles";
if (shellIntegrationStatus == null) {
return {
elemtype: "iconbutton",
- icon: "sparkles",
+ icon,
className: "text-muted",
title: "No shell integration — Wave AI unable to run commands.",
noAction: true,
@@ -409,14 +411,16 @@ export class TermViewModel implements ViewModel {
if (shellIntegrationStatus === "ready") {
return {
elemtype: "iconbutton",
- icon: "sparkles",
+ icon,
className: "text-accent",
title: "Shell ready — Wave AI can run commands in this terminal.",
noAction: true,
};
}
if (shellIntegrationStatus === "running-command") {
- let title = "Shell busy — Wave AI unable to run commands while another command is running.";
+ let title = claudeCodeActive
+ ? "Claude Code Detected"
+ : "Shell busy — Wave AI unable to run commands while another command is running.";
if (this.termRef.current) {
const inAltBuffer = this.termRef.current.terminal?.buffer?.active?.type === "alternate";
@@ -429,7 +433,7 @@ export class TermViewModel implements ViewModel {
return {
elemtype: "iconbutton",
- icon: "sparkles",
+ icon,
className: "text-warning",
title: title,
noAction: true,
@@ -544,7 +548,7 @@ export class TermViewModel implements ViewModel {
console.log("search is open, not giving focus");
return true;
}
- let termMode = globalStore.get(this.termMode);
+ const termMode = globalStore.get(this.termMode);
if (termMode == "term") {
if (this.termRef?.current?.terminal) {
this.termRef.current.terminal.focus();
diff --git a/frontend/app/view/term/term.tsx b/frontend/app/view/term/term.tsx
index b167688907..beabbe5174 100644
--- a/frontend/app/view/term/term.tsx
+++ b/frontend/app/view/term/term.tsx
@@ -1,6 +1,7 @@
-// Copyright 2025, Command Line Inc.
+// Copyright 2026, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
+import ClaudeColorSvg from "@/app/asset/claude-color.svg";
import { SubBlock } from "@/app/block/block";
import type { BlockNodeModel } from "@/app/block/blocktypes";
import { NullErrorBoundary } from "@/app/element/errorboundary";
@@ -33,6 +34,16 @@ interface TerminalViewProps {
model: TermViewModel;
}
+const TermClaudeIcon = React.memo(() => {
+ return (
+
+
+
+ );
+});
+
+TermClaudeIcon.displayName = "TermClaudeIcon";
+
const TermResyncHandler = React.memo(({ blockId, model }: TerminalViewProps) => {
const connStatus = jotai.useAtomValue(model.connStatus);
const [lastConnStatus, setLastConnStatus] = React.useState(connStatus);
@@ -60,7 +71,7 @@ const TermVDomToolbarNode = ({ vdomBlockId, blockId, model }: TerminalViewProps
const unsub = waveEventSubscribeSingle({
eventType: "blockclose",
scope: WOS.makeORef("block", vdomBlockId),
- handler: (event) => {
+ handler: (_event) => {
RpcApi.SetMetaCommand(TabRpcClient, {
oref: WOS.makeORef("block", blockId),
meta: {
@@ -103,7 +114,7 @@ const TermVDomNodeSingleId = ({ vdomBlockId, blockId, model }: TerminalViewProps
const unsub = waveEventSubscribeSingle({
eventType: "blockclose",
scope: WOS.makeORef("block", vdomBlockId),
- handler: (event) => {
+ handler: (_event) => {
RpcApi.SetMetaCommand(TabRpcClient, {
oref: WOS.makeORef("block", blockId),
meta: {
@@ -391,4 +402,4 @@ const TerminalView = ({ blockId, model }: ViewComponentProps) =>
);
};
-export { TerminalView };
+export { TermClaudeIcon, TerminalView };
diff --git a/frontend/app/view/term/termwrap.ts b/frontend/app/view/term/termwrap.ts
index 1cd167c800..1e9399ea4f 100644
--- a/frontend/app/view/term/termwrap.ts
+++ b/frontend/app/view/term/termwrap.ts
@@ -1,4 +1,4 @@
-// Copyright 2025, Command Line Inc.
+// Copyright 2026, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type { BlockNodeModel } from "@/app/block/blocktypes";
@@ -32,6 +32,7 @@ import {
handleOsc16162Command,
handleOsc52Command,
handleOsc7Command,
+ isClaudeCodeCommand,
type ShellIntegrationStatus,
} from "./osc-handlers";
import { bufferLinesToText, createTempFileFromBlob, extractAllClipboardData, normalizeCursorStyle } from "./termutil";
@@ -90,6 +91,7 @@ export class TermWrap {
promptMarkers: TermTypes.IMarker[] = [];
shellIntegrationStatusAtom: jotai.PrimitiveAtom;
lastCommandAtom: jotai.PrimitiveAtom;
+ claudeCodeActiveAtom: jotai.PrimitiveAtom;
nodeModel: BlockNodeModel; // this can be null
hoveredLinkUri: string | null = null;
onLinkHover?: (uri: string | null, mouseX: number, mouseY: number) => void;
@@ -142,6 +144,7 @@ export class TermWrap {
this.promptMarkers = [];
this.shellIntegrationStatusAtom = jotai.atom(null) as jotai.PrimitiveAtom;
this.lastCommandAtom = jotai.atom(null) as jotai.PrimitiveAtom;
+ this.claudeCodeActiveAtom = jotai.atom(false);
this.terminal = new Terminal(options);
this.fitAddon = new FitAddon();
this.fitAddon.scrollbarWidth = 6; // this needs to match scrollbar width in term.scss
@@ -393,16 +396,19 @@ export class TermWrap {
const rtInfo = await RpcApi.GetRTInfoCommand(TabRpcClient, {
oref: WOS.makeORef("block", this.blockId),
});
+ let shellState: ShellIntegrationStatus = null;
if (rtInfo && rtInfo["shell:integration"]) {
- const shellState = rtInfo["shell:state"] as ShellIntegrationStatus;
+ shellState = rtInfo["shell:state"] as ShellIntegrationStatus;
globalStore.set(this.shellIntegrationStatusAtom, shellState || null);
} else {
globalStore.set(this.shellIntegrationStatusAtom, null);
}
const lastCmd = rtInfo ? rtInfo["shell:lastcmd"] : null;
+ const isCC = shellState === "running-command" && isClaudeCodeCommand(lastCmd);
globalStore.set(this.lastCommandAtom, lastCmd || null);
+ globalStore.set(this.claudeCodeActiveAtom, isCC);
} catch (e) {
console.log("Error loading runtime info:", e);
}
@@ -419,14 +425,18 @@ export class TermWrap {
this.promptMarkers.forEach((marker) => {
try {
marker.dispose();
- } catch (_) {}
+ } catch (_) {
+ /* nothing */
+ }
});
this.promptMarkers = [];
this.terminal.dispose();
this.toDispose.forEach((d) => {
try {
d.dispose();
- } catch (_) {}
+ } catch (_) {
+ /* nothing */
+ }
});
this.mainFileSubject.release();
}
@@ -481,7 +491,7 @@ export class TermWrap {
}
}
let resolve: () => void = null;
- let prtn = new Promise((presolve, _) => {
+ const prtn = new Promise((presolve, _) => {
resolve = presolve;
});
this.terminal.write(data, () => {
diff --git a/package-lock.json b/package-lock.json
index 99c2a025b4..3dbb6471ab 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "waveterm",
- "version": "0.14.2-beta.1",
+ "version": "0.14.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "waveterm",
- "version": "0.14.2-beta.1",
+ "version": "0.14.2",
"hasInstallScript": true,
"license": "Apache-2.0",
"workspaces": [
@@ -5434,32 +5434,32 @@
}
},
"node_modules/@floating-ui/core": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
- "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
+ "version": "1.7.5",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
+ "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
"license": "MIT",
"dependencies": {
- "@floating-ui/utils": "^0.2.10"
+ "@floating-ui/utils": "^0.2.11"
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
- "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
+ "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
"license": "MIT",
"dependencies": {
- "@floating-ui/core": "^1.7.3",
- "@floating-ui/utils": "^0.2.10"
+ "@floating-ui/core": "^1.7.5",
+ "@floating-ui/utils": "^0.2.11"
}
},
"node_modules/@floating-ui/react": {
- "version": "0.27.16",
- "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.16.tgz",
- "integrity": "sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==",
+ "version": "0.27.19",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.19.tgz",
+ "integrity": "sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==",
"license": "MIT",
"dependencies": {
- "@floating-ui/react-dom": "^2.1.6",
- "@floating-ui/utils": "^0.2.10",
+ "@floating-ui/react-dom": "^2.1.8",
+ "@floating-ui/utils": "^0.2.11",
"tabbable": "^6.0.0"
},
"peerDependencies": {
@@ -5468,12 +5468,12 @@
}
},
"node_modules/@floating-ui/react-dom": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
- "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz",
+ "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==",
"license": "MIT",
"dependencies": {
- "@floating-ui/dom": "^1.7.4"
+ "@floating-ui/dom": "^1.7.6"
},
"peerDependencies": {
"react": ">=16.8.0",
@@ -5481,9 +5481,9 @@
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.2.10",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
- "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
+ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
"license": "MIT"
},
"node_modules/@hapi/hoek": {
@@ -15194,9 +15194,9 @@
"license": "MIT"
},
"node_modules/emoji-regex": {
- "version": "10.5.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz",
- "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==",
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"license": "MIT"
},
"node_modules/emojilib": {
@@ -15365,9 +15365,9 @@
}
},
"node_modules/es-toolkit": {
- "version": "1.39.10",
- "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.10.tgz",
- "integrity": "sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==",
+ "version": "1.45.1",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz",
+ "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==",
"license": "MIT",
"workspaces": [
"docs",
@@ -18960,9 +18960,9 @@
}
},
"node_modules/katex": {
- "version": "0.16.22",
- "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz",
- "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==",
+ "version": "0.16.38",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.38.tgz",
+ "integrity": "sha512-cjHooZUmIAUmDsHBN+1n8LaZdpmbj03LtYeYPyuYB7OuloiaeaV6N4LcfjcnHVzGWjVQmKrxxTrpDcmSzEZQwQ==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"
@@ -29930,13 +29930,13 @@
}
},
"node_modules/swr": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz",
- "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.1.tgz",
+ "integrity": "sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==",
"license": "MIT",
"dependencies": {
"dequal": "^2.0.3",
- "use-sync-external-store": "^1.4.0"
+ "use-sync-external-store": "^1.6.0"
},
"peerDependencies": {
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -29959,9 +29959,9 @@
}
},
"node_modules/tabbable": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
- "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
"license": "MIT"
},
"node_modules/tailwind-merge": {
@@ -31879,9 +31879,9 @@
}
},
"node_modules/use-sync-external-store": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
- "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
"license": "MIT",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"