feat: auto-sync bound codex threads into conversations
This commit is contained in:
@@ -485,3 +485,70 @@ test("device import routes reject unrelated logged-in members", async () => {
|
||||
});
|
||||
assert.equal(getResponse.status, 403);
|
||||
});
|
||||
|
||||
test("existing bound production devices auto-sync suggested candidates into conversations on heartbeat", async () => {
|
||||
await setup();
|
||||
|
||||
const heartbeatResponse = await deviceHeartbeatRoute(
|
||||
new NextRequest("http://127.0.0.1:3000/api/device-heartbeat", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
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: ["Boss 移动控制台", "硬件审计协作"],
|
||||
endpoint: "mac://kris.local",
|
||||
projectCandidates: [
|
||||
{
|
||||
folderName: "yuandi",
|
||||
folderRef: "/Users/kris/code/yuandi",
|
||||
threadId: "session-yuandi-1",
|
||||
threadDisplayName: "Epicurus",
|
||||
codexFolderRef: "/Users/kris/code/yuandi",
|
||||
codexThreadRef: "session-yuandi-1",
|
||||
lastActiveAt: "2026-03-30T12:42:56+08:00",
|
||||
suggestedImport: true,
|
||||
},
|
||||
{
|
||||
folderName: "wenshenapp",
|
||||
folderRef: "/Users/kris/code/wenshenapp",
|
||||
threadId: "session-wenshenapp-1",
|
||||
threadDisplayName: "wenshenapp · ea5f",
|
||||
codexFolderRef: "/Users/kris/code/wenshenapp",
|
||||
codexThreadRef: "session-wenshenapp-1",
|
||||
lastActiveAt: "2026-03-30T12:34:51+08:00",
|
||||
suggestedImport: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
assert.equal(heartbeatResponse.status, 200);
|
||||
|
||||
const payload = (await heartbeatResponse.json()) as {
|
||||
importDraft?: { status: string; selectedCandidateIds: string[] } | null;
|
||||
};
|
||||
assert.equal(payload.importDraft?.status, "applied");
|
||||
assert.equal(payload.importDraft?.selectedCandidateIds.length, 2);
|
||||
|
||||
const nextState = await readState();
|
||||
const yuandiProject = nextState.projects.find(
|
||||
(project) => project.threadMeta.codexThreadRef === "session-yuandi-1",
|
||||
);
|
||||
const wenshenProject = nextState.projects.find(
|
||||
(project) => project.threadMeta.codexThreadRef === "session-wenshenapp-1",
|
||||
);
|
||||
assert.ok(yuandiProject, "expected a discovered yuandi session to become a real chat window");
|
||||
assert.ok(wenshenProject, "expected a discovered wenshenapp session to become a real chat window");
|
||||
assert.equal(yuandiProject?.threadMeta.folderName, "yuandi");
|
||||
assert.equal(wenshenProject?.threadMeta.folderName, "wenshenapp");
|
||||
|
||||
const device = nextState.devices.find((item) => item.id === "mac-studio");
|
||||
assert.deepEqual(device?.projects, ["yuandi", "wenshenapp"]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user