From 6bad739ab91468d9aa4edc17f3463a5d430d93a5 Mon Sep 17 00:00:00 2001 From: kris Date: Sat, 4 Apr 2026 08:49:08 +0800 Subject: [PATCH] feat: mirror project understanding sync into master chat --- src/lib/boss-data.ts | 42 +++++++++++++++++++++++++++++++ tests/device-import-draft.test.ts | 8 ++++++ 2 files changed, 50 insertions(+) diff --git a/src/lib/boss-data.ts b/src/lib/boss-data.ts index 1e6224a..5bffa25 100644 --- a/src/lib/boss-data.ts +++ b/src/lib/boss-data.ts @@ -6214,6 +6214,8 @@ export async function completeMasterAgentTask(payload: { } else if (isProjectUnderstandingSync) { const understanding = parseStructuredProjectUnderstandingReply(task); if (understanding && task.projectUnderstandingTargetProjectId) { + const targetProject = state.projects.find((item) => item.id === task.projectUnderstandingTargetProjectId); + const previousUnderstanding = targetProject?.projectUnderstanding; applyProjectUnderstandingSnapshotInState(state, { projectId: task.projectUnderstandingTargetProjectId, account: task.requestedByAccount, @@ -6221,6 +6223,19 @@ export async function completeMasterAgentTask(payload: { sourceMessageId: task.requestMessageId, sourceKind: "thread_sync", }); + if ( + targetProject && + shouldAnnounceProjectUnderstandingUpdate(previousUnderstanding, understanding) + ) { + pushProjectLedgerMessage(state, "master-agent", { + sender: "master", + senderLabel: "主 Agent", + body: buildProjectUnderstandingUpdateDigest(targetProject.name, understanding), + kind: "system_notice", + }); + publishBossEvent("project.messages.updated", { projectId: "master-agent" }); + publishBossEvent("conversation.updated", { projectId: "master-agent" }); + } publishBossEvent("conversation.updated", { projectId: task.projectUnderstandingTargetProjectId }); } } else if (isThreadConversationReply) { @@ -7354,6 +7369,33 @@ function applyProjectUnderstandingSnapshotInState( return snapshot; } +function shouldAnnounceProjectUnderstandingUpdate( + previous: ProjectUnderstandingSnapshot | undefined, + next: ProjectUnderstandingSnapshot, +) { + if (!previous) { + return true; + } + return ( + previous.projectGoal !== next.projectGoal || + previous.currentProgress !== next.currentProgress || + previous.technicalArchitecture !== next.technicalArchitecture || + previous.currentBlockers !== next.currentBlockers || + previous.recommendedNextStep !== next.recommendedNextStep + ); +} + +function buildProjectUnderstandingUpdateDigest(projectName: string, snapshot: ProjectUnderstandingSnapshot) { + return [ + `已同步项目理解:${projectName}`, + snapshot.currentProgress ? `进度:${snapshot.currentProgress}` : undefined, + snapshot.currentBlockers ? `阻塞:${snapshot.currentBlockers}` : undefined, + snapshot.recommendedNextStep ? `下一步:${snapshot.recommendedNextStep}` : undefined, + ] + .filter(Boolean) + .join("\n"); +} + function shouldQueueProjectUnderstandingSync(project: Project, observedActivityAt: string, state: BossState) { if (!isDispatchableThreadProject(project)) { return false; diff --git a/tests/device-import-draft.test.ts b/tests/device-import-draft.test.ts index ed1a134..704968e 100644 --- a/tests/device-import-draft.test.ts +++ b/tests/device-import-draft.test.ts @@ -609,6 +609,14 @@ test("imported thread projects queue hidden understanding sync tasks on newer ac )?.content, "优先压平实时状态刷新抖动,再验证群聊调度链路。", ); + const masterAgentProject = currentState.projects.find((project) => project.id === "master-agent"); + const syncNotice = masterAgentProject?.messages.findLast( + (message) => + message.kind === "system_notice" && + /已同步项目理解:智能看板主线程/.test(message.body) && + /实时状态同步和 UI 联调阶段/.test(message.body), + ); + assert.ok(syncNotice, "expected master-agent conversation to receive a lightweight sync digest"); }); test("heartbeat candidates no longer auto-create chat windows from legacy projects when import draft is present", async () => {