Files
boss/tests/device-gui-cli-capabilities.test.ts
2026-04-06 10:22:07 +08:00

243 lines
7.1 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm, writeFile } from "node:fs/promises";
let runtimeRoot = "";
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let writeState: (typeof import("../src/lib/boss-data"))["writeState"];
let upsertDeviceHeartbeat: (typeof import("../src/lib/boss-data"))["upsertDeviceHeartbeat"];
let updateDevice: (typeof import("../src/lib/boss-data"))["updateDevice"];
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-device-capabilities-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const data = await import("../src/lib/boss-data.ts");
readState = data.readState;
writeState = data.writeState;
upsertDeviceHeartbeat = data.upsertDeviceHeartbeat;
updateDevice = data.updateDevice;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
test("device stores gui and cli capabilities without splitting the physical device", async () => {
await setup();
const state = await readState();
const device = state.devices.find((item) => item.id === "mac-studio") as
| ({
capabilities?: {
gui?: { connected?: boolean };
cli?: { connected?: boolean };
};
preferredExecutionMode?: string;
} & (typeof state.devices)[number])
| undefined;
assert.ok(device);
assert.equal(device.capabilities?.gui?.connected, true);
assert.equal(device.capabilities?.cli?.connected, true);
assert.equal(device.preferredExecutionMode, "cli");
});
test("conflict policy is scoped to the active folder instead of the whole device", async () => {
await setup();
const state = (await readState()) as typeof readState extends () => Promise<infer T>
? T & {
projectExecutionPolicies?: Array<{
deviceId: string;
folderKey?: string;
projectId: string;
allowPolicy: string;
conflictState: string;
updatedAt: string;
}>;
}
: never;
state.projectExecutionPolicies = [
{
deviceId: "mac-studio",
folderKey: "mac-studio:boss",
projectId: "thread-ui",
allowPolicy: "allow_always",
conflictState: "warning",
updatedAt: "2026-04-06T10:00:00.000Z",
},
];
await writeState(state);
const nextState = (await readState()) as typeof state;
const bossPolicy = nextState.projectExecutionPolicies?.find(
(item) => item.folderKey === "mac-studio:boss",
);
const otherPolicy = nextState.projectExecutionPolicies?.find(
(item) => item.folderKey === "mac-studio:talking",
);
assert.equal(bossPolicy?.allowPolicy, "allow_always");
assert.equal(otherPolicy, undefined);
});
test("legacy device state without capabilities is normalized with seeded defaults", async () => {
await setup();
const state = await readState();
const legacyState = {
...state,
devices: state.devices.map((device) =>
device.id === "mac-studio"
? {
...device,
capabilities: undefined,
preferredExecutionMode: undefined,
}
: device,
),
};
await writeFile(process.env.BOSS_STATE_FILE!, JSON.stringify(legacyState, null, 2), "utf8");
const normalized = await readState();
const device = normalized.devices.find((item) => item.id === "mac-studio");
assert.ok(device);
assert.equal(device.capabilities?.gui.connected, true);
assert.equal(device.capabilities?.cli.connected, true);
assert.equal(device.preferredExecutionMode, "cli");
});
test("legacy device normalization matches seeded defaults by device id instead of array position", async () => {
await setup();
const state = await readState();
const reorderedLegacyDevices = [
{
id: "win-gpu-01",
source: "production",
capabilities: undefined,
preferredExecutionMode: undefined,
},
{
id: "mac-studio",
source: "production",
capabilities: undefined,
preferredExecutionMode: undefined,
},
];
await writeFile(
process.env.BOSS_STATE_FILE!,
JSON.stringify(
{
...state,
devices: reorderedLegacyDevices,
},
null,
2,
),
"utf8",
);
const normalized = await readState();
const windowsDevice = normalized.devices.find((item) => item.id === "win-gpu-01");
const macDevice = normalized.devices.find((item) => item.id === "mac-studio");
assert.ok(windowsDevice);
assert.ok(macDevice);
assert.equal(windowsDevice.capabilities?.gui.connected, true);
assert.equal(windowsDevice.capabilities?.cli.connected, false);
assert.equal(windowsDevice.preferredExecutionMode, "gui");
assert.equal(macDevice.capabilities?.gui.connected, true);
assert.equal(macDevice.capabilities?.cli.connected, true);
assert.equal(macDevice.preferredExecutionMode, "cli");
});
test("device heartbeat persists gui cli capability state on the same physical device", async () => {
await setup();
await upsertDeviceHeartbeat({
deviceId: "mac-studio",
name: "Mac Studio",
avatar: "M",
account: "17600003315",
status: "online",
quota5h: 72,
quota7d: 86,
preferredExecutionMode: "gui",
capabilities: {
gui: {
connected: true,
lastSeenAt: "2026-04-06T09:30:00.000Z",
lastActiveProjectId: "audit-collab",
},
cli: {
connected: true,
lastSeenAt: "2026-04-06T09:31:00.000Z",
lastActiveProjectId: "master-agent",
},
},
projects: ["硬件审计协作"],
endpoint: "mac://kris.local",
});
const state = await readState();
const device = state.devices.find((item) => item.id === "mac-studio");
assert.ok(device);
assert.equal(device.preferredExecutionMode, "cli");
assert.equal(device.capabilities?.gui.connected, true);
assert.equal(device.capabilities?.gui.lastActiveProjectId, "audit-collab");
assert.equal(device.capabilities?.cli.connected, true);
assert.equal(device.capabilities?.cli.lastActiveProjectId, "master-agent");
});
test("device heartbeat does not overwrite the preferred execution mode chosen in Boss for an existing device", async () => {
await setup();
await updateDevice("mac-studio", {
preferredExecutionMode: "gui",
});
await upsertDeviceHeartbeat({
deviceId: "mac-studio",
name: "Mac Studio",
avatar: "M",
account: "17600003315",
status: "online",
quota5h: 72,
quota7d: 86,
preferredExecutionMode: "cli",
capabilities: {
gui: {
connected: true,
lastSeenAt: "2026-04-06T09:35:00.000Z",
lastActiveProjectId: "master-agent",
},
cli: {
connected: true,
lastSeenAt: "2026-04-06T09:36:00.000Z",
lastActiveProjectId: "audit-collab",
},
},
projects: ["硬件审计协作"],
endpoint: "mac://kris.local",
});
const state = await readState();
const device = state.devices.find((item) => item.id === "mac-studio");
assert.ok(device);
assert.equal(device.preferredExecutionMode, "gui");
});