diff --git a/meshchatx.rsm b/meshchatx.rsm
index c7031905..3e976502 100644
Binary files a/meshchatx.rsm and b/meshchatx.rsm differ
diff --git a/meshchatx/src/backend/bake_frozen_pycodec2.py b/meshchatx/src/backend/bake_frozen_pycodec2.py
index b3b796f4..d7a04efe 100644
--- a/meshchatx/src/backend/bake_frozen_pycodec2.py
+++ b/meshchatx/src/backend/bake_frozen_pycodec2.py
@@ -15,6 +15,7 @@ from __future__ import annotations
import importlib.metadata
import shutil
+import stat
import subprocess
import sys
from pathlib import Path
@@ -81,8 +82,13 @@ def _extension_module(pkg: Path) -> Path | None:
def _copy_file(src: Path, dest: Path) -> None:
dest.parent.mkdir(parents=True, exist_ok=True)
- if src.resolve() == dest.resolve():
- return
+ if dest.is_symlink():
+ dest.unlink()
+ elif dest.exists():
+ if src.resolve() == dest.resolve():
+ return
+ dest.chmod(stat.S_IWRITE | stat.S_IREAD)
+ dest.unlink()
shutil.copy2(src, dest)
diff --git a/tests/backend/test_bake_frozen_pycodec2.py b/tests/backend/test_bake_frozen_pycodec2.py
index 22254083..b3551d14 100644
--- a/tests/backend/test_bake_frozen_pycodec2.py
+++ b/tests/backend/test_bake_frozen_pycodec2.py
@@ -127,6 +127,40 @@ def test_bake_copies_executable_path_basename_from_load_command(
assert (root / "lib" / "libcodec2.dylib").read_bytes() == b"lib"
+def test_bake_replaces_symlink_dest_without_writing_through_it(tmp_path: Path) -> None:
+ root = _frozen_pycodec2_tree(tmp_path)
+ pkg = root / "lib" / "pycodec2"
+ (pkg / "libcodec2.dylib").write_bytes(b"canonical")
+
+ cellar = tmp_path / "cellar"
+ cellar.mkdir()
+ cellar_lib = cellar / "libcodec2.dylib"
+ cellar_lib.write_bytes(b"homebrew")
+ cellar_lib.chmod(0o444)
+
+ dest_lib = root / "lib" / "libcodec2.dylib"
+ dest_lib.symlink_to(cellar_lib)
+
+ bake_frozen_pycodec2(root)
+
+ assert dest_lib.is_symlink() is False
+ assert dest_lib.read_bytes() == b"canonical"
+ assert cellar_lib.read_bytes() == b"homebrew"
+
+
+def test_bake_replaces_readonly_dest_libcodec2(tmp_path: Path) -> None:
+ root = _frozen_pycodec2_tree(tmp_path)
+ pkg = root / "lib" / "pycodec2"
+ (pkg / "libcodec2.dylib").write_bytes(b"canonical")
+ dest_lib = root / "lib" / "libcodec2.dylib"
+ dest_lib.write_bytes(b"old")
+ dest_lib.chmod(0o444)
+
+ bake_frozen_pycodec2(root)
+
+ assert dest_lib.read_bytes() == b"canonical"
+
+
def test_bake_copies_from_build_env_when_freeze_tree_has_no_dylib(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
diff --git a/tests/frontend/SidebarLink.test.js b/tests/frontend/SidebarLink.test.js
index 43788b57..7bf80e6d 100644
--- a/tests/frontend/SidebarLink.test.js
+++ b/tests/frontend/SidebarLink.test.js
@@ -2,18 +2,17 @@ import { mount } from "@vue/test-utils";
import { describe, it, expect } from "vitest";
import SidebarLink from "../../meshchatx/src/frontend/components/SidebarLink.vue";
-const RouterLinkStub = {
- name: "RouterLinkStub",
- props: ["to"],
- template: '',
- methods: {
- navigate(e) {
- if (e) e.preventDefault();
+function mountSidebarLink(props = {}, slots = {}, { isActive = false } = {}) {
+ const RouterLinkStub = {
+ name: "RouterLinkStub",
+ props: ["to"],
+ template: ``,
+ methods: {
+ navigate(e) {
+ if (e) e.preventDefault();
+ },
},
- },
-};
-
-function mountSidebarLink(props = {}, slots = {}) {
+ };
return mount(SidebarLink, {
props: { to: { name: "messages" }, ...props },
slots: {
@@ -63,11 +62,24 @@ describe("SidebarLink UI", () => {
expect(innerLink.exists()).toBe(true);
expect(innerLink.classes()).toContain("justify-center");
expect(innerLink.classes()).not.toContain("mr-2");
- expect(innerLink.classes()).toContain("rounded-lg");
+ expect(innerLink.classes()).toContain("rounded-none");
+ expect(innerLink.classes()).not.toContain("rounded-lg");
expect(wrapper.text()).not.toContain("Messages");
expect(wrapper.find(".icon-slot").exists()).toBe(true);
});
+ it("uses a square inset well when collapsed and selected", () => {
+ const wrapper = mountSidebarLink({ isCollapsed: true }, {}, { isActive: true });
+ const innerLink = wrapper.find("a.justify-center");
+ const className = innerLink.attributes("class");
+ expect(innerLink.classes()).toContain("rounded-none");
+ expect(innerLink.classes()).not.toContain("rounded-lg");
+ expect(innerLink.classes()).not.toContain("bg-blue-100");
+ expect(innerLink.classes()).not.toContain("dark:bg-zinc-800");
+ expect(className).toContain("shadow-[inset_");
+ expect(className).toContain("bg-black/[0.04]");
+ });
+
it("does not navigate when editMode is on", async () => {
const wrapper = mountSidebarLink({ editMode: true });
const innerLink = wrapper.find("a.rounded-r-full");