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 ? 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: "krisolo", 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: "krisolo", 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"); }); test("device heartbeat without capability payload refreshes stale gui cli lastSeenAt", async () => { await setup(); const staleCapabilityTime = "2026-03-25T11:52:00+08:00"; const staleState = await readState(); await writeState({ ...staleState, devices: staleState.devices.map((device) => device.id === "mac-studio" ? { ...device, lastSeenAt: staleCapabilityTime, capabilities: { gui: { ...device.capabilities?.gui, connected: true, lastSeenAt: staleCapabilityTime, lastActiveProjectId: "master-agent", }, cli: { ...device.capabilities?.cli, connected: true, lastSeenAt: staleCapabilityTime, lastActiveProjectId: "master-agent", }, }, } : device, ), }); await upsertDeviceHeartbeat({ deviceId: "mac-studio", name: "Mac Studio", avatar: "M", account: "krisolo", status: "online", quota5h: 72, quota7d: 86, preferredExecutionMode: "cli", projects: ["硬件审计协作"], endpoint: "mac://kris.local", }); const state = await readState(); const device = state.devices.find((item) => item.id === "mac-studio"); assert.ok(device); assert.notEqual(device.lastSeenAt, staleCapabilityTime); assert.equal(device.capabilities?.gui.lastSeenAt, device.lastSeenAt); assert.equal(device.capabilities?.cli.lastSeenAt, device.lastSeenAt); });