import test from "node:test"; import assert from "node:assert/strict"; import os from "node:os"; import path from "node:path"; import { mkdtemp, rm } from "node:fs/promises"; import { NextRequest } from "next/server"; let runtimeRoot = ""; let createAuthSession: (typeof import("../src/lib/boss-data"))["createAuthSession"]; let readState: (typeof import("../src/lib/boss-data"))["readState"]; let deviceHeartbeatRoute: (typeof import("../src/app/api/device-heartbeat/route"))["POST"]; let AUTH_SESSION_COOKIE = ""; async function setup() { if (runtimeRoot) return; runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-device-import-candidate-id-")); process.env.BOSS_RUNTIME_ROOT = runtimeRoot; process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json"); const [heartbeatModule, data, auth] = await Promise.all([ import("../src/app/api/device-heartbeat/route.ts"), import("../src/lib/boss-data.ts"), import("../src/lib/boss-auth.ts"), ]); deviceHeartbeatRoute = heartbeatModule.POST; createAuthSession = data.createAuthSession; readState = data.readState; AUTH_SESSION_COOKIE = auth.AUTH_SESSION_COOKIE; } test.after(async () => { if (runtimeRoot) { await rm(runtimeRoot, { recursive: true, force: true }); } }); async function createAuthedSessionCookie() { const session = await createAuthSession({ account: "17600003315", role: "highest_admin", displayName: "Boss 超级管理员", loginMethod: "password", }); return `${AUTH_SESSION_COOKIE}=${session.sessionToken}`; } test("auto-sync import keeps long-prefix project candidates distinct", async () => { await setup(); const cookie = await createAuthedSessionCookie(); const state = await readState(); state.devices = [ { id: "mac-studio", name: "Mac Studio", avatar: "M", account: "17600003315", source: "production", status: "online", projects: [], quota5h: 68, quota7d: 81, lastSeenAt: "2026-04-03T10:00:00.000Z", endpoint: "mac://kris.local", token: "boss-mac-studio-token", note: "本机 Codex 主节点", }, ]; const response = await deviceHeartbeatRoute( new NextRequest("http://127.0.0.1:3000/api/device-heartbeat", { method: "POST", headers: { "content-type": "application/json", cookie, }, body: JSON.stringify({ deviceId: "mac-studio", token: "boss-mac-studio-token", name: "Mac Studio", avatar: "M", account: "17600003315", status: "online", quota5h: 68, quota7d: 81, projects: [], endpoint: "mac://kris.local", projectCandidates: [ { folderName: "AItoukui", folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/AItoukui", threadId: "019d4efb-3485-7b21-86dc-b70d3f4adf68", threadDisplayName: "拉取代码并验证交接文档和本地启动状态", codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/AItoukui", codexThreadRef: "019d4efb-3485-7b21-86dc-b70d3f4adf68", lastActiveAt: "2026-04-02T20:50:36.000Z", suggestedImport: true, }, { folderName: "500Gcode", folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode", threadId: "019d4e19-1d27-77d3-bc54-2a1c80c7431b", threadDisplayName: "本机运行3.5B模型并搭建Web演示", codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode", codexThreadRef: "019d4e19-1d27-77d3-bc54-2a1c80c7431b", lastActiveAt: "2026-04-02T20:50:36.000Z", suggestedImport: true, }, { folderName: "figma", folderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/figma", threadId: "019d4e1d-03b8-7610-b427-c4ffd234aed4", threadDisplayName: "配置Figma账号并启用UI制作Skill", codexFolderRef: "/Volumes/Macintosh HD/Users/kris/500Gcode/figma", codexThreadRef: "019d4e1d-03b8-7610-b427-c4ffd234aed4", lastActiveAt: "2026-04-02T20:50:36.000Z", suggestedImport: true, }, ], }), }), ); assert.equal(response.status, 200); const payload = (await response.json()) as { importDraft?: { candidates: Array<{ candidateId: string }>; appliedProjectNames: string[] }; }; const candidateIds = payload.importDraft?.candidates.map((candidate) => candidate.candidateId) ?? []; assert.equal(new Set(candidateIds).size, 3); const nextState = await readState(); const importedProjects = nextState.projects.filter((project) => ["AItoukui", "500Gcode", "figma"].includes(project.threadMeta.folderName), ); assert.equal(importedProjects.length, 3); assert.deepEqual( importedProjects.map((project) => project.threadMeta.folderName).sort(), ["500Gcode", "AItoukui", "figma"], ); });