diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index fc0affbd..05f9e3af 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,3 +23,17 @@ jobs: python-version: ${{ matrix.python-version }} - name: Test with pytest run: uv run --with pytest --with pytest-cov pytest --doctest-modules --cov=copilotj --cov-report=xml --cov-report=html --ignore=examples --pyargs copilotj + + java-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: "21" + cache: maven + - name: Run Java unit tests + working-directory: plugin + run: mvn -B test diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 43537973..eff0da73 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -23,15 +23,16 @@ Run `just` or `just --list` to see all available commands. You can also review the `justfile` to understand how each task is defined and configured, or refer to it directly if you prefer not to install [just](https://github.com/casey/just). -| Command | Description | -| ------------------- | ------------------------------ | -| `just dev-server` | Run the bridge server | -| `just dev-plugin` | Run the ImageJ plugin (debug) | -| `just dev-web` | Run the web frontend | -| `just test` | Run Python tests | -| `just test-cov` | Run tests with coverage report | -| `just build-plugin` | Build the plugin JAR | -| `just build-web` | Build the web frontend | +| Command | Description | +| ------------------- | ----------------------------- | +| `just dev-server` | Run the bridge server | +| `just dev-plugin` | Run the ImageJ plugin (debug) | +| `just dev-web` | Run the web frontend | +| `just test` | Run tests | +| `just test-python` | Run Python tests only | +| `just test-plugin` | Run ImageJ plugin tests only | +| `just build-plugin` | Build the plugin JAR | +| `just build-web` | Build the web frontend | ## Running the components @@ -278,8 +279,9 @@ and register any custom tools. ## Testing ```bash -just test # Run Python tests -just test-cov # Run tests with coverage report (HTML + XML) +just test # Run tests +just test-python # Run Python tests only +just test-plugin # Run ImageJ plugin tests only ``` ## Observability (optional) diff --git a/copilotj/multiagent/leader_multiagent.py b/copilotj/multiagent/leader_multiagent.py index ec51b94e..95d35f1d 100644 --- a/copilotj/multiagent/leader_multiagent.py +++ b/copilotj/multiagent/leader_multiagent.py @@ -784,6 +784,7 @@ async def run(self, task: str, trace_ctx: Langfuse | None = None) -> None: "Reply with a single Thought + Action, or a Final Answer.", trace_ctx=trace_ctx, ) + syntax_error_counter = 0 # Reset syntax error counter on success except ModelSyntaxError as e: syntax_error_counter += 1 self.log_error( diff --git a/copilotj/plugin/awt/window/ij_image.py b/copilotj/plugin/awt/window/ij_image.py index 861a81f3..af8c5300 100644 --- a/copilotj/plugin/awt/window/ij_image.py +++ b/copilotj/plugin/awt/window/ij_image.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 +import re from typing import Literal, override from copilotj.plugin._base import FromTo, Response, Verbosity @@ -46,11 +47,42 @@ def _describe(self, *, level: int, verbosity: Verbosity) -> list[str]: return [self._describe_one_line(level=level, verbosity=verbosity)] +# Values of these metadata keys duplicate the structured fields rendered by IjImage._describe +# (width/height/depth/channels/frames, calibration, units, bit depth). They are skipped on the +# perception/display path only — the stored `info` keeps the full raw metadata. Note that `info` +# also participates in IjImage.equals and is rendered verbatim on the diff path +# (IjImageDifference via FromTo), so volatile metadata can still surface as snapshot diffs; that +# tradeoff is intentional (see the matching note on the Java side, IjImage.buildImageMetadata). +_INFO_REDUNDANT_KEYS = frozenset( + { + "SizeX", + "SizeY", + "SizeZ", + "SizeC", + "SizeT", + "PhysicalSizeX", + "PhysicalSizeY", + "PhysicalSizeZ", + "PhysicalSizeXUnit", + "PhysicalSizeYUnit", + "PhysicalSizeZUnit", + "BitsPerSample", + "BitsPerPixel", + "SignificantBits", + "PixelType", + } +) +# Matches Bio-Formats/TIFF-style "Key: Value" lines; non-matching lines (prose, OME-XML, "key=value" +# headers from FileInfo.description) are left intact. +_INFO_KV_RE = re.compile(r"^([A-Za-z0-9_]+)\s*:\s*(.+)$") + + class IjImage(AwtWindowBase[TYPE]): title: str image_type: str size: str path: str | None + info: str | None = None bit_depth: int stack_size: int @@ -121,6 +153,17 @@ def _describe(self, *, level: int, verbosity: Verbosity) -> list[str]: if self.roi: lines.append(self.roi._describe_one_line(level=level, verbosity=verbosity)) + if self.info: + kept = [] + for ln in self.info.splitlines(): + m = _INFO_KV_RE.match(ln.strip()) + if m and m.group(1) in _INFO_REDUNDANT_KEYS: + continue # already shown via the structured fields above + kept.append(ln) + if kept: # don't emit an empty "Metadata:" block when every line was redundant + lines.append("Metadata:") + lines.extend(kept) + return lines @@ -129,6 +172,7 @@ class IjImageDifference(AwtWindowDifferenceBase[TYPE]): image_type: FromTo[str] | None = None size: FromTo[str] | None = None path: FromTo[str | None] | None = None + info: FromTo[str | None] | None = None bit_depth: FromTo[int] | None = None stack_size: FromTo[int] | None = None diff --git a/copilotj/test/multiagent/test_leader_syntax_reset.py b/copilotj/test/multiagent/test_leader_syntax_reset.py new file mode 100644 index 00000000..988e51b2 --- /dev/null +++ b/copilotj/test/multiagent/test_leader_syntax_reset.py @@ -0,0 +1,155 @@ +# SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Tests for LeaderDriven.run() syntax-error counter reset. + +`syntax_error_counter` must track CONSECUTIVE ReAct syntax errors, not +cumulative ones: a model that recovers (produces a valid response) between +errors must have its counter reset, mirroring `tool_retry_counter` at L850. + +Control-flow fact these tests rely on (verified by trace + outside-voice +review): every ModelSyntaxError increment in run() leaves `agent_resp = None`, +which routes recovery through the single `send_correction` at ~L782. That site +is the only place a reset is load-bearing. +""" + +import asyncio + +from copilotj.core import ModelSyntaxError +from copilotj.multiagent.leader_multiagent import LeaderDriven + +_MAX_SYNTAX_ERRORS = 3 + + +class _Args: + def model_dump(self) -> dict: + return {} + + +class _Tool: + def __init__(self, name: str) -> None: + self.name = name + + +class _ToolCall: + def __init__(self, name: str) -> None: + self.tool = _Tool(name) + self.args = _Args() + + +class _Resp: + """Minimal stand-in for ModelResponse exercised by run().""" + + def __init__(self, *, content=None, reasoning_content=None, tool_calls=None) -> None: + self.content = content + self.reasoning_content = reasoning_content + self.tool_calls = tool_calls + + +def _syntax_err() -> ModelSyntaxError: + return ModelSyntaxError("bad ReAct") + + +def _action() -> _Resp: + """A valid parsed response that carries a tool call (no final answer).""" + return _Resp(reasoning_content="thought", tool_calls=[_ToolCall("some_tool")]) + + +def _final() -> _Resp: + return _Resp(content="final answer") + + +class _ScriptedLeader: + """LeaderAgent stub whose dialog methods pop a scripted queue. + + Each queue holds either a _Resp (returned) or a ModelSyntaxError (raised). + """ + + def __init__(self) -> None: + self.begin_dialog_q: list = [] + self.send_correction_q: list = [] + self.continue_dialog_q: list = [] + self.call_tool_q: list = [] + + @staticmethod + def _pop(queue: list): + item = queue.pop(0) + if isinstance(item, Exception): + raise item + return item + + async def begin_dialog(self, task, trace_ctx=None): + return self._pop(self.begin_dialog_q) + + async def send_correction(self, message, trace_ctx=None): + return self._pop(self.send_correction_q) + + async def continue_dialog(self, prior_response, observation, trace_ctx=None): + return self._pop(self.continue_dialog_q) + + async def _call_tool(self, tool_call): + return self._pop(self.call_tool_q) + + +async def _noop_dialog_changed(*args, **kwargs) -> None: + pass + + +async def _drive(leader: _ScriptedLeader) -> str: + """Run one LeaderDriven.run() dialog and return its final status. + + Bypasses LeaderDriven.__init__ (which needs cfg/apis/model_client); run() + only touches the attributes wired up here. + """ + pattern = LeaderDriven.__new__(LeaderDriven) + pattern.dialog_counter = 1 + pattern._summarize_task = None # type: ignore[attr-defined] + pattern.log_info = lambda *a, **k: None # type: ignore[assignment] + pattern.log_error = lambda *a, **k: None # type: ignore[assignment] + pattern.dialog_changed = _noop_dialog_changed # type: ignore[assignment] + pattern.leader_agent = leader # type: ignore[assignment] + + captured: dict = {} + + async def _record(*args) -> None: + # _background_summarize_and_store(dialog_id, task, dialog_context) + captured["ctx"] = args[-1] + + pattern._background_summarize_and_store = _record # type: ignore[assignment] + + await pattern.run("do the thing") + await pattern._summarize_task # type: ignore[attr-defined] + return captured["ctx"]["status"] + + +def test_cumulative_errors_with_recovery_complete(): + """>=3 total syntax errors, each recovered from, must NOT abort. + + Under the old cumulative counting this sequence aborted at the third error + (status "failed"); with the reset-on-recovery it completes. + """ + leader = _ScriptedLeader() + leader.begin_dialog_q = [_syntax_err()] + # Three recoveries at site (a), each producing a valid tool call: + leader.send_correction_q = [_action(), _action(), _action()] + leader.call_tool_q = ["ok", "ok", "ok"] + # Two errors interleaved, then a final answer on the third continue: + leader.continue_dialog_q = [_syntax_err(), _syntax_err(), _final()] + + status = asyncio.run(_drive(leader)) + + assert status == "completed" + + +def test_consecutive_errors_still_abort(): + """Three consecutive syntax errors (no recovery) must still abort.""" + leader = _ScriptedLeader() + leader.begin_dialog_q = [_syntax_err()] + leader.send_correction_q = [_syntax_err(), _syntax_err()] + + status = asyncio.run(_drive(leader)) + + assert status == "failed" + # Sanity: we exercised the abort threshold, not some other failure path. + assert len(leader.send_correction_q) == 0 diff --git a/flake.nix b/flake.nix index 2404d9c5..90a10901 100644 --- a/flake.nix +++ b/flake.nix @@ -153,7 +153,6 @@ UV_PYTHON = python.interpreter; # JDK configuration JAVA_HOME = pkgs.jdk21.home; - JAVA8_HOME = pkgs.jdk8.home; } // lib.optionalAttrs pkgs.stdenv.isLinux { # Python libraries often load native shared objects using dlopen(3). @@ -206,7 +205,6 @@ # JDK configuration JAVA_HOME = pkgs.jdk21.home; - JAVA8_HOME = pkgs.jdk8.home; }; shellHook = '' diff --git a/justfile b/justfile index 1c5529f0..c1d9f1cf 100644 --- a/justfile +++ b/justfile @@ -2,7 +2,6 @@ # # JDK configuration (set via flake.nix env vars): # JAVA_HOME -> JDK 21 (builds the single JAR: core -> Java 8 bytecode, MCP -> Java 17) -# JAVA8_HOME -> JDK 8 (only for ad-hoc Java 8 downgrade checks; not required to build) default: @just --list @@ -23,6 +22,15 @@ build-plugin: clean-plugin: cd plugin && mvn clean +# Test: run the Java unit tests (surefire). No Fiji/ImageJ runtime needed. +test-plugin: + cd plugin && mvn test + +# Test + coverage: JaCoCo prepare-agent is already bound by pom-scijava-base, +# so `mvn test` produces jacoco.exec; invoke report explicitly for the HTML. +test-cov-plugin: + cd plugin && mvn test jacoco:report + copy-plugin-deps: cd plugin && mvn dependency:copy-dependencies -DoutputDirectory=target/deps @@ -35,13 +43,15 @@ build-web: run-workflow: scripts/run-workflow.sh -test: +test: test-python test-plugin + +test-python: uv run --with pytest \ pytest \ --doctest-modules --ignore=examples \ --pyargs copilotj -test-cov: +test-pythn-cov: uv run --with pytest --with pytest-cov \ pytest \ --doctest-modules --ignore=examples \ diff --git a/plugin/pom.xml b/plugin/pom.xml index d5387872..dfccfdbc 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -5,7 +5,7 @@ org.scijava pom-scijava - 38.0.1 + 40.0.0 @@ -248,6 +248,18 @@ ij1-patcher provided + + + + org.junit.jupiter + junit-jupiter + ${junit-jupiter.version} + test + diff --git a/plugin/src/main/java/copilotj/awt/Action.java b/plugin/src/main/java/copilotj/awt/Action.java index 5dddffb8..c9dd047d 100644 --- a/plugin/src/main/java/copilotj/awt/Action.java +++ b/plugin/src/main/java/copilotj/awt/Action.java @@ -111,7 +111,7 @@ protected ParameterSchema(final String type, final String name, final String des * Validates the given value against this parameter's schema. * * @param value The value to validate. - * @return A list of error messages. An empty list indicates the value is valid. + * @return A list of error messages, or null if the value is valid. */ public abstract List validate(Object value); } @@ -146,12 +146,13 @@ public StringParameterSchema(final String name, final String description, final // but for now, we'll assume it's a valid regex string if provided. this.pattern = pattern; - if (enumValues != null && enumValues.isEmpty()) { - // Ensure no nulls or empty strings in enumValues + if (enumValues != null) { + // Reject null entries. Blank strings are legitimate widget labels (e.g. an + // AWT Choice/List placeholder item passed via ChoiceNode/ListNode.getActions()), + // so they must NOT be rejected here. for (final String value : enumValues) { - if (value == null || value.isEmpty()) { - throw new IllegalArgumentException( - "Enum values cannot contain null or empty strings for parameter: " + name); + if (value == null) { + throw new IllegalArgumentException("Enum values cannot contain null for parameter: " + name); } } } @@ -281,7 +282,7 @@ public List validate(final Object value) { errors.add("Invalid type. Expected boolean, got " + value.getClass().getSimpleName()); } } - return errors; + return errors.isEmpty() ? null : errors; } } diff --git a/plugin/src/main/java/copilotj/awt/window/IjImage.java b/plugin/src/main/java/copilotj/awt/window/IjImage.java index 4077b69e..3ac2fe6f 100644 --- a/plugin/src/main/java/copilotj/awt/window/IjImage.java +++ b/plugin/src/main/java/copilotj/awt/window/IjImage.java @@ -10,8 +10,10 @@ import java.awt.Window; import java.awt.image.BufferedImage; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; +import java.util.Properties; import ij.ImagePlus; import ij.gui.ImageWindow; @@ -46,6 +48,7 @@ public static class Difference extends AbstractAwtWindow.Difference { public final FromTo imageType; public final FromTo size; public final FromTo path; + public final FromTo info; public final FromTo bitDepth; public final FromTo stackSize; @@ -81,6 +84,7 @@ public Difference(final IjImage from, final IjImage to, final boolean imageUpdat this.imageType = !Objects.equals(from.imageType, to.imageType) ? new FromTo<>(from.imageType, to.imageType) : null; this.size = !Objects.equals(from.size, to.size) ? new FromTo<>(from.size, to.size) : null; this.path = !Objects.equals(from.path, to.path) ? new FromTo<>(from.path, to.path) : null; + this.info = !Objects.equals(from.info, to.info) ? new FromTo<>(from.info, to.info) : null; this.bitDepth = !Objects.equals(from.bitDepth, to.bitDepth) ? new FromTo<>(from.bitDepth, to.bitDepth) : null; this.stackSize = !Objects.equals(from.stackSize, to.stackSize) ? new FromTo<>(from.stackSize, to.stackSize) : null; @@ -277,6 +281,7 @@ public static ImagePreviewWithInfo captureImage(final WindowIdentifier identifie public final String imageType; public final String size; public final String path; + public final String info; public final int bitDepth; public final int stackSize; @@ -328,6 +333,7 @@ public IjImage(final WindowIdentifier identifier, final ImageWindow w) { } } this.path = path; + this.info = buildImageMetadata(imp); this.bitDepth = imp.getBitDepth(); this.stackSize = imp.getStackSize(); @@ -362,12 +368,60 @@ public IjImage(final WindowIdentifier identifier, final ImageWindow w) { } } + /** Maximum characters captured for the image metadata block. Bounds leader context and snapshot + * diff churn from volatile or large metadata (e.g. OME-XML stored in the "Info" property). */ + private static final int INFO_MAX_CHARS = 4000; + private static final String INFO_TRUNCATION_MARKER = "\n... [truncated, full metadata omitted]"; + + /** Assemble a readable, multi-line metadata block from the image's "Info" property, every other + * String-valued property, and the FileInfo description. Sources are deduped by exact whole-string + * equality (Info first); returns null when no metadata is present so the field stays absent. */ + private static String buildImageMetadata(final ImagePlus imp) { + final LinkedHashSet blocks = new LinkedHashSet<>(); + + // 1. The "Info" property — full text, no line filtering. + final String infoProp = (String) imp.getProperty("Info"); + if (infoProp != null && !infoProp.trim().isEmpty()) { + blocks.add(infoProp.trim()); + } + + // 2. Every other String-valued property (skip "Info", already captured; "HideInfo" is a UI flag). + final Properties props = imp.getProperties(); + if (props != null) { + for (final String key : props.stringPropertyNames()) { + if ("Info".equals(key) || "HideInfo".equals(key)) { + continue; + } + final String value = props.getProperty(key); + if (value != null && !value.isEmpty()) { + blocks.add(key + ": " + value); + } + } + } + + // 3. FileInfo.description — the raw file header; independent of the "Info" property. + final FileInfo fi = imp.getOriginalFileInfo(); + if (fi != null && fi.description != null && !fi.description.trim().isEmpty()) { + blocks.add(fi.description.trim()); + } + + if (blocks.isEmpty()) { + return null; + } + String result = String.join("\n", blocks); + if (result.length() > INFO_MAX_CHARS) { + result = result.substring(0, INFO_MAX_CHARS) + INFO_TRUNCATION_MARKER; + } + return result; + } + public boolean equals(final IjImage other) { return this.id == other.id && Objects.equals(this.title, other.title) && Objects.equals(this.type, other.type) && Objects.equals(this.size, other.size) && Objects.equals(this.path, other.path) + && Objects.equals(this.info, other.info) && this.bitDepth == other.bitDepth && this.stackSize == other.stackSize diff --git a/plugin/src/main/java/copilotj/util/Trie.java b/plugin/src/main/java/copilotj/util/Trie.java index 08074568..b5618105 100644 --- a/plugin/src/main/java/copilotj/util/Trie.java +++ b/plugin/src/main/java/copilotj/util/Trie.java @@ -261,7 +261,6 @@ private SimpleMap nodeToSimpleMap(final Node node, final KeyCombiner childNode = onlyChild.getValue(); } } - System.out.println(word); map.put(word, nodeToSimpleMap(childNode, combiner)); } return map; diff --git a/plugin/src/test/java/copilotj/BoundedLogTest.java b/plugin/src/test/java/copilotj/BoundedLogTest.java new file mode 100644 index 00000000..b789fde0 --- /dev/null +++ b/plugin/src/test/java/copilotj/BoundedLogTest.java @@ -0,0 +1,92 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link BoundedLog}, a synchronized append-only log with a soft + * char cap. Lives in package {@code copilotj} so it can reference the + * package-private {@link BoundedLog#MAX_CHARS} directly. + */ +public class BoundedLogTest { + + @Test + public void snapshotEmptyAfterConstruction() { + assertEquals("", new BoundedLog().snapshot()); + } + + @Test + public void appendIgnoresNull() { + final BoundedLog log = new BoundedLog(); + log.append(null); + assertEquals("", log.snapshot()); + } + + @Test + public void appendIgnoresEmpty() { + final BoundedLog log = new BoundedLog(); + log.append(""); + assertEquals("", log.snapshot()); + } + + @Test + public void appendAndSnapshotJoinsInOrder() { + final BoundedLog log = new BoundedLog(); + log.append("a"); + log.append("b"); + log.append("c"); + assertEquals("abc", log.snapshot()); + } + + @Test + public void clearEmptiesLog() { + final BoundedLog log = new BoundedLog(); + log.append("x"); + log.clear(); + assertEquals("", log.snapshot()); + } + + @Test + public void evictsOldestChunksOverCap() { + // Four MAX_CHARS/4 chunks fill exactly to the cap; a fifth evicts the oldest. + final BoundedLog log = new BoundedLog(); + final int chunk = BoundedLog.MAX_CHARS / 4; + log.append(repeat('1', chunk)); + log.append(repeat('2', chunk)); + log.append(repeat('3', chunk)); + log.append(repeat('4', chunk)); + final String newest = repeat('5', chunk); + log.append(newest); + + final String snap = log.snapshot(); + assertTrue(snap.endsWith(newest), "newest chunk must be fully retained"); + assertFalse(snap.startsWith(repeat('1', chunk)), "oldest chunk must be evicted"); + assertTrue(snap.length() <= BoundedLog.MAX_CHARS, "total retained must stay under the cap"); + } + + @Test + public void alwaysKeepsAtLeastOneChunkEvenWhenOverCap() { + // A single append larger than MAX_CHARS is never evicted (size > 1 guard). + final BoundedLog log = new BoundedLog(); + final String huge = repeat('z', BoundedLog.MAX_CHARS + 100); + log.append(huge); + assertEquals(huge.length(), log.snapshot().length()); + } + + private static String repeat(final char c, final int n) { + final char[] arr = new char[n]; + Arrays.fill(arr, c); + return new String(arr); + } +} diff --git a/plugin/src/test/java/copilotj/awt/ActionBuilderTest.java b/plugin/src/test/java/copilotj/awt/ActionBuilderTest.java new file mode 100644 index 00000000..01cd69cc --- /dev/null +++ b/plugin/src/test/java/copilotj/awt/ActionBuilderTest.java @@ -0,0 +1,95 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.awt; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import copilotj.awt.Action.Builder; + +/** + * Unit tests for {@link Action.Builder} construction and {@link Action} assembly. + */ +public class ActionBuilderTest { + + @Test + public void builderRejectsNullType() { + assertThrows(IllegalStateException.class, () -> Action.builder(null, "n", "d")); + } + + @Test + public void builderRejectsNullName() { + assertThrows(IllegalStateException.class, () -> Action.builder("t", null, "d")); + } + + @Test + public void builderRejectsNullDescription() { + assertThrows(IllegalStateException.class, () -> Action.builder("t", "n", null)); + } + + @Test + public void builderAcceptsAllNonNull() { + assertNotNull(Action.builder("t", "n", "d")); + } + + @Test + public void buildCopiesFieldsAndStartsEmpty() { + final Action a = Action.builder("t", "n", "d").build(); + assertEquals("t", a.type); + assertEquals("n", a.name); + assertEquals("d", a.description); + assertTrue(a.parameters.isEmpty()); + assertTrue(a.path.isEmpty()); + } + + @Test + public void addStringParameterEnumOverloadRejectsNull() { + final Builder b = Action.builder("t", "n", "d"); + assertThrows(IllegalArgumentException.class, () -> b.addStringParameter("p", "d", (List) null)); + } + + @Test + public void addStringParameterEnumOverloadRejectsEmpty() { + final Builder b = Action.builder("t", "n", "d"); + assertThrows(IllegalArgumentException.class, () -> b.addStringParameter("p", "d", Collections.emptyList())); + } + + @Test + public void addPathAppendsInPlace() { + final Action a = Action.builder("t", "n", "d").build(); + a.addPath("x"); + a.addPath("y"); + assertEquals(Arrays.asList("x", "y"), a.path); + } + + @Test + public void descriptionIsMutableOnBuiltAction() { + // description is the only non-final Action field. + final Action a = Action.builder("t", "n", "d").build(); + a.description = "new"; + assertEquals("new", a.description); + } + + @Test + public void chainingReturnsSelfAndBuilds() { + final Action a = Action.builder("t", "n", "d") + .addStringParameter("s", "desc") + .addBooleanParameter("b", "desc") + .addIntegerParameter("i", "desc") + .addNumberParameter("n2", "desc") + .build(); + assertEquals(4, a.parameters.size()); + } +} diff --git a/plugin/src/test/java/copilotj/awt/ParameterSchemaTest.java b/plugin/src/test/java/copilotj/awt/ParameterSchemaTest.java new file mode 100644 index 00000000..cf5221b2 --- /dev/null +++ b/plugin/src/test/java/copilotj/awt/ParameterSchemaTest.java @@ -0,0 +1,103 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.awt; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * Constructor-invariant tests for the {@link Action.ParameterSchema} hierarchy. + * Schemas are constructed directly (not via the Builder) to exercise the + * constructors' own validation. + */ +public class ParameterSchemaTest { + + // --- base ParameterSchema name validation --- + + @Test + public void baseRejectsNullName() { + assertThrows(IllegalArgumentException.class, () -> new Action.BooleanParameterSchema(null, "d")); + } + + @Test + public void baseRejectsEmptyName() { + assertThrows(IllegalArgumentException.class, () -> new Action.BooleanParameterSchema("", "d")); + } + + // --- StringParameterSchema bounds --- + + @Test + public void stringRejectsNegativeMinLength() { + assertThrows(IllegalArgumentException.class, + () -> new Action.StringParameterSchema("p", "d", -1, null, null, null)); + } + + @Test + public void stringRejectsNegativeMaxLength() { + assertThrows(IllegalArgumentException.class, + () -> new Action.StringParameterSchema("p", "d", null, -5, null, null)); + } + + @Test + public void stringRejectsInvertedMinMax() { + assertThrows(IllegalArgumentException.class, + () -> new Action.StringParameterSchema("p", "d", 5, 2, null, null)); + } + + @Test + public void stringAcceptsNullOptionals() { + assertNotNull(new Action.StringParameterSchema("p", "d", null, null, null, null)); + } + + // Regression guard: enum-list null entries are rejected at construction (the guard was + // previously inverted dead code). Blank strings are ACCEPTED because they are legitimate + // widget labels (AWT Choice/List placeholder items) — see ChoiceNode/ListNode.getActions(). + + @Test + public void stringRejectsEnumListWithNullEntry() { + final List bad = Arrays.asList("ok", null); + assertThrows(IllegalArgumentException.class, + () -> new Action.StringParameterSchema("p", "d", null, null, null, bad)); + } + + @Test + public void stringAcceptsEnumListWithBlankEntry() { + // Blank entries must be accepted: ChoiceNode/ListNode pass AWT item lists here and a + // blank placeholder item is valid. Rejecting it would crash getActions()/snapshot generation. + final List vals = Arrays.asList("ok", ""); + assertNotNull(new Action.StringParameterSchema("p", "d", null, null, null, vals)); + } + + // --- IntegerParameterSchema --- + + @Test + public void integerRejectsInvertedMinMax() { + assertThrows(IllegalArgumentException.class, () -> new Action.IntegerParameterSchema("p", "d", 10, 1)); + } + + @Test + public void integerAcceptsNullBounds() { + assertNotNull(new Action.IntegerParameterSchema("p", "d", null, null)); + } + + // --- NumberParameterSchema --- + + @Test + public void numberRejectsInvertedMinMax() { + assertThrows(IllegalArgumentException.class, () -> new Action.NumberParameterSchema("p", "d", 10.0, 1.0)); + } + + @Test + public void numberAcceptsNullBounds() { + assertNotNull(new Action.NumberParameterSchema("p", "d", null, null)); + } +} diff --git a/plugin/src/test/java/copilotj/awt/ParameterSchemaValidateTest.java b/plugin/src/test/java/copilotj/awt/ParameterSchemaValidateTest.java new file mode 100644 index 00000000..df0f7d5a --- /dev/null +++ b/plugin/src/test/java/copilotj/awt/ParameterSchemaValidateTest.java @@ -0,0 +1,162 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.awt; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link Action.ParameterSchema#validate(Object)} across all four + * subclasses. Contract: a valid value returns {@code null}; an invalid value + * returns a non-empty error list (never an empty list). + */ +public class ParameterSchemaValidateTest { + + private static void assertInvalid(final List errors, final String containsFragment) { + assertNotNull(errors, "invalid value must return a non-null error list"); + assertFalse(errors.isEmpty(), "invalid value must return a non-empty error list"); + if (containsFragment != null) { + assertTrue( + errors.stream().anyMatch(e -> e.contains(containsFragment)), + "expected an error containing \"" + containsFragment + "\", got " + errors); + } + } + + // ===== String ===== + + @Test + public void stringValidReturnsNull() { + assertNull(new Action.StringParameterSchema("p", "d", null, null, null, null).validate("ok")); + } + + @Test + public void stringNullReturnsTypeError() { + assertInvalid(new Action.StringParameterSchema("p", "d", null, null, null, null).validate(null), "cannot be null"); + } + + @Test + public void stringWrongTypeReportsSimpleClassName() { + final List errors = + new Action.StringParameterSchema("p", "d", null, null, null, null).validate(Integer.valueOf(5)); + assertInvalid(errors, "got Integer"); + assertEquals(1, errors.size(), "type mismatch returns early with a single error"); + } + + @Test + public void stringTooShort() { + assertInvalid(new Action.StringParameterSchema("p", "d", 3, null, null, null).validate("ab"), "less than minimum"); + } + + @Test + public void stringTooLong() { + assertInvalid(new Action.StringParameterSchema("p", "d", null, 3, null, null).validate("abcd"), "greater than maximum"); + } + + @Test + public void stringPatternMismatch() { + assertInvalid(new Action.StringParameterSchema("p", "d", null, null, "[0-9]+", null).validate("abc"), + "does not match pattern"); + } + + @Test + public void stringNotInEnum() { + assertInvalid(new Action.StringParameterSchema("p", "d", null, null, null, Arrays.asList("a", "b")).validate("c"), + "not in the allowed enum"); + } + + @Test + public void stringEnumBoundaryValid() { + assertNull(new Action.StringParameterSchema("p", "d", null, null, null, Arrays.asList("a", "b")).validate("a")); + } + + // ===== Integer ===== + + @Test + public void integerValidReturnsNull() { + assertNull(new Action.IntegerParameterSchema("p", "d", null, null).validate(Integer.valueOf(3))); + } + + @Test + public void integerNullReturnsTypeError() { + assertInvalid(new Action.IntegerParameterSchema("p", "d", null, null).validate(null), "cannot be null"); + } + + @Test + public void integerRejectsLong() { + // Only java.lang.Integer is accepted; a Long reports a type error. + final List errors = + new Action.IntegerParameterSchema("p", "d", null, null).validate(Long.valueOf(3L)); + assertInvalid(errors, "got Long"); + } + + @Test + public void integerBelowMinimum() { + assertInvalid(new Action.IntegerParameterSchema("p", "d", 0, null).validate(Integer.valueOf(-1)), "less than minimum"); + } + + @Test + public void integerAboveMaximum() { + assertInvalid(new Action.IntegerParameterSchema("p", "d", null, 10).validate(Integer.valueOf(11)), "greater than maximum"); + } + + // ===== Number ===== + + @Test + public void numberAcceptsInteger() { + assertNull(new Action.NumberParameterSchema("p", "d", null, null).validate(Integer.valueOf(3))); + } + + @Test + public void numberAcceptsDouble() { + assertNull(new Action.NumberParameterSchema("p", "d", null, null).validate(Double.valueOf(3.5))); + } + + @Test + public void numberNullReturnsTypeError() { + assertInvalid(new Action.NumberParameterSchema("p", "d", null, null).validate(null), "cannot be null"); + } + + @Test + public void numberBelowMinimum() { + assertInvalid(new Action.NumberParameterSchema("p", "d", 0.0, null).validate(Double.valueOf(-1.0)), "less than minimum"); + } + + @Test + public void numberAboveMaximum() { + assertInvalid(new Action.NumberParameterSchema("p", "d", null, 1.0).validate(Double.valueOf(2.5)), "greater than maximum"); + } + + // ===== Boolean (regression: valid -> null, NOT an empty list) ===== + + @Test + public void booleanValidTrueReturnsNull() { + assertNull(new Action.BooleanParameterSchema("p", "d").validate(Boolean.TRUE)); + } + + @Test + public void booleanValidFalseReturnsNull() { + assertNull(new Action.BooleanParameterSchema("p", "d").validate(Boolean.FALSE)); + } + + @Test + public void booleanNullReturnsTypeError() { + assertInvalid(new Action.BooleanParameterSchema("p", "d").validate(null), "cannot be null"); + } + + @Test + public void booleanWrongTypeReportsSimpleClassName() { + assertInvalid(new Action.BooleanParameterSchema("p", "d").validate("yes"), "got String"); + } +} diff --git a/plugin/src/test/java/copilotj/util/FlexibleLocalDateTimeDeserializerTest.java b/plugin/src/test/java/copilotj/util/FlexibleLocalDateTimeDeserializerTest.java new file mode 100644 index 00000000..57be5ceb --- /dev/null +++ b/plugin/src/test/java/copilotj/util/FlexibleLocalDateTimeDeserializerTest.java @@ -0,0 +1,102 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Unit tests for {@link FlexibleLocalDateTimeDeserializer}. Exercised through a + * real {@link ObjectMapper} (no mock) so the production {@code JsonParser} path + * runs. Expected offset-aware values are computed via the same chain the + * implementation uses, so the assertions are zone-agnostic. + */ +public class FlexibleLocalDateTimeDeserializerTest { + + /** Plain static holder (NOT a record — tests compile under Java 8). */ + public static final class Holder { + @JsonProperty("t") + public LocalDateTime t; + } + + private static ObjectMapper mapper() { + final ObjectMapper m = new ObjectMapper(); + final SimpleModule module = new SimpleModule(); + module.addDeserializer(LocalDateTime.class, new FlexibleLocalDateTimeDeserializer()); + m.registerModule(module); + return m; + } + + private static LocalDateTime parse(final String jsonValue) throws Exception { + return mapper().readValue("{\"t\":\"" + jsonValue + "\"}", Holder.class).t; + } + + private static LocalDateTime localAtSystemZone(final String offsetDateTime) { + return OffsetDateTime.parse(offsetDateTime).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + } + + @Test + public void parsesNaiveLocalDateTime() throws Exception { + assertEquals(LocalDateTime.of(2026, 6, 18, 10, 0, 0), parse("2026-06-18T10:00:00")); + } + + @Test + public void parsesUtcZ() throws Exception { + final String s = "2026-06-18T10:00:00Z"; + assertEquals(localAtSystemZone(s), parse(s)); + } + + @Test + public void parsesExplicitPositiveOffset() throws Exception { + final String s = "2026-06-18T18:00:00+08:00"; + assertEquals(localAtSystemZone(s), parse(s)); + } + + @Test + public void parsesNegativeOffset() throws Exception { + final String s = "2026-06-18T05:00:00-05:00"; + assertEquals(localAtSystemZone(s), parse(s)); + } + + @Test + public void trimsWhitespace() throws Exception { + assertEquals(LocalDateTime.of(2026, 6, 18, 10, 0, 0), parse(" 2026-06-18T10:00:00 ")); + } + + @Test + public void returnsNullForJsonNull() throws Exception { + final Holder h = mapper().readValue("{\"t\":null}", Holder.class); + assertNull(h.t); + } + + @Test + public void returnsNullForEmptyAfterTrim() throws Exception { + assertNull(parse(" ")); + } + + @Test + public void rejectsDateOnly() { + // No time component -> LocalDateTime.parse throws, propagating out of readValue. + assertThrows(Exception.class, () -> parse("2026-06-18")); + } + + @Test + public void rejectsGarbage() { + assertThrows(Exception.class, () -> parse("not-a-date")); + } +} diff --git a/plugin/src/test/java/copilotj/util/FromToTest.java b/plugin/src/test/java/copilotj/util/FromToTest.java new file mode 100644 index 00000000..07f2027b --- /dev/null +++ b/plugin/src/test/java/copilotj/util/FromToTest.java @@ -0,0 +1,56 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link FromTo}, a minimal generic value pair with no validation + * and no defined {@code equals}. + */ +public class FromToTest { + + @Test + public void holdsFromAndToValues() { + final FromTo ft = new FromTo<>(1, 2); + assertEquals(1, ft.from); + assertEquals(2, ft.to); + } + + @Test + public void acceptsNullOnBothEnds() { + final FromTo ft = new FromTo<>(null, null); + assertNull(ft.from); + assertNull(ft.to); + } + + @Test + public void acceptsNullOnOneEnd() { + final FromTo ft = new FromTo<>(null, "x"); + assertNull(ft.from); + assertEquals("x", ft.to); + } + + @Test + public void worksAsStringPair() { + final FromTo ft = new FromTo<>("a", "b"); + assertEquals("a", ft.from); + assertEquals("b", ft.to); + } + + @Test + public void distinctInstancesAreNotEqualByReference() { + // FromTo defines no equals; two equal-content instances remain distinct references. + final FromTo a = new FromTo<>(1, 2); + final FromTo b = new FromTo<>(1, 2); + assertNotSame(a, b); + } +} diff --git a/plugin/src/test/java/copilotj/util/JsonBase64ImageTruncatorTest.java b/plugin/src/test/java/copilotj/util/JsonBase64ImageTruncatorTest.java new file mode 100644 index 00000000..885f80d6 --- /dev/null +++ b/plugin/src/test/java/copilotj/util/JsonBase64ImageTruncatorTest.java @@ -0,0 +1,101 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link JsonBase64ImageTruncator}, a pure regex/string utility + * with no ImageJ coupling. + */ +public class JsonBase64ImageTruncatorTest { + + private static final String LONG = "AAAAAAAAAAAAAAAAAAAA"; // 20 chars + + @Test + public void truncatesLongBase64Content() { + final String json = "{\"img\":\"data:image/png;base64," + LONG + "\"}"; + // maxLength 16 -> keep max(0, 16-3)=13 chars, then append "...". + final String expected = "{\"img\":\"data:image/png;base64,AAAAAAAAAAAAA...\"}"; + assertEquals(expected, new JsonBase64ImageTruncator(json, 16).toString()); + } + + @Test + public void leavesShortContentUntouched() { + final String content = "AAAAAAAAAA"; // 10 chars, <= 16 + final String json = "{\"img\":\"data:image/png;base64," + content + "\"}"; + assertEquals(json, new JsonBase64ImageTruncator(json, 16).toString()); + } + + @Test + public void contentExactlyAtMaxLengthIsUntouched() { + // Production truncates only when content.length() > maxLength (strict). Pin the + // exact boundary so an off-by-one flip to >= would be caught. + final String content = "AAAAAAAAAAAAAAAA"; // 16 chars == maxLength + final String json = "{\"img\":\"data:image/png;base64," + content + "\"}"; + assertEquals(json, new JsonBase64ImageTruncator(json, 16).toString()); + } + + @Test + public void noMatchReturnsOriginal() { + final String json = "{\"msg\":\"hello world\"}"; + assertEquals(json, new JsonBase64ImageTruncator(json, 16).toString()); + } + + @Test + public void truncatesEveryMatch() { + final String json = "{\"a\":\"data:image/png;base64," + LONG + "\"," + + "\"b\":\"data:image/jpeg;base64," + LONG + "\"}"; + final String result = new JsonBase64ImageTruncator(json, 16).toString(); + assertEquals(2, countOccurrences(result, "...")); + } + + @Test + public void maxLengthBelowThreeCollapsesToEllipsis() { + final String json = "{\"img\":\"data:image/png;base64," + LONG + "\"}"; + // max(0, 2-3)=0 -> substring(0,0) + "...". + assertEquals("{\"img\":\"data:image/png;base64,...\"}", + new JsonBase64ImageTruncator(json, 2).toString()); + } + + @Test + public void withTitlePrependsTitle() { + final String json = "{\"img\":\"data:image/png;base64," + LONG + "\"}"; + // WithTitle hardcodes maxLength = 16. + final String result = new JsonBase64ImageTruncator.WithTitle("img", json).toString(); + assertEquals("img: {\"img\":\"data:image/png;base64,AAAAAAAAAAAAA...\"}", result); + } + + @Test + public void staticHelperMatchesInstance() { + final String json = "{\"img\":\"data:image/png;base64," + LONG + "\"}"; + final String viaStatic = JsonBase64ImageTruncator.truncateJsonBase64(json, 16); + final String viaInstance = new JsonBase64ImageTruncator(json, 16).toString(); + assertEquals(viaInstance, viaStatic); + } + + @Test + public void svgXmlMimeSubtypeIsNotMatchedAndPassesThrough() { + // The regex matches only image/\w+ (single-token MIME), so a structured subtype + // like image/svg+xml does NOT match and is left intact. Known limitation; + // broadening the regex is tracked as a follow-up. + final String json = "{\"img\":\"data:image/svg+xml;base64," + LONG + "\"}"; + assertEquals(json, new JsonBase64ImageTruncator(json, 4).toString()); + } + + private static int countOccurrences(final String haystack, final String needle) { + int count = 0; + int idx = 0; + while ((idx = haystack.indexOf(needle, idx)) != -1) { + count++; + idx += needle.length(); + } + return count; + } +} diff --git a/plugin/src/test/java/copilotj/util/TrieTest.java b/plugin/src/test/java/copilotj/util/TrieTest.java new file mode 100644 index 00000000..13983ffd --- /dev/null +++ b/plugin/src/test/java/copilotj/util/TrieTest.java @@ -0,0 +1,129 @@ +/** + * SPDX-FileCopyrightText: Copyright contributors to the CopilotJ project. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package copilotj.util; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +import copilotj.util.Trie.CharTrie; +import copilotj.util.Trie.SentenceTrie; +import copilotj.util.Trie.WordTrie; + +/** + * Unit tests for the pure-logic {@link Trie} data structure. {@link Trie} has no + * ImageJ/AWT/runtime coupling, so it can be exercised directly. + */ +// Raw Trie.Map / Trie.SimpleMap are inner generic types; unchecked access is by design here. +@SuppressWarnings("rawtypes") +public class TrieTest { + + @Test + public void charTrieInsertSearchAndPrefix() { + final CharTrie trie = new CharTrie(); + trie.insert("apple"); + + assertTrue(trie.search("apple"), "exact sentence should be found"); + assertFalse(trie.search("app"), "non-leaf prefix should not satisfy search"); + assertTrue(trie.startsWith("app"), "prefix should be detected"); + assertFalse(trie.startsWith("b"), "unknown prefix"); + assertFalse(new CharTrie().search("x"), "empty trie lookup handled"); + } + + @Test + public void charTrieSharedPrefixDoesNotInterfere() { + final CharTrie trie = new CharTrie(); + trie.insert("app"); + trie.insert("apple"); + + assertTrue(trie.search("app")); + assertTrue(trie.search("apple")); + assertFalse(trie.search("ap")); + } + + @Test + public void duplicateInsertIsIdempotent() { + final CharTrie trie = new CharTrie(); + trie.insert("abc"); + trie.insert("abc"); + + assertTrue(trie.search("abc")); + } + + @Test + public void wordTrieSearchAndPrefix() { + final WordTrie trie = new WordTrie(); + trie.insert(new String[] {"a", "b", "c"}); + + assertTrue(trie.search(new String[] {"a", "b", "c"})); + assertFalse(trie.search(new String[] {"a", "b"})); + assertTrue(trie.startsWith(new String[] {"a", "b"})); + assertFalse(trie.startsWith(new String[] {"x"})); + } + + @Test + public void wordTrieToMapWithFlattenCollapsesSingleChildChains() { + // root -> a -> b -> {c (leaf), d (leaf)}; the single-child a->b chain is + // flattened into the combined key "ab". + final WordTrie trie = new WordTrie(); + trie.insert(new String[] {"a", "b", "c"}); + trie.insert(new String[] {"a", "b", "d"}); + + final Trie.Map flattened = trie.toMapWithFlatten(); + assertNotNull(flattened.children); + assertTrue(flattened.children.containsKey("ab"), "flattened single-child chain should produce key 'ab'"); + + final Trie.Map ab = (Trie.Map) flattened.children.get("ab"); + assertNotNull(ab.children); + assertTrue(ab.children.containsKey("c")); + assertTrue(ab.children.containsKey("d")); + assertTrue(((Trie.Map) ab.children.get("c")).isLeaf, "leaf node c should be marked"); + } + + @Test + public void wordTrieToSimpleMapWithFlattenCollapsesSingleChildChains() { + // nodeToSimpleMap flattens single-child chains via a while-loop (distinct from + // toMap's single-edge flatten). This is the path that previously held a debug + // println, so it is covered explicitly here. + final WordTrie trie = new WordTrie(); + trie.insert(new String[] {"a", "b", "c"}); + trie.insert(new String[] {"a", "b", "d"}); + + final Trie.SimpleMap flattened = trie.toSimpleMapWithFlatten(); + assertTrue(flattened.containsKey("ab"), "flattened single-child chain should produce key 'ab'"); + + final Trie.SimpleMap ab = (Trie.SimpleMap) flattened.get("ab"); + assertTrue(ab.containsKey("c")); + assertTrue(ab.containsKey("d")); + } + + @Test + public void sentenceTrieSplitsOnDelimiters() { + // Delimiters stick to the preceding token: "a/b.c" -> ["a/", "b.", "c"]. + final SentenceTrie trie = new SentenceTrie(new char[] {'/', '.'}); + trie.insert("a/b.c"); + + assertTrue(trie.search("a/b.c"), "full sentence reconstructs"); + assertFalse(trie.search("a/b"), "trailing-delimiter token is significant"); + assertTrue(trie.startsWith("a/"), "prefix token including its delimiter"); + assertTrue(trie.startsWith("a/b."), "prefix across two tokens"); + assertFalse(trie.startsWith("a/b")); + } + + @Test + public void toMapWithFlattenRejectsNullCombiner() { + assertThrows(IllegalArgumentException.class, () -> new WordTrie().toMapWithFlatten(null)); + } + + @Test + public void toSimpleMapWithFlattenRejectsNullCombiner() { + assertThrows(IllegalArgumentException.class, () -> new WordTrie().toSimpleMapWithFlatten(null)); + } +} diff --git a/uv.lock b/uv.lock index 485f57c9..2d01cbf6 100644 --- a/uv.lock +++ b/uv.lock @@ -4206,11 +4206,11 @@ wheels = [ [[package]] name = "pypdf" -version = "6.12.2" +version = "6.13.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/6d/20879428577c1e57ecd41b69dc86beabf43db9287ad2e702207f8b48c751/pypdf-6.12.2.tar.gz", hash = "sha256:111669eb6680c04495ae0c113a1476e3bf93a95761d23c7406b591c80a6490b1", size = 6468184, upload-time = "2026-05-26T13:31:26.911Z" } +sdist = { url = "https://files.pythonhosted.org/packages/17/18/9947cc201af9ccf76720fd3347bf4f70eb882ce3fcf4cb05f7443e4cf871/pypdf-6.13.3.tar.gz", hash = "sha256:f3cb822769725f1bac658c406cfc9460399043f3750c2d3e4650e0a85eacabd7", size = 6484063, upload-time = "2026-06-17T15:22:00.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/44/fee070a16639d9869bb6a7e0f3a1b3946da1d66f32b9260b4d19cb90d7b2/pypdf-6.12.2-py3-none-any.whl", hash = "sha256:67b2699357a1f3f4c945940ea80826349ee507c9e2577724a14b4941982c104d", size = 343865, upload-time = "2026-05-26T13:31:25.068Z" }, + { url = "https://files.pythonhosted.org/packages/94/56/2967e621598987905fb8cdfadd8f8de6b5c68c9351f0523c4df8409f28f1/pypdf-6.13.3-py3-none-any.whl", hash = "sha256:c6e3f86afb625791510b02ad5480e94b63970bb957df75d44657c282ecc52224", size = 347288, upload-time = "2026-06-17T15:21:59.512Z" }, ] [[package]] diff --git a/web/package.json b/web/package.json index 06532830..13109875 100644 --- a/web/package.json +++ b/web/package.json @@ -37,7 +37,7 @@ "prettier-plugin-organize-imports": "^4.3.0", "typescript": "~5.9.3", "unplugin-vue-components": "^32.1.0", - "vite": "^6.4.3", + "vite": "^8.0.12", "vue-tsc": "^3.3.5" }, "prettier": { diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 128607e0..8e719b7a 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -16,16 +16,16 @@ importers: version: 2.0.3 '@tabler/icons-vue': specifier: ^3.44.0 - version: 3.44.0(vue@3.5.38(typescript@5.9.3)) + version: 3.44.0(vue@3.5.39(typescript@5.9.3)) '@tailwindcss/typography': specifier: ^0.5.20 version: 0.5.20(tailwindcss@4.3.1) '@tailwindcss/vite': specifier: ^4.3.1 - version: 4.3.1(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0)) + version: 4.3.1(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0)) '@vueuse/core': specifier: ^14.3.0 - version: 14.3.0(vue@3.5.38(typescript@5.9.3)) + version: 14.3.0(vue@3.5.39(typescript@5.9.3)) date-fns: specifier: ^4.4.0 version: 4.4.0 @@ -43,10 +43,10 @@ importers: version: 2.2.4(marked@18.0.5) pinia: specifier: ^3.0.4 - version: 3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)) + version: 3.0.4(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)) primevue: specifier: ^4.5.5 - version: 4.5.5(vue@3.5.38(typescript@5.9.3)) + version: 4.5.5(vue@3.5.39(typescript@5.9.3)) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 @@ -61,26 +61,26 @@ importers: version: 14.0.0 vue: specifier: ^3.5.38 - version: 3.5.38(typescript@5.9.3) + version: 3.5.39(typescript@5.9.3) vue-router: specifier: ^5.1.0 - version: 5.1.0(@vue/compiler-sfc@3.5.38)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)))(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)) + version: 5.1.0(@vue/compiler-sfc@3.5.39)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)))(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.39(typescript@5.9.3)) devDependencies: '@primevue/auto-import-resolver': specifier: ^4.5.5 version: 4.5.5 '@types/node': specifier: ^26.0.0 - version: 26.0.0 + version: 26.0.1 '@types/uuid': specifier: ^11.0.0 version: 11.0.0 '@vitejs/plugin-vue': specifier: ^6.0.7 - version: 6.0.7(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)) + version: 6.0.7(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.39(typescript@5.9.3)) '@vue/tsconfig': specifier: ^0.9.1 - version: 0.9.1(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)) + version: 0.9.1(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)) prettier-plugin-organize-imports: specifier: ^4.3.0 version: 4.3.0(prettier@3.6.0)(typescript@5.9.3)(vue-tsc@3.3.5(typescript@5.9.3)) @@ -89,10 +89,10 @@ importers: version: 5.9.3 unplugin-vue-components: specifier: ^32.1.0 - version: 32.1.0(vue@3.5.38(typescript@5.9.3)) + version: 32.1.0(vue@3.5.39(typescript@5.9.3)) vite: - specifier: ^6.4.3 - version: 6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + specifier: ^8.0.12 + version: 8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0) vue-tsc: specifier: ^3.3.5 version: 3.3.5(typescript@5.9.3) @@ -137,161 +137,14 @@ packages: resolution: {integrity: sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==} engines: {node: ^22.18.0 || >=24.11.0} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -309,6 +162,15 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@primeuix/styled@0.7.4': resolution: {integrity: sha512-QSO/NpOQg8e9BONWRBx9y8VGMCMYz0J/uKfNJEya/RGEu7ARx0oYW0ugI1N3/KB1AAvyGxzKBzGImbwg0KUiOQ==} engines: {node: '>=12.11.0'} @@ -341,133 +203,103 @@ packages: resolution: {integrity: sha512-ZYLu9m3Nm5BmL0woqCJX84EZfLBepJn+T19v5oj3PlsMpUVNnDAsm2jgYdT6/b3RkdOuccxk4Pg/0EvlATOAhA==} engines: {node: '>=12.11.0'} - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - - '@rollup/rollup-android-arm-eabi@4.62.0': - resolution: {integrity: sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.62.0': - resolution: {integrity: sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==} + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.0': - resolution: {integrity: sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==} + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.0': - resolution: {integrity: sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==} + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.0': - resolution: {integrity: sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.62.0': - resolution: {integrity: sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==} + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.0': - resolution: {integrity: sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.62.0': - resolution: {integrity: sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.62.0': - resolution: {integrity: sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==} + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.0': - resolution: {integrity: sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==} + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.0': - resolution: {integrity: sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.62.0': - resolution: {integrity: sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.62.0': - resolution: {integrity: sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.62.0': - resolution: {integrity: sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==} + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.62.0': - resolution: {integrity: sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.62.0': - resolution: {integrity: sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.62.0': - resolution: {integrity: sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==} + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.0': - resolution: {integrity: sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==} + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.0': - resolution: {integrity: sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==} + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.0': - resolution: {integrity: sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.62.0': - resolution: {integrity: sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==} + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.0': - resolution: {integrity: sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==} - cpu: [arm64] - os: [win32] + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@rollup/rollup-win32-ia32-msvc@4.62.0': - resolution: {integrity: sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==} - cpu: [ia32] + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.0': - resolution: {integrity: sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==} + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.0': - resolution: {integrity: sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==} - cpu: [x64] - os: [win32] + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} '@tabler/icons-vue@3.44.0': resolution: {integrity: sha512-mABxdhq3SWo2ZI77w/t0reiOGNim/SEDSlfMT5PeiWA3cZwnZoQUYRiq/X6SgeTaA7LzCTX0IuvQWVf4RWOvsg==} @@ -515,24 +347,28 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.3.1': resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.3.1': resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.3.1': resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.3.1': resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} @@ -572,14 +408,14 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/jsesc@2.5.1': resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} - '@types/node@26.0.0': - resolution: {integrity: sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==} + '@types/node@26.0.1': + resolution: {integrity: sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==} '@types/uuid@11.0.0': resolution: {integrity: sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA==} @@ -613,56 +449,80 @@ packages: vue: optional: true + '@vue/compiler-core@3.5.30': + resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} + '@vue/compiler-core@3.5.38': resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + '@vue/compiler-core@3.5.39': + resolution: {integrity: sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==} + + '@vue/compiler-dom@3.5.30': + resolution: {integrity: sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==} + '@vue/compiler-dom@3.5.38': resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} - '@vue/compiler-sfc@3.5.38': - resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + '@vue/compiler-dom@3.5.39': + resolution: {integrity: sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==} + + '@vue/compiler-sfc@3.5.30': + resolution: {integrity: sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==} - '@vue/compiler-ssr@3.5.38': - resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} + '@vue/compiler-sfc@3.5.39': + resolution: {integrity: sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==} + + '@vue/compiler-ssr@3.5.30': + resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==} + + '@vue/compiler-ssr@3.5.39': + resolution: {integrity: sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==} '@vue/devtools-api@7.7.9': resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} - '@vue/devtools-api@8.1.3': - resolution: {integrity: sha512-73NMCvxXh8Hyozc/jiwqTFWVcCMyi11U1zmrq4DoukQJnuo8JHt6FsNu4HdeUDa8SpIp5vb7Q22GWgIq0efsXg==} + '@vue/devtools-api@8.1.5': + resolution: {integrity: sha512-YJipMVAKe5wT5CWf5kTYCaNV7NMNjFVxJkIkJaJ4W/nCxEBzlZzrOsYKeCymdCrFZmBS/+wTWFoUs3Jf/Q6XSQ==} '@vue/devtools-kit@7.7.9': resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} - '@vue/devtools-kit@8.1.3': - resolution: {integrity: sha512-cRn7GXiCQkMYU2Z3h3pM4YO/ndbx9FY1yLDAqIqPLcmIq4H6zAOJHein6tvZU3AfPwgrodqLiPBEF+YQaS8AxA==} + '@vue/devtools-kit@8.1.5': + resolution: {integrity: sha512-FcSAxsi4eWuXLCB7Rv9lj0aIVHHPNVQ2BazGf4RJTc2JCqb4BQg0hk87ZFhminCfl+mD5OUI0rX2cgyu4kJOGA==} '@vue/devtools-shared@7.7.9': resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - '@vue/devtools-shared@8.1.3': - resolution: {integrity: sha512-CM3uIPL+v+lrJUk33+pxspYo0MhuMWlCvf7zC9fybifvCPyM2jUbYRPwoYEJgYbwRqPikm5HozbUhp60MF2QuA==} + '@vue/devtools-shared@8.1.5': + resolution: {integrity: sha512-mhT4zcPFhF+Xk1O4BfhhrbXzpmfqY03fS6xGpcllbQG7lDjhQf8pQHcTIhqQIYx1hfwtHmk/6jM96ele0UxPqQ==} '@vue/language-core@3.3.5': resolution: {integrity: sha512-UkKu5nhX89fg4VhlG/FOeI10G3cj/7radKT/cy9BT4Q9qJmJlSTAc/dP63Xqs29aypN4f39xUV6PsLNk/dcD6g==} - '@vue/reactivity@3.5.38': - resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} + '@vue/reactivity@3.5.39': + resolution: {integrity: sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==} - '@vue/runtime-core@3.5.38': - resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} + '@vue/runtime-core@3.5.39': + resolution: {integrity: sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==} - '@vue/runtime-dom@3.5.38': - resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} + '@vue/runtime-dom@3.5.39': + resolution: {integrity: sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==} - '@vue/server-renderer@3.5.38': - resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + '@vue/server-renderer@3.5.39': + resolution: {integrity: sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==} peerDependencies: - vue: 3.5.38 + vue: 3.5.39 + + '@vue/shared@3.5.30': + resolution: {integrity: sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==} '@vue/shared@3.5.38': resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + '@vue/shared@3.5.39': + resolution: {integrity: sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==} + '@vue/tsconfig@0.9.1': resolution: {integrity: sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==} peerDependencies: @@ -687,8 +547,8 @@ packages: peerDependencies: vue: ^3.5.0 - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true @@ -746,11 +606,6 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -834,24 +689,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -869,6 +728,10 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + local-pkg@1.2.1: resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} engines: {node: '>=14'} @@ -893,6 +756,9 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} + mlly@1.8.2: resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} @@ -939,8 +805,8 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - pkg-types@2.3.1: - resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} @@ -979,9 +845,9 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.62.0: - resolution: {integrity: sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true scule@1.3.0: @@ -1018,13 +884,16 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.6.4: - resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} @@ -1054,31 +923,34 @@ packages: resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true - vite@6.4.3: - resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -1121,8 +993,8 @@ packages: peerDependencies: typescript: '>=5.0.0' - vue@3.5.38: - resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} + vue@3.5.39: + resolution: {integrity: sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -1174,82 +1046,20 @@ snapshots: '@babel/helper-string-parser': 8.0.0 '@babel/helper-validator-identifier': 8.0.2 - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-mips64el@0.25.12': - optional: true - - '@esbuild/linux-ppc64@0.25.12': - optional: true - - '@esbuild/linux-riscv64@0.25.12': - optional: true - - '@esbuild/linux-s390x@0.25.12': - optional: true - - '@esbuild/linux-x64@0.25.12': - optional: true - - '@esbuild/netbsd-arm64@0.25.12': - optional: true - - '@esbuild/netbsd-x64@0.25.12': - optional: true - - '@esbuild/openbsd-arm64@0.25.12': - optional: true - - '@esbuild/openbsd-x64@0.25.12': - optional: true - - '@esbuild/openharmony-arm64@0.25.12': - optional: true - - '@esbuild/sunos-x64@0.25.12': - optional: true - - '@esbuild/win32-arm64@0.25.12': + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 optional: true - '@esbuild/win32-ia32@0.25.12': + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/win32-x64@0.25.12': + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 optional: true '@jridgewell/gen-mapping@0.3.13': @@ -1271,6 +1081,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@oxc-project/types@0.133.0': {} + '@primeuix/styled@0.7.4': dependencies: '@primeuix/utils': 0.6.4 @@ -1289,102 +1108,76 @@ snapshots: dependencies: '@primevue/metadata': 4.5.5 - '@primevue/core@4.5.5(vue@3.5.38(typescript@5.9.3))': + '@primevue/core@4.5.5(vue@3.5.39(typescript@5.9.3))': dependencies: '@primeuix/styled': 0.7.4 '@primeuix/utils': 0.6.4 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) - '@primevue/icons@4.5.5(vue@3.5.38(typescript@5.9.3))': + '@primevue/icons@4.5.5(vue@3.5.39(typescript@5.9.3))': dependencies: '@primeuix/utils': 0.6.4 - '@primevue/core': 4.5.5(vue@3.5.38(typescript@5.9.3)) + '@primevue/core': 4.5.5(vue@3.5.39(typescript@5.9.3)) transitivePeerDependencies: - vue '@primevue/metadata@4.5.5': {} - '@rolldown/pluginutils@1.0.1': {} - - '@rollup/rollup-android-arm-eabi@4.62.0': - optional: true - - '@rollup/rollup-android-arm64@4.62.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.62.0': - optional: true - - '@rollup/rollup-darwin-x64@4.62.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.62.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.62.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.62.0': + '@rolldown/binding-android-arm64@1.0.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.0': + '@rolldown/binding-darwin-arm64@1.0.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.0': + '@rolldown/binding-darwin-x64@1.0.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.0': + '@rolldown/binding-freebsd-x64@1.0.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.0': + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.0': + '@rolldown/binding-linux-arm64-gnu@1.0.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.0': + '@rolldown/binding-linux-arm64-musl@1.0.3': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.0': + '@rolldown/binding-linux-ppc64-gnu@1.0.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.0': + '@rolldown/binding-linux-s390x-gnu@1.0.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.0': + '@rolldown/binding-linux-x64-gnu@1.0.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.0': + '@rolldown/binding-linux-x64-musl@1.0.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.0': + '@rolldown/binding-openharmony-arm64@1.0.3': optional: true - '@rollup/rollup-linux-x64-musl@4.62.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.62.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.62.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.62.0': + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.0': + '@rolldown/binding-win32-arm64-msvc@1.0.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.0': + '@rolldown/binding-win32-x64-msvc@1.0.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.0': - optional: true + '@rolldown/pluginutils@1.0.1': {} - '@tabler/icons-vue@3.44.0(vue@3.5.38(typescript@5.9.3))': + '@tabler/icons-vue@3.44.0(vue@3.5.39(typescript@5.9.3))': dependencies: '@tabler/icons': 3.44.0 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) '@tabler/icons@3.44.0': {} @@ -1454,18 +1247,21 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.3.1 - '@tailwindcss/vite@4.3.1(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))': + '@tailwindcss/vite@4.3.1(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.3.1 '@tailwindcss/oxide': 4.3.1 tailwindcss: 4.3.1 - vite: 6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + vite: 8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0) - '@types/estree@1.0.9': {} + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true '@types/jsesc@2.5.1': {} - '@types/node@26.0.0': + '@types/node@26.0.1': dependencies: undici-types: 8.3.0 @@ -1475,11 +1271,11 @@ snapshots: '@types/web-bluetooth@0.0.21': {} - '@vitejs/plugin-vue@6.0.7(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.7(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.39(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) - vue: 3.5.38(typescript@5.9.3) + vite: 8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0) + vue: 3.5.39(typescript@5.9.3) '@volar/language-core@2.4.28': dependencies: @@ -1493,15 +1289,23 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue-macros/common@3.1.2(vue@3.5.38(typescript@5.9.3))': + '@vue-macros/common@3.1.2(vue@3.5.39(typescript@5.9.3))': dependencies: - '@vue/compiler-sfc': 3.5.38 + '@vue/compiler-sfc': 3.5.30 ast-kit: 2.2.0 - local-pkg: 1.2.1 + local-pkg: 1.1.2 magic-string-ast: 1.0.3 unplugin-utils: 0.3.1 optionalDependencies: - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) + + '@vue/compiler-core@3.5.30': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.30 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 '@vue/compiler-core@3.5.38': dependencies: @@ -1511,35 +1315,70 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@3.5.39': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.39 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.30': + dependencies: + '@vue/compiler-core': 3.5.30 + '@vue/shared': 3.5.30 + '@vue/compiler-dom@3.5.38': dependencies: '@vue/compiler-core': 3.5.38 '@vue/shared': 3.5.38 - '@vue/compiler-sfc@3.5.38': + '@vue/compiler-dom@3.5.39': + dependencies: + '@vue/compiler-core': 3.5.39 + '@vue/shared': 3.5.39 + + '@vue/compiler-sfc@3.5.30': dependencies: '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.38 - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/compiler-core': 3.5.30 + '@vue/compiler-dom': 3.5.30 + '@vue/compiler-ssr': 3.5.30 + '@vue/shared': 3.5.30 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.15 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.38': + '@vue/compiler-sfc@3.5.39': dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/shared': 3.5.38 + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.39 + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.15 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.30': + dependencies: + '@vue/compiler-dom': 3.5.30 + '@vue/shared': 3.5.30 + + '@vue/compiler-ssr@3.5.39': + dependencies: + '@vue/compiler-dom': 3.5.39 + '@vue/shared': 3.5.39 '@vue/devtools-api@7.7.9': dependencies: '@vue/devtools-kit': 7.7.9 - '@vue/devtools-api@8.1.3': + '@vue/devtools-api@8.1.5': dependencies: - '@vue/devtools-kit': 8.1.3 + '@vue/devtools-kit': 8.1.5 '@vue/devtools-kit@7.7.9': dependencies: @@ -1551,9 +1390,9 @@ snapshots: speakingurl: 14.0.1 superjson: 2.2.6 - '@vue/devtools-kit@8.1.3': + '@vue/devtools-kit@8.1.5': dependencies: - '@vue/devtools-shared': 8.1.3 + '@vue/devtools-shared': 8.1.5 birpc: 2.9.0 hookable: 5.5.3 perfect-debounce: 2.1.0 @@ -1562,7 +1401,7 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/devtools-shared@8.1.3': {} + '@vue/devtools-shared@8.1.5': {} '@vue/language-core@3.3.5': dependencies: @@ -1574,49 +1413,53 @@ snapshots: path-browserify: 1.0.1 picomatch: 4.0.4 - '@vue/reactivity@3.5.38': + '@vue/reactivity@3.5.39': dependencies: - '@vue/shared': 3.5.38 + '@vue/shared': 3.5.39 - '@vue/runtime-core@3.5.38': + '@vue/runtime-core@3.5.39': dependencies: - '@vue/reactivity': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/reactivity': 3.5.39 + '@vue/shared': 3.5.39 - '@vue/runtime-dom@3.5.38': + '@vue/runtime-dom@3.5.39': dependencies: - '@vue/reactivity': 3.5.38 - '@vue/runtime-core': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/reactivity': 3.5.39 + '@vue/runtime-core': 3.5.39 + '@vue/shared': 3.5.39 csstype: 3.2.3 - '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@5.9.3))': + '@vue/server-renderer@3.5.39(vue@3.5.39(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 - vue: 3.5.38(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 + vue: 3.5.39(typescript@5.9.3) + + '@vue/shared@3.5.30': {} '@vue/shared@3.5.38': {} - '@vue/tsconfig@0.9.1(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3))': + '@vue/shared@3.5.39': {} + + '@vue/tsconfig@0.9.1(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3))': optionalDependencies: typescript: 5.9.3 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) - '@vueuse/core@14.3.0(vue@3.5.38(typescript@5.9.3))': + '@vueuse/core@14.3.0(vue@3.5.39(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.3.0 - '@vueuse/shared': 14.3.0(vue@3.5.38(typescript@5.9.3)) - vue: 3.5.38(typescript@5.9.3) + '@vueuse/shared': 14.3.0(vue@3.5.39(typescript@5.9.3)) + vue: 3.5.39(typescript@5.9.3) '@vueuse/metadata@14.3.0': {} - '@vueuse/shared@14.3.0(vue@3.5.38(typescript@5.9.3))': + '@vueuse/shared@14.3.0(vue@3.5.39(typescript@5.9.3))': dependencies: - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) - acorn@8.17.0: {} + acorn@8.16.0: {} alien-signals@3.2.1: {} @@ -1662,35 +1505,6 @@ snapshots: entities@7.0.1: {} - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - estree-walker@2.0.2: {} exsolve@1.0.8: {} @@ -1765,10 +1579,16 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + local-pkg@1.1.2: + dependencies: + mlly: 1.8.1 + pkg-types: 2.3.0 + quansync: 0.2.11 + local-pkg@1.2.1: dependencies: - mlly: 1.8.2 - pkg-types: 2.3.1 + mlly: 1.8.1 + pkg-types: 2.3.0 quansync: 0.2.11 magic-string-ast@1.0.3: @@ -1787,12 +1607,19 @@ snapshots: mitt@3.0.1: {} + mlly@1.8.1: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + mlly@1.8.2: dependencies: - acorn: 8.17.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.4 + ufo: 1.6.3 muggle-string@0.4.1: {} @@ -1812,20 +1639,20 @@ snapshots: picomatch@4.0.4: {} - pinia@3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)): + pinia@3.0.4(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)): dependencies: '@vue/devtools-api': 7.7.9 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.2 + mlly: 1.8.1 pathe: 2.0.3 - pkg-types@2.3.1: + pkg-types@2.3.0: dependencies: confbox: 0.2.4 exsolve: 1.0.8 @@ -1851,13 +1678,13 @@ snapshots: prettier@3.6.0: {} - primevue@4.5.5(vue@3.5.38(typescript@5.9.3)): + primevue@4.5.5(vue@3.5.39(typescript@5.9.3)): dependencies: '@primeuix/styled': 0.7.4 '@primeuix/styles': 2.0.3 '@primeuix/utils': 0.6.4 - '@primevue/core': 4.5.5(vue@3.5.38(typescript@5.9.3)) - '@primevue/icons': 4.5.5(vue@3.5.38(typescript@5.9.3)) + '@primevue/core': 4.5.5(vue@3.5.39(typescript@5.9.3)) + '@primevue/icons': 4.5.5(vue@3.5.39(typescript@5.9.3)) transitivePeerDependencies: - vue @@ -1867,36 +1694,26 @@ snapshots: rfdc@1.4.1: {} - rollup@4.62.0: + rolldown@1.0.3: dependencies: - '@types/estree': 1.0.9 + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.0 - '@rollup/rollup-android-arm64': 4.62.0 - '@rollup/rollup-darwin-arm64': 4.62.0 - '@rollup/rollup-darwin-x64': 4.62.0 - '@rollup/rollup-freebsd-arm64': 4.62.0 - '@rollup/rollup-freebsd-x64': 4.62.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.0 - '@rollup/rollup-linux-arm-musleabihf': 4.62.0 - '@rollup/rollup-linux-arm64-gnu': 4.62.0 - '@rollup/rollup-linux-arm64-musl': 4.62.0 - '@rollup/rollup-linux-loong64-gnu': 4.62.0 - '@rollup/rollup-linux-loong64-musl': 4.62.0 - '@rollup/rollup-linux-ppc64-gnu': 4.62.0 - '@rollup/rollup-linux-ppc64-musl': 4.62.0 - '@rollup/rollup-linux-riscv64-gnu': 4.62.0 - '@rollup/rollup-linux-riscv64-musl': 4.62.0 - '@rollup/rollup-linux-s390x-gnu': 4.62.0 - '@rollup/rollup-linux-x64-gnu': 4.62.0 - '@rollup/rollup-linux-x64-musl': 4.62.0 - '@rollup/rollup-openbsd-x64': 4.62.0 - '@rollup/rollup-openharmony-arm64': 4.62.0 - '@rollup/rollup-win32-arm64-msvc': 4.62.0 - '@rollup/rollup-win32-ia32-msvc': 4.62.0 - '@rollup/rollup-win32-x64-gnu': 4.62.0 - '@rollup/rollup-win32-x64-msvc': 4.62.0 - fsevents: 2.3.3 + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 scule@1.3.0: {} @@ -1923,9 +1740,12 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tslib@2.8.1: + optional: true + typescript@5.9.3: {} - ufo@1.6.4: {} + ufo@1.6.3: {} undici-types@8.3.0: {} @@ -1934,7 +1754,7 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.4 - unplugin-vue-components@32.1.0(vue@3.5.38(typescript@5.9.3)): + unplugin-vue-components@32.1.0(vue@3.5.39(typescript@5.9.3)): dependencies: chokidar: 5.0.0 local-pkg: 1.2.1 @@ -1945,7 +1765,7 @@ snapshots: tinyglobby: 0.2.17 unplugin: 3.0.0 unplugin-utils: 0.3.1 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) unplugin@3.0.0: dependencies: @@ -1957,32 +1777,30 @@ snapshots: uuid@14.0.0: {} - vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0): + vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0): dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.4) + lightningcss: 1.32.0 picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.62.0 + rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 26.0.0 + '@types/node': 26.0.1 fsevents: 2.3.3 jiti: 2.7.0 - lightningcss: 1.32.0 yaml: 2.9.0 vscode-uri@3.1.0: {} - vue-router@5.1.0(@vue/compiler-sfc@3.5.38)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)))(vite@6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.38(typescript@5.9.3)): + vue-router@5.1.0(@vue/compiler-sfc@3.5.39)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)))(vite@8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0))(vue@3.5.39(typescript@5.9.3)): dependencies: '@babel/generator': 8.0.0 - '@vue-macros/common': 3.1.2(vue@3.5.38(typescript@5.9.3)) - '@vue/devtools-api': 8.1.3 + '@vue-macros/common': 3.1.2(vue@3.5.39(typescript@5.9.3)) + '@vue/devtools-api': 8.1.5 ast-walker-scope: 0.9.0 chokidar: 5.0.0 json5: 2.2.3 - local-pkg: 1.2.1 + local-pkg: 1.1.2 magic-string: 0.30.21 mlly: 1.8.2 muggle-string: 0.4.1 @@ -1992,12 +1810,12 @@ snapshots: tinyglobby: 0.2.17 unplugin: 3.0.0 unplugin-utils: 0.3.1 - vue: 3.5.38(typescript@5.9.3) + vue: 3.5.39(typescript@5.9.3) yaml: 2.9.0 optionalDependencies: - '@vue/compiler-sfc': 3.5.38 - pinia: 3.0.4(typescript@5.9.3)(vue@3.5.38(typescript@5.9.3)) - vite: 6.4.3(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.9.0) + '@vue/compiler-sfc': 3.5.39 + pinia: 3.0.4(typescript@5.9.3)(vue@3.5.39(typescript@5.9.3)) + vite: 8.0.16(@types/node@26.0.1)(jiti@2.7.0)(yaml@2.9.0) vue-tsc@3.3.5(typescript@5.9.3): dependencies: @@ -2005,13 +1823,13 @@ snapshots: '@vue/language-core': 3.3.5 typescript: 5.9.3 - vue@3.5.38(typescript@5.9.3): + vue@3.5.39(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-sfc': 3.5.38 - '@vue/runtime-dom': 3.5.38 - '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@5.9.3)) - '@vue/shared': 3.5.38 + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-sfc': 3.5.39 + '@vue/runtime-dom': 3.5.39 + '@vue/server-renderer': 3.5.39(vue@3.5.39(typescript@5.9.3)) + '@vue/shared': 3.5.39 optionalDependencies: typescript: 5.9.3