diff --git a/.changeset/fn-6681-recharts-charts.md b/.changeset/fn-6681-recharts-charts.md new file mode 100644 index 0000000000..f5b0bf49df --- /dev/null +++ b/.changeset/fn-6681-recharts-charts.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": minor +--- + +Add `recharts` and shared Command Center PieChart/LineChart wrappers for downstream graphical chart migrations. The wrappers are token-themed, responsive, reduced-motion aware, and safe for empty, zero, negative, NaN, and Infinity inputs; the current production build shows no observable Command Center chunk-size increase yet because no Command Center surface imports the new wrappers until the dependent migration tasks land (CommandCenter chunk remains 74.68 kB / 16.46 kB gzip in this task's build output). diff --git a/packages/dashboard/app/components/command-center/charts/recharts/LineChart.tsx b/packages/dashboard/app/components/command-center/charts/recharts/LineChart.tsx new file mode 100644 index 0000000000..e10f84b707 --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/LineChart.tsx @@ -0,0 +1,128 @@ +import { + CartesianGrid, + Legend, + Line, + LineChart as RechartsLineChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; +import { getCommandCenterChartColor, getCommandCenterChartTheme } from "./theme"; + +export interface LineChartSeries { + label: string; + values: number[]; +} + +export interface LineChartProps { + series: LineChartSeries[]; + ariaLabel: string; + width?: number | string; + height?: number | string; + emptyLabel?: string; +} + +interface SanitizedLineChartSeries { + label: string; + dataKey: string; + values: number[]; +} + +type LineChartPoint = { index: number } & Record; +type ResponsiveDimension = number | `${number}%`; + +function prefersReducedMotion(): boolean { + return ( + typeof window !== "undefined" + && typeof window.matchMedia === "function" + && window.matchMedia("(prefers-reduced-motion: reduce)").matches + ); +} + +function sanitizeLineValue(value: number): number { + return Number.isFinite(value) && value > 0 ? value : 0; +} + +function sanitizeSeries(series: LineChartSeries[]): SanitizedLineChartSeries[] { + return series + .map((entry, index) => ({ + label: entry.label, + dataKey: `series${index}`, + values: entry.values.map(sanitizeLineValue), + })) + .filter((entry) => entry.values.length > 0); +} + +function lineChartData(series: SanitizedLineChartSeries[]): LineChartPoint[] { + const pointCount = series.reduce((largest, entry) => Math.max(largest, entry.values.length), 0); + return Array.from({ length: pointCount }, (_, index) => { + const point: LineChartPoint = { index: index + 1 }; + for (const entry of series) { + point[entry.dataKey] = entry.values[index] ?? 0; + } + return point; + }); +} + +function containerStyle(width?: number | string, height?: number | string) { + return width !== undefined || height !== undefined ? { width, height } : undefined; +} + +function responsiveDimension(value: number | string | undefined): ResponsiveDimension { + if (typeof value === "number") { + return value; + } + + return typeof value === "string" && /^\d+(?:\.\d+)?%$/.test(value) ? (value as `${number}%`) : "100%"; +} + +/** + * FNXC:CommandCenterCharts 2026-06-18-21:52: + * User requested real graphical pie + line charts on every Command Center surface using a proper chart library (recharts); this shared line wrapper preserves the existing series shape while coercing zero/NaN/Infinity inputs into safe responsive, token-themed, reduced-motion-aware recharts data. + */ +export function LineChart({ series, ariaLabel, width, height, emptyLabel = "No chart data" }: LineChartProps) { + const theme = getCommandCenterChartTheme(); + const chartSeries = sanitizeSeries(series); + const chartData = lineChartData(chartSeries); + + if (chartSeries.length === 0 || chartData.length === 0) { + return ( +
+ {emptyLabel} +
+ ); + } + + return ( +
+ + + + + + + + {chartSeries.map((entry, index) => ( + + ))} + + +
+ ); +} diff --git a/packages/dashboard/app/components/command-center/charts/recharts/PieChart.tsx b/packages/dashboard/app/components/command-center/charts/recharts/PieChart.tsx new file mode 100644 index 0000000000..17fc4c2cc3 --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/PieChart.tsx @@ -0,0 +1,104 @@ +import { + Cell, + Legend, + Pie, + PieChart as RechartsPieChart, + ResponsiveContainer, + Tooltip, +} from "recharts"; +import { getCommandCenterChartColor, getCommandCenterChartTheme } from "./theme"; + +export interface PieChartDatum { + label: string; + value: number; +} + +export interface PieChartProps { + data: PieChartDatum[]; + ariaLabel: string; + width?: number | string; + height?: number | string; + emptyLabel?: string; +} + +interface SanitizedPieChartDatum { + label: string; + value: number; +} + +type ResponsiveDimension = number | `${number}%`; + +function prefersReducedMotion(): boolean { + return ( + typeof window !== "undefined" + && typeof window.matchMedia === "function" + && window.matchMedia("(prefers-reduced-motion: reduce)").matches + ); +} + +function sanitizePieData(data: PieChartDatum[]): SanitizedPieChartDatum[] { + return data + .map((entry) => ({ + label: entry.label, + value: Number.isFinite(entry.value) && entry.value > 0 ? entry.value : 0, + })) + .filter((entry) => entry.value > 0); +} + +function containerStyle(width?: number | string, height?: number | string) { + return width !== undefined || height !== undefined ? { width, height } : undefined; +} + +function responsiveDimension(value: number | string | undefined): ResponsiveDimension { + if (typeof value === "number") { + return value; + } + + return typeof value === "string" && /^\d+(?:\.\d+)?%$/.test(value) ? (value as `${number}%`) : "100%"; +} + +/** + * FNXC:CommandCenterCharts 2026-06-18-21:47: + * User requested real graphical pie + line charts on every Command Center surface using a proper chart library (recharts); this shared pie wrapper is token-themed, responsive, reduced-motion aware, and filters zero/NaN/negative values before recharts can receive invalid geometry. + */ +export function PieChart({ data, ariaLabel, width, height, emptyLabel = "No chart data" }: PieChartProps) { + const theme = getCommandCenterChartTheme(); + const chartData = sanitizePieData(data); + + if (chartData.length === 0) { + return ( +
+ {emptyLabel} +
+ ); + } + + return ( +
+ + + + {chartData.map((entry, index) => ( + + ))} + + + + + +
+ ); +} diff --git a/packages/dashboard/app/components/command-center/charts/recharts/__tests__/LineChart.test.tsx b/packages/dashboard/app/components/command-center/charts/recharts/__tests__/LineChart.test.tsx new file mode 100644 index 0000000000..7bb75512b0 --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/__tests__/LineChart.test.tsx @@ -0,0 +1,83 @@ +import { render, screen } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { LineChart } from "../LineChart"; +import type { LineChartSeries } from "../LineChart"; + +const chartSize = { width: 360, height: 220 }; + +function chartHtml(label: string): string { + return screen.getByRole("img", { name: label }).outerHTML; +} + +function renderChart(series: LineChartSeries[], ariaLabel = "line chart") { + // FNXC:CommandCenterCharts 2026-06-18-22:03: jsdom's ResizeObserver mock does not report dimensions, so tests pass explicit dimensions through the wrapper to mount recharts children while production remains responsive. + return render(); +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("recharts LineChart", () => { + it("renders populated multi-series lines with an accessible label and finite output", () => { + expect(() => renderChart([ + { label: "Messages", values: [1, 3, 2] }, + { label: "Tasks", values: [0, 2, 4] }, + ], "activity trend")).not.toThrow(); + + expect(screen.getByRole("img", { name: "activity trend" })).toBeTruthy(); + expect(screen.getByText("Messages")).toBeTruthy(); + expect(screen.getByText("Tasks")).toBeTruthy(); + expect(chartHtml("activity trend")).not.toMatch(/NaN|Infinity/); + }); + + it("renders a single-point series cleanly", () => { + expect(() => renderChart([{ label: "Single", values: [5] }], "single point")).not.toThrow(); + + expect(screen.getByRole("img", { name: "single point" })).toBeTruthy(); + expect(screen.getByText("Single")).toBeTruthy(); + expect(chartHtml("single point")).not.toMatch(/NaN|Infinity/); + }); + + it("renders an accessible empty state for empty input", () => { + expect(() => renderChart([], "empty line")).not.toThrow(); + + expect(screen.getByRole("img", { name: "empty line" })).toBeTruthy(); + expect(screen.getByText("No chart data")).toBeTruthy(); + expect(chartHtml("empty line")).not.toMatch(/NaN|Infinity/); + }); + + it("renders all-zero series as a valid baseline chart", () => { + expect(() => renderChart([{ label: "Zero", values: [0, 0, 0] }], "zero line")).not.toThrow(); + + expect(screen.getByRole("img", { name: "zero line" })).toBeTruthy(); + expect(screen.getByText("Zero")).toBeTruthy(); + expect(screen.queryByText("No chart data")).toBeNull(); + expect(chartHtml("zero line")).not.toMatch(/NaN|Infinity/); + }); + + it("coerces non-finite and negative values without leaking invalid output", () => { + expect(() => renderChart([{ label: "Invalid", values: [Number.NaN, Number.POSITIVE_INFINITY, -4, 2] }], "invalid line")).not.toThrow(); + + expect(screen.getByRole("img", { name: "invalid line" })).toBeTruthy(); + expect(screen.getByText("Invalid")).toBeTruthy(); + expect(chartHtml("invalid line")).not.toMatch(/NaN|Infinity/); + }); + + it("checks reduced-motion preference before enabling recharts animation", () => { + const matchMedia = vi.fn().mockImplementation((query: string) => ({ + matches: query === "(prefers-reduced-motion: reduce)", + media: query, + onchange: null, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })); + vi.stubGlobal("matchMedia", matchMedia); + + renderChart([{ label: "Messages", values: [1, 2] }], "reduced motion line"); + + expect(matchMedia).toHaveBeenCalledWith("(prefers-reduced-motion: reduce)"); + expect(chartHtml("reduced motion line")).not.toMatch(/NaN|Infinity/); + }); +}); diff --git a/packages/dashboard/app/components/command-center/charts/recharts/__tests__/PieChart.test.tsx b/packages/dashboard/app/components/command-center/charts/recharts/__tests__/PieChart.test.tsx new file mode 100644 index 0000000000..3015bf6a74 --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/__tests__/PieChart.test.tsx @@ -0,0 +1,83 @@ +import { render, screen } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { PieChart } from "../PieChart"; +import type { PieChartProps } from "../PieChart"; + +const chartSize = { width: 320, height: 220 }; + +function chartHtml(label: string): string { + return screen.getByRole("img", { name: label }).outerHTML; +} + +function renderChart(data: PieChartProps["data"], ariaLabel = "pie chart") { + // FNXC:CommandCenterCharts 2026-06-18-22:01: jsdom's ResizeObserver mock does not report dimensions, so tests pass explicit dimensions through the wrapper to mount recharts children while production remains responsive. + return render(); +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("recharts PieChart", () => { + it("renders a populated multi-item pie with an accessible label and finite output", () => { + expect(() => renderChart([{ label: "Done", value: 8 }, { label: "Todo", value: 4 }], "status split")).not.toThrow(); + + expect(screen.getByRole("img", { name: "status split" })).toBeTruthy(); + expect(screen.getByText("Done")).toBeTruthy(); + expect(screen.getByText("Todo")).toBeTruthy(); + expect(chartHtml("status split")).not.toMatch(/NaN|Infinity/); + }); + + it("renders a single-item pie without invalid geometry", () => { + expect(() => renderChart([{ label: "Only", value: 3 }], "single slice")).not.toThrow(); + + expect(screen.getByRole("img", { name: "single slice" })).toBeTruthy(); + expect(screen.getByText("Only")).toBeTruthy(); + expect(chartHtml("single slice")).not.toMatch(/NaN|Infinity/); + }); + + it("renders an accessible empty state for empty input", () => { + expect(() => renderChart([], "empty pie")).not.toThrow(); + + expect(screen.getByRole("img", { name: "empty pie" })).toBeTruthy(); + expect(screen.getByText("No chart data")).toBeTruthy(); + expect(chartHtml("empty pie")).not.toMatch(/NaN|Infinity/); + }); + + it("renders an accessible empty state for all-zero input", () => { + expect(() => renderChart([{ label: "Zero", value: 0 }], "zero pie")).not.toThrow(); + + expect(screen.getByRole("img", { name: "zero pie" })).toBeTruthy(); + expect(screen.getByText("No chart data")).toBeTruthy(); + expect(chartHtml("zero pie")).not.toMatch(/NaN|Infinity/); + }); + + it("filters non-finite and negative values without leaking invalid output", () => { + expect(() => renderChart([ + { label: "NaN", value: Number.NaN }, + { label: "Infinity", value: Number.POSITIVE_INFINITY }, + { label: "Negative", value: -2 }, + ], "invalid pie")).not.toThrow(); + + expect(screen.getByRole("img", { name: "invalid pie" })).toBeTruthy(); + expect(screen.getByText("No chart data")).toBeTruthy(); + expect(chartHtml("invalid pie")).not.toMatch(/NaN|Infinity/); + }); + + it("checks reduced-motion preference before enabling recharts animation", () => { + const matchMedia = vi.fn().mockImplementation((query: string) => ({ + matches: query === "(prefers-reduced-motion: reduce)", + media: query, + onchange: null, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })); + vi.stubGlobal("matchMedia", matchMedia); + + renderChart([{ label: "Done", value: 1 }], "reduced motion pie"); + + expect(matchMedia).toHaveBeenCalledWith("(prefers-reduced-motion: reduce)"); + expect(chartHtml("reduced motion pie")).not.toMatch(/NaN|Infinity/); + }); +}); diff --git a/packages/dashboard/app/components/command-center/charts/recharts/index.ts b/packages/dashboard/app/components/command-center/charts/recharts/index.ts new file mode 100644 index 0000000000..e0432b44bf --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/index.ts @@ -0,0 +1,15 @@ +/** + * FNXC:CommandCenterCharts 2026-06-18-21:55: + * Downstream Command Center migrations need one stable import surface for recharts wrappers and theme helpers so every real pie + line graph shares token theming, responsive layout, reduced-motion behavior, and zero/NaN safety. + */ +export { PieChart } from "./PieChart"; +export type { PieChartDatum, PieChartProps } from "./PieChart"; +export { LineChart } from "./LineChart"; +export type { LineChartProps, LineChartSeries } from "./LineChart"; +export { + getCommandCenterChartColor, + getCommandCenterChartCssToken, + getCommandCenterChartOptionalCssToken, + getCommandCenterChartTheme, +} from "./theme"; +export type { CommandCenterChartTheme } from "./theme"; diff --git a/packages/dashboard/app/components/command-center/charts/recharts/theme.ts b/packages/dashboard/app/components/command-center/charts/recharts/theme.ts new file mode 100644 index 0000000000..9f29e31e9b --- /dev/null +++ b/packages/dashboard/app/components/command-center/charts/recharts/theme.ts @@ -0,0 +1,84 @@ +export interface CommandCenterChartTheme { + stroke: string; + fill: string; + grid: string; + tick: string; + tooltipBackground: string; + tooltipBorder: string; + tooltipText: string; + legendText: string; + palette: string[]; +} + +const TOKEN_FALLBACK = "currentColor"; + +const paletteTokens = [ + "--accent", + "--todo", + "--in-progress", + "--in-review", + "--triage", + "--color-success", + "--color-warning", + "--color-error", +] as const; + +function cssTokenValue(tokenName: string, fallback = TOKEN_FALLBACK): string { + if (typeof document === "undefined" || typeof getComputedStyle !== "function") { + return fallback; + } + + const value = getComputedStyle(document.documentElement).getPropertyValue(tokenName).trim(); + return value.length > 0 ? value : fallback; +} + +function cssTokenValueOptional(tokenName: string): string { + if (typeof document === "undefined" || typeof getComputedStyle !== "function") { + return ""; + } + + return getComputedStyle(document.documentElement).getPropertyValue(tokenName).trim(); +} + +/** + * FNXC:CommandCenterCharts 2026-06-18-21:41: + * User requested real graphical pie + line charts on every Command Center surface using recharts; resolve dashboard CSS tokens at render time so wrappers stay theme-aware while keeping SSR/jsdom fallbacks free of undefined, NaN, or hardcoded color output. + */ +export function getCommandCenterChartTheme(): CommandCenterChartTheme { + const text = cssTokenValue("--text"); + const mutedText = cssTokenValue("--text-muted", text); + const accent = cssTokenValue("--accent"); + const surface = cssTokenValue("--surface-1", ""); + const surfaceAlt = cssTokenValue("--surface-2", surface); + const border = cssTokenValue("--border-subtle", ""); + const palette = paletteTokens.map((tokenName) => cssTokenValue(tokenName)).filter((value) => value.length > 0); + + return { + stroke: accent, + fill: surfaceAlt, + grid: border, + tick: mutedText, + tooltipBackground: surface, + tooltipBorder: border, + tooltipText: text, + legendText: mutedText, + palette: palette.length > 0 ? palette : [TOKEN_FALLBACK], + }; +} + +export function getCommandCenterChartColor(index: number, theme = getCommandCenterChartTheme()): string { + if (theme.palette.length === 0) { + return TOKEN_FALLBACK; + } + + const safeIndex = Number.isFinite(index) && index >= 0 ? Math.floor(index) : 0; + return theme.palette[safeIndex % theme.palette.length] ?? TOKEN_FALLBACK; +} + +export function getCommandCenterChartCssToken(tokenName: string, fallback = TOKEN_FALLBACK): string { + return cssTokenValue(tokenName, fallback); +} + +export function getCommandCenterChartOptionalCssToken(tokenName: string): string { + return cssTokenValueOptional(tokenName); +} diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index 403327150c..6748532cd3 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -130,6 +130,7 @@ "node-pty": "npm:@homebridge/node-pty-prebuilt-multiarch@^0.13.1", "qrcode": "^1.5.4", "react": "^19.0.0", + "recharts": "^3.8.1", "react-dom": "^19.0.0", "react-i18next": "^17.0.8", "react-markdown": "^10.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47707149f5..2923da0e40 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,10 +47,10 @@ importers: dependencies: '@earendil-works/pi-ai': specifier: ^0.79.1 - version: 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + version: 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) '@earendil-works/pi-coding-agent': specifier: ^0.79.1 - version: 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) + version: 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) dockerode: specifier: ^4.0.12 version: 4.0.12 @@ -284,7 +284,7 @@ importers: version: 5.5.0 '@xyflow/react': specifier: ^12.11.0 - version: 12.11.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 12.11.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(immer@11.1.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) archiver: specifier: ^7.0.1 version: 7.0.1 @@ -327,6 +327,9 @@ importers: react-markdown: specifier: ^10.1.0 version: 10.1.0(@types/react@19.2.14)(react@19.2.4) + recharts: + specifier: ^3.8.1 + version: 3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@17.0.2)(react@19.2.4)(redux@5.0.1) remark-gfm: specifier: ^4.0.1 version: 4.0.1 @@ -2575,6 +2578,17 @@ packages: '@protobufjs/utf8@1.1.1': resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@reduxjs/toolkit@2.12.0': + resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -2773,6 +2787,9 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@swc/core-darwin-arm64@1.15.40': resolution: {integrity: sha512-PaYyclfmQ++77D8ityYvmmVzHv9aG8ROwt2GfG6/ccloy4Hgf80qtOnzb9VYvPsUT7Ty1uhuDRhv3XYpf62qhQ==} engines: {node: '>=10'} @@ -2940,18 +2957,39 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + '@types/d3-color@3.1.3': resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} '@types/d3-drag@3.0.7': resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + '@types/d3-interpolate@3.0.4': resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + '@types/d3-selection@3.0.11': resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + '@types/d3-transition@3.0.9': resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} @@ -3065,6 +3103,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/verror@1.10.11': resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} @@ -3819,6 +3860,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} @@ -3974,6 +4019,10 @@ packages: curve25519-js@0.0.4: resolution: {integrity: sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + d3-color@3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} @@ -3990,14 +4039,38 @@ packages: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + d3-interpolate@3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + d3-selection@3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + d3-timer@3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} @@ -4033,6 +4106,9 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -4821,6 +4897,12 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + immer@10.2.0: + resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} + + immer@11.1.8: + resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -4899,6 +4981,10 @@ packages: '@types/node': optional: true + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + ioredis@5.10.1: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} @@ -6078,6 +6164,18 @@ packages: peerDependencies: react: ^19.2.0 + react-redux@9.3.0: + resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -6128,6 +6226,14 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + recharts@3.8.1: + resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==} + engines: {node: '>=18'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -6140,6 +6246,14 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} @@ -6167,6 +6281,9 @@ packages: resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} engines: {node: '>=12', npm: '>=6'} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -6610,6 +6727,9 @@ packages: tiny-async-pool@1.3.0: resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tiny-typed-emitter@2.1.0: resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} @@ -6871,6 +6991,9 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + victory-vendor@37.3.6: + resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + vite@6.4.1: resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -7185,6 +7308,10 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 + '@anthropic-ai/sdk@0.91.1': + dependencies: + json-schema-to-ts: 3.1.1 + '@anthropic-ai/sdk@0.91.1(zod@3.25.76)': dependencies: json-schema-to-ts: 3.1.1 @@ -7950,6 +8077,20 @@ snapshots: - ws - zod + '@earendil-works/pi-agent-core@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + '@earendil-works/pi-agent-core@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: '@earendil-works/pi-ai': 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) @@ -7980,14 +8121,14 @@ snapshots: '@earendil-works/pi-ai@0.77.0': dependencies: - '@anthropic-ai/sdk': 0.91.1(zod@3.25.76) + '@anthropic-ai/sdk': 0.91.1 '@aws-sdk/client-bedrock-runtime': 3.1048.0 - '@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)) + '@google/genai': 1.52.0 '@mistralai/mistralai': 2.2.1 '@smithy/node-http-handler': 4.7.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 - openai: 6.26.0(ws@8.20.0)(zod@3.25.76) + openai: 6.26.0 partial-json: 0.1.7 typebox: 1.1.38 transitivePeerDependencies: @@ -8038,6 +8179,26 @@ snapshots: - ws - zod + '@earendil-works/pi-ai@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@3.25.76) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76)) + '@mistralai/mistralai': 2.2.1 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.20.0)(zod@3.25.76) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + '@earendil-works/pi-ai@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: '@anthropic-ai/sdk': 0.91.1(zod@4.3.6) @@ -8062,7 +8223,7 @@ snapshots: dependencies: '@anthropic-ai/sdk': 0.91.1(zod@3.25.76) '@aws-sdk/client-bedrock-runtime': 3.1048.0 - '@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)) + '@google/genai': 1.52.0 '@mistralai/mistralai': 2.2.1 '@smithy/node-http-handler': 4.7.3 http-proxy-agent: 7.0.2 @@ -8165,6 +8326,35 @@ snapshots: - ws - zod + '@earendil-works/pi-coding-agent@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@earendil-works/pi-agent-core': 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@earendil-works/pi-ai': 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@earendil-works/pi-tui': 0.79.1 + '@silvia-odwyer/photon-node': 0.3.4 + chalk: 5.6.2 + cross-spawn: 7.0.6 + diff: 8.0.4 + glob: 13.0.6 + highlight.js: 10.7.3 + hosted-git-info: 9.0.3 + ignore: 7.0.5 + jiti: 2.7.0 + minimatch: 10.2.5 + proper-lockfile: 4.1.2 + typebox: 1.1.38 + undici: 8.3.0 + yaml: 2.9.0 + optionalDependencies: + '@mariozechner/clipboard': 0.3.9 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + '@earendil-works/pi-coding-agent@0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6)': dependencies: '@earendil-works/pi-agent-core': 0.79.1(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))(ws@8.20.0)(zod@4.3.6) @@ -8549,6 +8739,30 @@ snapshots: '@exodus/bytes@1.15.0': {} + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.6.2 + p-retry: 4.6.2 + protobufjs: 7.5.8 + ws: 8.20.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@3.25.76))': + dependencies: + google-auth-library: 10.6.2 + p-retry: 4.6.2 + protobufjs: 7.5.8 + ws: 8.20.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.28.0(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.28.0(zod@4.3.6))': dependencies: google-auth-library: 10.6.2 @@ -9053,6 +9267,29 @@ snapshots: - bufferutil - utf-8-validate + '@modelcontextprotocol/sdk@1.28.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.12(hono@4.12.9) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.1(express@5.2.1) + hono: 4.12.9 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - supports-color + optional: true + '@modelcontextprotocol/sdk@1.28.0(zod@4.3.6)': dependencies: '@hono/node-server': 1.19.12(hono@4.12.9) @@ -9133,6 +9370,18 @@ snapshots: '@protobufjs/utf8@1.1.1': {} + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@standard-schema/utils': 0.3.0 + immer: 11.1.8 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.4 + react-redux: 9.3.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1) + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/rollup-android-arm-eabi@4.60.0': @@ -9274,6 +9523,8 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@standard-schema/utils@0.3.0': {} + '@swc/core-darwin-arm64@1.15.40': optional: true @@ -9428,18 +9679,36 @@ snapshots: dependencies: '@types/node': 25.5.2 + '@types/d3-array@3.2.2': {} + '@types/d3-color@3.1.3': {} '@types/d3-drag@3.0.7': dependencies: '@types/d3-selection': 3.0.11 + '@types/d3-ease@3.0.2': {} + '@types/d3-interpolate@3.0.4': dependencies: '@types/d3-color': 3.1.3 + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + '@types/d3-selection@3.0.11': {} + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + '@types/d3-transition@3.0.9': dependencies: '@types/d3-selection': 3.0.11 @@ -9576,6 +9845,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/use-sync-external-store@0.0.6': {} + '@types/verror@1.10.11': optional: true @@ -9708,7 +9979,7 @@ snapshots: obug: 2.1.2 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.8(@types/node@25.5.2)(@vitest/coverage-v8@4.1.8)(happy-dom@20.10.1)(jsdom@29.0.1)(vite@6.4.1(@types/node@25.5.2)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + vitest: 4.1.8(@types/node@25.5.2)(@vitest/coverage-v8@4.1.8)(happy-dom@20.10.1)(jsdom@29.0.1)(vite@6.4.1(@types/node@25.5.2)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/expect@4.1.8': dependencies: @@ -9838,13 +10109,13 @@ snapshots: '@xterm/xterm@5.5.0': {} - '@xyflow/react@12.11.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@xyflow/react@12.11.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(immer@11.1.8)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@xyflow/system': 0.0.77 classcat: 5.0.5 react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - zustand: 4.5.7(@types/react@19.2.14)(react@19.2.4) + zustand: 4.5.7(@types/react@19.2.14)(immer@11.1.8)(react@19.2.4) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -10435,6 +10706,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + cluster-key-slot@1.1.2: {} code-excerpt@4.0.0: @@ -10569,6 +10842,10 @@ snapshots: curve25519-js@0.0.4: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + d3-color@3.1.0: {} d3-dispatch@3.0.1: {} @@ -10580,12 +10857,36 @@ snapshots: d3-ease@3.0.1: {} + d3-format@3.1.2: {} + d3-interpolate@3.0.1: dependencies: d3-color: 3.1.0 + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-selection@3.0.0: {} + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + d3-timer@3.0.1: {} d3-transition@3.0.1(d3-selection@3.0.0): @@ -10620,6 +10921,8 @@ snapshots: decamelize@1.2.0: {} + decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} decode-named-character-reference@1.3.0: @@ -11658,6 +11961,10 @@ snapshots: ignore@7.0.5: {} + immer@10.2.0: {} + + immer@11.1.8: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -11746,6 +12053,8 @@ snapshots: optionalDependencies: '@types/node': 25.5.2 + internmap@2.0.3: {} + ioredis@5.10.1: dependencies: '@ioredis/commands': 1.5.1 @@ -12722,6 +13031,8 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openai@6.26.0: {} + openai@6.26.0(ws@8.20.0)(zod@3.25.76): optionalDependencies: ws: 8.20.0 @@ -13122,6 +13433,15 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 + react-redux@9.3.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + redux: 5.0.1 + react-refresh@0.17.0: {} react@19.2.4: {} @@ -13179,6 +13499,26 @@ snapshots: real-require@0.2.0: {} + recharts@3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@17.0.2)(react@19.2.4)(redux@5.0.1): + dependencies: + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.45.1 + eventemitter3: 5.0.4 + immer: 10.2.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-is: 17.0.2 + react-redux: 9.3.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1) + reselect: 5.1.1 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.6.0(react@19.2.4) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -13190,6 +13530,12 @@ snapshots: dependencies: redis-errors: 1.2.0 + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 @@ -13234,6 +13580,8 @@ snapshots: dependencies: pe-library: 0.4.1 + reselect@5.1.1: {} + resolve-alpn@1.2.1: {} resolve-from@4.0.0: {} @@ -13769,6 +14117,8 @@ snapshots: dependencies: semver: 5.7.2 + tiny-invariant@1.3.3: {} + tiny-typed-emitter@2.1.0: {} tinybench@2.9.0: {} @@ -14024,6 +14374,23 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + victory-vendor@37.3.6: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + vite@6.4.1(@types/node@25.5.2)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.25.12 @@ -14283,11 +14650,12 @@ snapshots: zod@4.3.6: {} - zustand@4.5.7(@types/react@19.2.14)(react@19.2.4): + zustand@4.5.7(@types/react@19.2.14)(immer@11.1.8)(react@19.2.4): dependencies: use-sync-external-store: 1.6.0(react@19.2.4) optionalDependencies: '@types/react': 19.2.14 + immer: 11.1.8 react: 19.2.4 zwitch@2.0.4: {}