Files
boss/docs/superpowers/plans/2026-04-04-master-agent-thread-status-sync.md

786 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 主 Agent 线程状态文档与增量同步 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让主 Agent 用“线程状态文档 + 最近进展事件 + 关键时刻深拉”的方式理解活跃线程,减少常态 token 消耗,同时保持关键时刻的接手能力与实时性。
**Architecture:** 在现有 `projectUnderstandingSnapshot` 自动同步链路上新增线程级 `ThreadStatusDocument``ThreadProgressEvent`,让 heartbeat / thread reply 先走轻量事件同步,再在关键场景触发全量理解刷新。主 Agent prompt 组装从“读项目理解快照”升级为“读线程状态文档 + 最近事件 + 项目记忆”,前台增加只读 `线程状态` 入口。
**Tech Stack:** Next.js App Router、TypeScript、文件型状态存储 `data/boss-state.json`、Android 原生客户端、Node test runner、Gradle unit tests
---
## 文件结构
### 新增/扩展数据模型与状态归一化
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
- Test: `/Users/kris/code/boss/tests/thread-status-sync.test.ts`
- Test: `/Users/kris/code/boss/tests/device-import-draft.test.ts`
职责:
-`BossState` 里新增线程状态文档和进展事件
- 补 normalization / pruning / slicing
- 增加全量同步与轻量同步任务排队逻辑
### 主 Agent prompt 组装与读取逻辑
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
- Test: `/Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts`
职责:
- 让主 Agent 默认读取线程状态文档和最近进展事件
- 保留关键时刻深拉线程的兜底路径
### 线程状态 API 与会话信息展示
- Create: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/thread-status/route.ts`
- Modify: `/Users/kris/code/boss/src/components/app-ui.tsx`
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossApiClient.java`
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java`
- Create: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ThreadStatusActivity.java`
- Test: `/Users/kris/code/boss/tests/thread-status-route.test.ts`
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ConversationInfoActivityTest.java`
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ThreadStatusActivityTest.java`
职责:
- 提供线程状态只读接口
- 在线程会话信息页增加 `线程状态` 入口
- Android 前台可查看线程状态
### 文档与回归
- Modify: `/Users/kris/code/boss/README.md`
- Modify: `/Users/kris/code/boss/docs/architecture/current_runtime_and_deploy_status_cn.md`
- Modify: `/Users/kris/code/boss/docs/architecture/api_and_service_inventory_cn.md`
职责:
- 记录线程状态文档和进展事件的运行方式
- 记录 API 与同步策略
---
### Task 1: 新增线程状态文档与进展事件模型
**Files:**
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
- Test: `/Users/kris/code/boss/tests/thread-status-sync.test.ts`
- [ ] **Step 1: 写失败测试,锁住状态模型归一化与裁剪行为**
```ts
import test from "node:test";
import assert from "node:assert/strict";
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let writeState: (typeof import("../src/lib/boss-data"))["writeState"];
test("thread status documents and progress events normalize and trim correctly", async () => {
const state = await readState();
state.threadStatusDocuments = [
{
documentId: "doc-1",
projectId: "thread-a",
threadId: "thread-a-id",
threadDisplayName: "线程 A",
folderName: "Talking",
deviceId: "mac-studio",
projectGoal: "完成树莓派二代查询链路",
currentPhase: "功能实现",
currentProgress: "已打通查询接口,正在补手机端展示",
technicalArchitecture: "Next.js API + Android 原生客户端",
currentBlockers: "",
recommendedNextStep: "补会话页展示与排序",
keyFiles: ["src/lib/boss-data.ts"],
keyCommands: ["npm run build"],
updatedAt: "2026-04-04T18:00:00+08:00",
sourceTaskId: "task-1",
sourceKind: "full_sync",
},
];
state.threadProgressEvents = Array.from({ length: 30 }, (_, index) => ({
eventId: `event-${index}`,
projectId: "thread-a",
threadId: "thread-a-id",
threadDisplayName: "线程 A",
deviceId: "mac-studio",
eventType: "progress_updated",
summary: `进展 ${index}`,
phase: "功能实现",
blockerDelta: "",
nextStepDelta: "",
createdAt: `2026-04-04T18:${String(index).padStart(2, "0")}:00+08:00`,
sourceTaskId: `task-${index}`,
}));
await writeState(state);
const normalized = await readState();
assert.equal(normalized.threadStatusDocuments.length, 1);
assert.equal(normalized.threadStatusDocuments[0]?.projectGoal, "完成树莓派二代查询链路");
assert.equal(normalized.threadProgressEvents.length, 20);
assert.equal(normalized.threadProgressEvents[0]?.eventId, "event-29");
});
```
- [ ] **Step 2: 跑测试,确认它先失败**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-sync.test.ts
```
Expected:
- FAIL提示 `threadStatusDocuments``threadProgressEvents` 不存在,或者长度/排序不符合预期
- [ ] **Step 3: 在 `BossState` 里新增模型与归一化逻辑**
`/Users/kris/code/boss/src/lib/boss-data.ts` 增加接口与默认值:
```ts
export interface ThreadStatusDocument {
documentId: string;
projectId: string;
threadId: string;
threadDisplayName: string;
folderName: string;
deviceId: string;
projectGoal: string;
currentPhase: string;
currentProgress: string;
technicalArchitecture: string;
currentBlockers: string;
recommendedNextStep: string;
keyFiles: string[];
keyCommands: string[];
updatedAt: string;
sourceTaskId: string;
sourceKind: "device_import" | "full_sync" | "incremental_sync";
}
export interface ThreadProgressEvent {
eventId: string;
projectId: string;
threadId: string;
threadDisplayName: string;
deviceId: string;
eventType:
| "phase_changed"
| "progress_updated"
| "blocker_added"
| "blocker_resolved"
| "next_step_changed"
| "architecture_updated"
| "handoff_ready";
summary: string;
phase?: string;
blockerDelta?: string;
nextStepDelta?: string;
createdAt: string;
sourceTaskId: string;
sourceMessageId?: string;
}
```
并把状态接入:
```ts
threadStatusDocuments: ensureArray(raw.threadStatusDocuments, []).map((item) => ({
...item,
keyFiles: ensureArray(item.keyFiles, []),
keyCommands: ensureArray(item.keyCommands, []),
})),
threadProgressEvents: ensureArray(raw.threadProgressEvents, [])
.map((item) => ({ ...item }))
.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
.slice(0, 400),
```
`syncDerivedState` 里裁剪每线程最近事件:
```ts
const eventBuckets = new Map<string, ThreadProgressEvent[]>();
for (const event of state.threadProgressEvents) {
const key = `${event.projectId}:${event.threadId}`;
const bucket = eventBuckets.get(key) ?? [];
if (bucket.length < 20) bucket.push(event);
eventBuckets.set(key, bucket);
}
state.threadProgressEvents = [...eventBuckets.values()].flat();
```
- [ ] **Step 4: 重新跑测试,确认通过**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-sync.test.ts
```
Expected:
- PASS
- [ ] **Step 5: 提交这一小步**
```bash
git add /Users/kris/code/boss/src/lib/boss-data.ts /Users/kris/code/boss/tests/thread-status-sync.test.ts
git commit -m "feat: add thread status document models"
```
### Task 2: 用线程状态文档替代常态全量理解
**Files:**
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
- Test: `/Users/kris/code/boss/tests/device-import-draft.test.ts`
- Test: `/Users/kris/code/boss/tests/thread-status-sync.test.ts`
- [ ] **Step 1: 写失败测试锁住“heartbeat 优先记增量,不总是排全量理解”**
```ts
test("active thread updates create lightweight progress events before full re-sync", async () => {
const state = await readState();
const project = state.projects.find((item) => item.id !== "master-agent" && item.threadMeta.codexThreadRef);
assert.ok(project);
project!.projectUnderstanding = {
projectGoal: "目标 A",
currentProgress: "旧进度",
technicalArchitecture: "旧架构",
currentBlockers: "",
recommendedNextStep: "旧下一步",
sourceTaskId: "task-old",
updatedAt: "2026-04-04T10:00:00+08:00",
sourceKind: "thread_sync",
};
state.threadStatusDocuments = [
{
documentId: "doc-old",
projectId: project!.id,
threadId: project!.threadMeta.threadId,
threadDisplayName: project!.threadMeta.threadDisplayName,
folderName: project!.threadMeta.folderName,
deviceId: project!.deviceIds[0]!,
projectGoal: "目标 A",
currentPhase: "功能实现",
currentProgress: "旧进度",
technicalArchitecture: "旧架构",
currentBlockers: "",
recommendedNextStep: "旧下一步",
keyFiles: [],
keyCommands: [],
updatedAt: "2026-04-04T10:00:00+08:00",
sourceTaskId: "task-old",
sourceKind: "full_sync",
},
];
// 用已有 heartbeat 处理函数或相关 helper 驱动活跃更新
const result = await upsertThreadProgressEventInStateForTest(state, {
projectId: project!.id,
threadId: project!.threadMeta.threadId,
threadDisplayName: project!.threadMeta.threadDisplayName,
deviceId: project!.deviceIds[0]!,
eventType: "progress_updated",
summary: "已完成手机端排序修复",
phase: "功能实现",
createdAt: "2026-04-04T12:00:00+08:00",
sourceTaskId: "task-new",
});
assert.equal(result.threadProgressEvents[0]?.summary, "已完成手机端排序修复");
assert.equal(
result.masterAgentTasks.some((task) => task.projectUnderstandingTargetProjectId === project!.id),
false,
);
});
```
- [ ] **Step 2: 跑测试,确认先失败**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-sync.test.ts /Users/kris/code/boss/tests/device-import-draft.test.ts
```
Expected:
- FAIL提示没有轻量事件 helper 或仍然直接走完整理解任务
- [ ] **Step 3: 在状态层新增轻量事件写入与全量理解判定**
`/Users/kris/code/boss/src/lib/boss-data.ts` 增加:
```ts
function upsertThreadStatusDocumentInState(
state: BossState,
input: {
projectId: string;
threadId: string;
threadDisplayName: string;
folderName: string;
deviceId: string;
projectGoal: string;
currentPhase: string;
currentProgress: string;
technicalArchitecture: string;
currentBlockers: string;
recommendedNextStep: string;
keyFiles: string[];
keyCommands: string[];
updatedAt: string;
sourceTaskId: string;
sourceKind: ThreadStatusDocument["sourceKind"];
},
) {
const existing = state.threadStatusDocuments.find(
(item) => item.projectId === input.projectId && item.threadId === input.threadId,
);
if (existing) {
Object.assign(existing, input);
return existing;
}
const document: ThreadStatusDocument = {
documentId: randomToken("thread-status"),
...input,
};
state.threadStatusDocuments.unshift(document);
return document;
}
function appendThreadProgressEventInState(
state: BossState,
input: Omit<ThreadProgressEvent, "eventId">,
) {
state.threadProgressEvents.unshift({
eventId: randomToken("thread-event"),
...input,
});
}
```
并把 heartbeat / thread reply 的同步策略改成:
```ts
if (shouldQueueProjectUnderstandingSync(project, observedActivityAt, state)) {
// 仍保留关键时刻全量理解
} else {
appendThreadProgressEventInState(state, {
projectId: project.id,
threadId: project.threadMeta.threadId,
threadDisplayName: project.threadMeta.threadDisplayName,
deviceId: project.deviceIds[0] ?? "mac-studio",
eventType: "progress_updated",
summary: "检测到线程有新活动",
phase: project.projectUnderstanding ? "功能实现" : undefined,
createdAt: observedActivityAt,
sourceTaskId: "heartbeat-auto",
});
}
```
- [ ] **Step 4: 重新跑测试,确认通过**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-sync.test.ts /Users/kris/code/boss/tests/device-import-draft.test.ts
```
Expected:
- PASS
- [ ] **Step 5: 提交这一小步**
```bash
git add /Users/kris/code/boss/src/lib/boss-data.ts /Users/kris/code/boss/tests/thread-status-sync.test.ts /Users/kris/code/boss/tests/device-import-draft.test.ts
git commit -m "feat: add lightweight thread progress events"
```
### Task 3: 主 Agent 默认读取线程状态文档与最近事件
**Files:**
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
- Test: `/Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts`
- [ ] **Step 1: 写失败测试,锁住主 Agent prompt 读取顺序**
```ts
import test from "node:test";
import assert from "node:assert/strict";
import { readState } from "../src/lib/boss-data.ts";
import { buildMasterAgentExecutionPromptForTest } from "../src/lib/boss-master-agent.ts";
test("master agent prompt prefers thread status documents and recent events", async () => {
const state = await readState();
state.threadStatusDocuments = [
{
documentId: "doc-1",
projectId: "demo-thread",
threadId: "thread-1",
threadDisplayName: "树莓派二代查询",
folderName: "Talking",
deviceId: "mac-studio",
projectGoal: "完成树莓派二代问答",
currentPhase: "功能实现",
currentProgress: "已经打通线程排序与会话时间刷新",
technicalArchitecture: "Boss Web + Android + local-agent",
currentBlockers: "群聊回流文案还需要收口",
recommendedNextStep: "继续修群聊回流提示",
keyFiles: ["src/lib/boss-data.ts"],
keyCommands: ["npm run build"],
updatedAt: "2026-04-04T19:00:00+08:00",
sourceTaskId: "task-doc",
sourceKind: "full_sync",
},
];
state.threadProgressEvents = [
{
eventId: "event-1",
projectId: "demo-thread",
threadId: "thread-1",
threadDisplayName: "树莓派二代查询",
deviceId: "mac-studio",
eventType: "progress_updated",
summary: "已完成会话排序修复",
phase: "功能实现",
createdAt: "2026-04-04T19:10:00+08:00",
sourceTaskId: "task-event",
},
];
const prompt = buildMasterAgentExecutionPromptForTest(state, "请接手这个项目继续推进");
assert.match(prompt, /线程状态文档/);
assert.match(prompt, /完成树莓派二代问答/);
assert.match(prompt, /已完成会话排序修复/);
});
```
- [ ] **Step 2: 跑测试,确认先失败**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts
```
Expected:
- FAIL提示当前 prompt 里没有线程状态文档和进展事件
- [ ] **Step 3: 修改主 Agent prompt 组装**
`/Users/kris/code/boss/src/lib/boss-master-agent.ts` 增加线程状态摘要:
```ts
const activeThreadStatusDocs = state.threadStatusDocuments
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt))
.slice(0, 3)
.map((doc) =>
[
`线程状态文档:${doc.threadDisplayName}`,
doc.projectGoal ? `目标=${doc.projectGoal}` : undefined,
doc.currentPhase ? `阶段=${doc.currentPhase}` : undefined,
doc.currentProgress ? `进度=${doc.currentProgress}` : undefined,
doc.technicalArchitecture ? `架构=${doc.technicalArchitecture}` : undefined,
doc.currentBlockers ? `阻塞=${doc.currentBlockers}` : undefined,
doc.recommendedNextStep ? `下一步=${doc.recommendedNextStep}` : undefined,
]
.filter(Boolean)
.join(" / "),
)
.join("\\n");
const recentThreadProgressEvents = state.threadProgressEvents
.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
.slice(0, 5)
.map((event) => `${event.threadDisplayName}${event.summary}`)
.join("\\n");
```
并把返回 prompt 的内容改成:
```ts
"线程状态文档:",
activeThreadStatusDocs || "无",
"",
"最近线程进展:",
recentThreadProgressEvents || "无",
```
- [ ] **Step 4: 重新跑测试,确认通过**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts
```
Expected:
- PASS
- [ ] **Step 5: 提交这一小步**
```bash
git add /Users/kris/code/boss/src/lib/boss-master-agent.ts /Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts
git commit -m "feat: read thread status documents in master agent prompts"
```
### Task 4: 新增线程状态只读 API
**Files:**
- Create: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/thread-status/route.ts`
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
- Test: `/Users/kris/code/boss/tests/thread-status-route.test.ts`
- [ ] **Step 1: 写失败测试,锁住路由返回格式**
```ts
import test from "node:test";
import assert from "node:assert/strict";
import { GET } from "../src/app/api/v1/projects/[projectId]/thread-status/route.ts";
test("GET thread-status returns current document and recent events", async () => {
const response = await GET(
new Request("http://localhost/api/v1/projects/demo-thread/thread-status"),
{ params: Promise.resolve({ projectId: "demo-thread" }) },
);
assert.equal(response.status, 200);
const body = await response.json();
assert.ok(body.threadStatusDocument);
assert.ok(Array.isArray(body.recentProgressEvents));
});
```
- [ ] **Step 2: 跑测试,确认先失败**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-route.test.ts
```
Expected:
- FAIL提示 route 不存在或返回格式不对
- [ ] **Step 3: 实现只读 route**
创建 `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/thread-status/route.ts`
```ts
import { NextResponse } from "next/server";
import { readState } from "@/src/lib/boss-data";
export async function GET(
_request: Request,
{ params }: { params: Promise<{ projectId: string }> },
) {
const { projectId } = await params;
const state = await readState();
const project = state.projects.find((item) => item.id === projectId);
if (!project) {
return NextResponse.json({ error: "PROJECT_NOT_FOUND" }, { status: 404 });
}
const threadStatusDocument =
state.threadStatusDocuments.find((item) => item.projectId === projectId) ?? null;
const recentProgressEvents = state.threadProgressEvents
.filter((item) => item.projectId === projectId)
.sort((a, b) => b.createdAt.localeCompare(a.createdAt))
.slice(0, 5);
return NextResponse.json({
projectId,
threadStatusDocument,
recentProgressEvents,
});
}
```
- [ ] **Step 4: 重新跑测试,确认通过**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-route.test.ts
```
Expected:
- PASS
- [ ] **Step 5: 提交这一小步**
```bash
git add /Users/kris/code/boss/src/app/api/v1/projects/[projectId]/thread-status/route.ts /Users/kris/code/boss/tests/thread-status-route.test.ts
git commit -m "feat: add thread status read api"
```
### Task 5: 在线程会话信息页接入线程状态入口
**Files:**
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossApiClient.java`
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java`
- Create: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ThreadStatusActivity.java`
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ConversationInfoActivityTest.java`
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ThreadStatusActivityTest.java`
- [ ] **Step 1: 写失败测试,锁住入口和渲染**
```java
@Test
public void conversationInfoShowsThreadStatusEntryForThreadConversation() {
BossUi.ViewNode root = renderConversationInfoForThread();
assertTrue(viewTreeContainsText(root, "线程状态"));
}
@Test
public void threadStatusActivityRendersCurrentGoalProgressAndNextStep() {
BossUi.ViewNode root = renderThreadStatusActivityWithFixture();
assertTrue(viewTreeContainsText(root, "当前目标"));
assertTrue(viewTreeContainsText(root, "当前进度"));
assertTrue(viewTreeContainsText(root, "建议下一步"));
}
```
- [ ] **Step 2: 跑测试,确认先失败**
Run:
```bash
cd /Users/kris/code/boss/android && ./gradlew testDebugUnitTest --tests com.hyzq.boss.ConversationInfoActivityTest --tests com.hyzq.boss.ThreadStatusActivityTest --no-daemon
```
Expected:
- FAIL提示没有 `线程状态` 入口或 Activity 不存在
- [ ] **Step 3: 实现 Android 入口与只读页**
`/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossApiClient.java` 增加:
```java
public JSONObject getThreadStatus(String projectId) throws IOException, ApiException {
return getJson("/api/v1/projects/" + Uri.encode(projectId) + "/thread-status");
}
```
`/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java` 中,当当前会话是线程会话时增加:
```java
addMenuRow(container, "线程状态", v -> {
Intent intent = new Intent(this, ThreadStatusActivity.class);
intent.putExtra("projectId", projectId);
startActivity(intent);
});
```
创建 `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ThreadStatusActivity.java`,读取接口并展示:
```java
renderSection("当前目标", document.optString("projectGoal"));
renderSection("当前阶段", document.optString("currentPhase"));
renderSection("当前进度", document.optString("currentProgress"));
renderSection("技术架构", document.optString("technicalArchitecture"));
renderSection("当前阻塞", document.optString("currentBlockers"));
renderSection("建议下一步", document.optString("recommendedNextStep"));
renderEvents(recentProgressEvents);
```
- [ ] **Step 4: 重新跑测试,确认通过**
Run:
```bash
cd /Users/kris/code/boss/android && ./gradlew testDebugUnitTest --tests com.hyzq.boss.ConversationInfoActivityTest --tests com.hyzq.boss.ThreadStatusActivityTest --no-daemon
```
Expected:
- PASS
- [ ] **Step 5: 提交这一小步**
```bash
git add /Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossApiClient.java /Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java /Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ThreadStatusActivity.java /Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ConversationInfoActivityTest.java /Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ThreadStatusActivityTest.java
git commit -m "feat: add thread status view in android"
```
### Task 6: 完整回归、文档同步与发版
**Files:**
- Modify: `/Users/kris/code/boss/README.md`
- Modify: `/Users/kris/code/boss/docs/architecture/current_runtime_and_deploy_status_cn.md`
- Modify: `/Users/kris/code/boss/docs/architecture/api_and_service_inventory_cn.md`
- [ ] **Step 1: 同步文档**
在文档里明确新增:
```md
- 主 Agent 当前会优先读取线程状态文档和最近进展事件,而不是常态反复重跑完整理解
- 已导入设备与新导入设备都走统一的线程状态同步链
- 线程会话信息页新增只读 `线程状态`
```
- [ ] **Step 2: 跑完整关键回归**
Run:
```bash
npx --yes tsx --test /Users/kris/code/boss/tests/thread-status-sync.test.ts /Users/kris/code/boss/tests/device-import-draft.test.ts /Users/kris/code/boss/tests/master-agent-thread-status-prompt.test.ts /Users/kris/code/boss/tests/thread-status-route.test.ts
npm run lint
npm run build
cd /Users/kris/code/boss/android && ./gradlew testDebugUnitTest --tests com.hyzq.boss.ConversationInfoActivityTest --tests com.hyzq.boss.ThreadStatusActivityTest --no-daemon
cd /Users/kris/code/boss/android && ./gradlew assembleRelease --no-daemon
```
Expected:
- 全部 PASS
- build 成功
- Android release 包成功生成
- [ ] **Step 3: 部署服务器**
Run:
```bash
sshpass -p 'Asd123456.' ssh -o StrictHostKeyChecking=no ubuntu@106.53.170.158 "sudo rm -rf /opt/boss/.next && sudo mkdir -p /opt/boss/.next && sudo chown -R ubuntu:ubuntu /opt/boss /opt/boss/.next"
sshpass -p 'Asd123456.' rsync -az --delete -e "ssh -o StrictHostKeyChecking=no" --exclude '.git/' --exclude 'node_modules/' --exclude 'data/' --exclude '.superpowers/' --exclude 'public/downloads/' /Users/kris/code/boss/ ubuntu@106.53.170.158:/opt/boss/
sshpass -p 'Asd123456.' ssh -o StrictHostKeyChecking=no ubuntu@106.53.170.158 "cd /opt/boss && sudo systemctl restart boss-web && sudo systemctl restart caddy && curl -fsS http://127.0.0.1:3000/api/health"
curl -fsS https://boss.hyzq.net/api/health
```
Expected:
- 远端本机健康检查返回 `ok:true`
- 公网健康检查返回 `ok:true`
- [ ] **Step 4: 最终提交**
```bash
git add /Users/kris/code/boss/README.md /Users/kris/code/boss/docs/architecture/current_runtime_and_deploy_status_cn.md /Users/kris/code/boss/docs/architecture/api_and_service_inventory_cn.md
git commit -m "feat: add thread status sync pipeline"
git push gitea codex/wechat-native-ui-rollback
```
---
## 自检
### Spec 覆盖
- 线程状态文档Task 1
- 线程进展事件Task 1 / Task 2
- 主 Agent 读取“文档 + 最近事件”Task 3
- 关键时刻深拉保留Task 2 / Task 3
- APP 只读查看线程状态Task 4 / Task 5
- 不写入项目仓库:通过 Task 1-5 全部走 Boss 内部状态层实现
### Placeholder 扫描
- 没有 `TBD / TODO / implement later`
- 每个任务都给了文件、代码、命令和预期结果
### 类型一致性
- 线程状态文档统一命名为 `ThreadStatusDocument`
- 增量事件统一命名为 `ThreadProgressEvent`
- API 字段统一用 `threadStatusDocument / recentProgressEvents`