feat(ui): Appearance settings — dark/light/system mode and named themes; fix Add lane silently doing nothing (#42)

- Settings → Appearance: mode Dark / Light / System (follows the OS live) and
  a named theme remembered per mode — dark: Default, Darcula, Apple Dark;
  light: Default, Apple Light, IntelliJ Light, Canvas. Each theme is a
  CSS-variable override block keyed by `data-theme` on <html>; the sidebar
  quick toggle gains System and swaps between the two remembered themes.
- An inline boot script in index.html applies the stored mode and theme
  before first paint, so a reload no longer flashes the default colours.
- Diff +/- rows are easier to tell apart on every theme: a /20 status tint,
  a 3px status bar and a bold coloured marker; the changed-span emphasis no
  longer vanishes on light themes.
- #42: the Add-lane modal (Repo mode / "Current branch") asks
  POST /api/lanes/ensure with `exact: true`. Without it a folder nested inside
  an existing lane resolved to that parent lane with created:false, so the
  modal closed and no new card appeared. When the folder really already has a
  lane, the modal now says which one instead of closing.

Closes #42
This commit is contained in:
2026-09-24 09:44:42 +07:00
parent 2ea2184372
commit 6cf8a82889
33 changed files with 1756 additions and 59 deletions
+15
View File
@@ -1164,6 +1164,21 @@ describe("lane ensure, start mode, lane_id and releasing a finished run", () =>
assert.notEqual(sibling.body.lane.id, owner.body.lane.id);
});
it("with exact:true, creates a lane for a nested cwd instead of returning its parent (#42)", async () => {
const parent = path.join(ROOT, "ensure-exact-parent");
const nested = path.join(parent, "services");
const owner = await request("POST", "/api/lanes/ensure", { cwd: parent });
assert.equal(owner.status, 201);
const r = await request("POST", "/api/lanes/ensure", { cwd: nested, exact: true });
assert.equal(r.status, 201, JSON.stringify(r.body));
assert.equal(r.body.created, true);
assert.equal(r.body.lane.cwd, nested);
// The same directory still answers with its own lane, never a second one.
const again = await request("POST", "/api/lanes/ensure", { cwd: nested, exact: true });
assert.equal(again.body.created, false);
assert.equal(again.body.lane.id, r.body.lane.id);
});
it("yields exactly one lane for two concurrent ensure calls on the same path", async () => {
const cwd = path.join(ROOT, "ensure-concurrent");
const [a, b] = await Promise.all([