chore: checkpoint Boss app v2.5.11

This commit is contained in:
AI Bot
2026-06-08 12:22:50 +08:00
parent bddbe8b5ba
commit 3b51641d99
78 changed files with 5706 additions and 954 deletions

View File

@@ -1592,6 +1592,123 @@ test("POST /api/v1/master-agent/tasks/[taskId]/complete folds thread commentary
assert.equal(updatedProject?.unreadCount, 1);
});
test("POST /api/v1/master-agent/tasks/[taskId]/complete strips already mirrored process text from aggregate thread replies", async () => {
await setup();
const singleProject = await ensureSingleThreadProject();
assert.ok(singleProject, "expected a seeded single-thread project");
await resetThreadExecutionState(singleProject.id);
await setProjectTakeover(singleProject.id, false);
const sendResponse = await postMessageRoute(
await createAuthedRequest(
`http://127.0.0.1:3000/api/v1/projects/${singleProject.id}/messages`,
"POST",
{ body: "只要不对原有项目有任何影响。你按最推荐的方式做。" },
),
{ params: Promise.resolve({ projectId: singleProject.id }) },
);
const sendPayload = (await sendResponse.json()) as { task?: { taskId: string } };
const queuedState = await readState();
const task = queuedState.masterAgentTasks.find(
(item) => item.taskId === sendPayload.task?.taskId,
);
assert.ok(task, "expected a queued conversation_reply task");
const processOne = "我先按非侵入方式收口:不碰原项目代码,只把这次 APP 端问题整理成可复现、可提交的诊断文档。";
const processTwo = "我在按调试流程收证据,但会收在文档里,不会动任何现有项目文件。";
const processThree = "文档已经落下来了,我再做一次范围确认,确保只有独立报告被新增。";
const finalText = "我按非侵入方式处理了,没有碰任何原有项目代码,只新增了一份独立排查文档。";
const aggregateReply = `${processOne}${processTwo}${processThree}${finalText}`;
const requestedAtMs = Date.parse(task.requestedAt);
assert.ok(Number.isFinite(requestedAtMs), "expected task requestedAt to be parseable");
const taskRelativeTime = (offsetMs: number) => new Date(requestedAtMs + offsetMs).toISOString();
const mirroredState = await readState();
const project = mirroredState.projects.find((item) => item.id === singleProject.id);
assert.ok(project, "expected the single-thread project to exist");
project.messages = project.messages.filter(
(message) =>
message.id === task.requestMessageId ||
message.executionProgress?.taskId === task.taskId,
);
project.messages.push(
{
id: "msg-process-one",
sender: "device",
senderLabel: project.threadMeta.threadDisplayName,
body: processOne,
sentAt: taskRelativeTime(1_000),
kind: "thread_process",
},
{
id: "msg-process-two",
sender: "device",
senderLabel: project.threadMeta.threadDisplayName,
body: processTwo,
sentAt: taskRelativeTime(2_000),
kind: "thread_process",
},
{
id: "msg-process-three",
sender: "device",
senderLabel: project.threadMeta.threadDisplayName,
body: processThree,
sentAt: taskRelativeTime(3_000),
kind: "thread_process",
},
{
id: "msg-final-mirrored",
sender: "device",
senderLabel: project.threadMeta.threadDisplayName,
body: finalText,
sentAt: taskRelativeTime(4_000),
kind: "text",
},
);
project.preview = finalText;
project.lastMessageAt = taskRelativeTime(4_000);
project.unreadCount = 1;
await writeState(mirroredState);
const response = await completeMasterTaskRoute(
await createAuthedRequest(
`http://127.0.0.1:3000/api/v1/master-agent/tasks/${task.taskId}/complete`,
"POST",
{
deviceId: task.deviceId,
status: "completed",
targetProjectId: singleProject.id,
targetThreadId: singleProject.threadMeta.threadId,
replyBody: aggregateReply,
},
),
{ params: Promise.resolve({ taskId: task.taskId }) },
);
assert.equal(response.status, 200);
const nextState = await readState();
const updatedProject = nextState.projects.find((item) => item.id === singleProject.id);
const aggregateMessages =
updatedProject?.messages.filter((message) => message.body === aggregateReply) ?? [];
const finalMessages = updatedProject?.messages.filter((message) => message.body === finalText) ?? [];
assert.equal(aggregateMessages.length, 0, "aggregate process+final reply should not be displayed");
assert.equal(finalMessages.length, 1, "already mirrored final result should not be duplicated");
assert.equal(updatedProject?.preview, finalText);
assert.equal(updatedProject?.unreadCount, 1);
const cleanupState = await readState();
const cleanupProject = cleanupState.projects.find((item) => item.id === singleProject.id);
if (cleanupProject) {
cleanupProject.messages = [];
cleanupProject.preview = "测试线程等待继续处理。";
cleanupProject.lastMessageAt = "2026-04-04T11:30:00+08:00";
cleanupProject.unreadCount = 0;
}
await writeState(cleanupState);
});
test("POST /api/v1/master-agent/tasks/[taskId]/complete keeps compact numbered progress updates folded", async () => {
await setup();
const singleProject = await ensureSingleThreadProject();
@@ -1649,7 +1766,7 @@ test("POST /api/v1/master-agent/tasks/[taskId]/complete keeps compact numbered p
assert.equal(updatedProject?.unreadCount, 0);
});
test("device heartbeat keeps conversation preview on the latest non-process message", async () => {
test("device heartbeat activity does not overwrite conversation preview with desktop process text", async () => {
await setup();
const singleProject = await ensureSingleThreadProject();
assert.ok(singleProject, "expected a seeded single-thread project");
@@ -1713,12 +1830,14 @@ test("device heartbeat keeps conversation preview on the latest non-process mess
(message) => message.externalMessageId === "codex-thread:preview-keep:2026-04-24T05:41:14.246Z:p1",
);
assert.equal(processMessage?.kind, "thread_process");
assert.equal(processMessage, undefined);
assert.equal(updatedProject?.messages.length, 1);
assert.equal(updatedProject?.preview, "这是上一轮最终结果。");
assert.equal(updatedProject?.unreadCount, 0);
assert.equal(updatedProject?.threadMeta.lastObservedCodexActivityAt, "2026-04-24T05:41:14.246Z");
});
test("device heartbeat keeps conversation preview blank when only process messages are mirrored", async () => {
test("device heartbeat activity clears stale process preview without appending desktop process text", async () => {
await setup();
const singleProject = await ensureSingleThreadProject();
assert.ok(singleProject, "expected a seeded single-thread project");
@@ -1773,9 +1892,11 @@ test("device heartbeat keeps conversation preview blank when only process messag
(message) => message.externalMessageId === "codex-thread:preview-empty:2026-04-24T05:41:14.246Z:p1",
);
assert.equal(processMessage?.kind, "thread_process");
assert.equal(processMessage, undefined);
assert.equal(updatedProject?.messages.length, 0);
assert.equal(updatedProject?.preview, "");
assert.equal(updatedProject?.unreadCount, 0);
assert.equal(updatedProject?.threadMeta.lastObservedCodexActivityAt, "2026-04-24T05:41:14.246Z");
});
test("legacy device process text is reclassified and no longer pollutes preview or unread", async () => {