fix(client): repair the TypeScript build

`npm run build` runs `tsc -b` first and it has been failing: `api.ts` used
`NamedLock` without importing it, and four lane test fixtures predate
`Lane.active_feature_id` / the widened `LaneRuntime`, so spreading a
`Partial<Lane>` over them no longer satisfied the required fields.

Nothing shipped could be rebuilt while this was red, which is how a client
change reaches a dashboard running in production mode. The fixture fixes are
casts with a note, not type relaxations — the base literals still list every
required field, so the assertion states what they already prove.
This commit is contained in:
2026-08-07 09:52:13 +07:00
parent 8fcef5a10b
commit 201eae68bb
5 changed files with 24 additions and 6 deletions
@@ -34,6 +34,10 @@ vi.mock("../../../lib/api", () => ({
}));
function laneFixture(over: Partial<Lane> = {}): Lane {
// `as Lane`: spreading a Partial<Lane> widens every field it may carry to
// `T | undefined`, which no longer satisfies Lane's required fields. The
// base object below still lists all of them, so the cast asserts what the
// literal already proves.
return {
id: 9,
title: "",
@@ -64,7 +68,7 @@ function laneFixture(over: Partial<Lane> = {}): Lane {
slot: null,
ports: {},
...over,
};
} as Lane;
}
const SUGGESTIONS: CwdSuggestion[] = [
@@ -21,6 +21,10 @@ import { DestructiveLaneModal } from "../DestructiveLaneModal";
import type { Lane, LanePurgePreflight, LaneWorktreePreflight } from "../../../lib/types";
function makeLane(overrides: Partial<Lane> = {}): Lane {
// `as Lane`: spreading a Partial<Lane> widens every field it may carry to
// `T | undefined`, which no longer satisfies Lane's required fields. The
// base object below still lists all of them, so the cast asserts what the
// literal already proves.
return {
id: 1,
title: "demo",
@@ -50,7 +54,7 @@ function makeLane(overrides: Partial<Lane> = {}): Lane {
slot: null,
ports: {},
...overrides,
};
} as Lane;
}
function worktreePreflight(overrides: Partial<LaneWorktreePreflight> = {}): LaneWorktreePreflight {
@@ -12,7 +12,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import LaneCard from "../LaneCard";
import type { Lane } from "../../../lib/types";
import type { Lane, LaneRuntime } from "../../../lib/types";
import { api } from "../../../lib/api";
vi.mock("../../../lib/api", () => ({
@@ -48,6 +48,10 @@ vi.mocked(api.locks.list).mockReset();
vi.mocked(api.locks.list).mockResolvedValue({ locks: [] });
function makeLane(overrides: Partial<Lane> = {}): Lane {
// `as Lane`: spreading a Partial<Lane> widens every field it may carry to
// `T | undefined`, which no longer satisfies Lane's required fields. The
// base object below still lists all of them, so the cast asserts what the
// literal already proves.
return {
id: 1,
title: "demo",
@@ -78,7 +82,7 @@ function makeLane(overrides: Partial<Lane> = {}): Lane {
slot: null,
ports: {},
...overrides,
};
} as Lane;
}
describe("LaneCard status badge", () => {
@@ -396,6 +400,9 @@ describe("LaneCard — named locks", () => {
describe("agents install / mcp sync / integration badges / sync check", () => {
beforeEach(() => {
// Only the fields this describe block's assertions read; `as LaneRuntime`
// keeps the double from having to restate a shape the component never
// touches here.
vi.mocked(api.lanes.runtime).mockResolvedValue({
available: true as const,
provisioned: true as const,
@@ -403,7 +410,7 @@ describe("agents install / mcp sync / integration badges / sync check", () => {
slot: 1,
profileDir: "/work/demo/.ccam/profile",
ports: {},
});
} as unknown as LaneRuntime);
vi.mocked(api.lanes.integration).mockImplementation((_id, name) =>
Promise.resolve({ enabled: name === "tracker" })
);