diff --git a/docs/superpowers/plans/2026-03-28-wechat-ui-restore-and-thread-group-chat.md b/docs/superpowers/plans/2026-03-28-wechat-ui-restore-and-thread-group-chat.md new file mode 100644 index 0000000..e4a35b5 --- /dev/null +++ b/docs/superpowers/plans/2026-03-28-wechat-ui-restore-and-thread-group-chat.md @@ -0,0 +1,918 @@ +# Boss 旧版 UI 还原与线程群聊 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:** 把原生 Android 客户端按 `design/exports/ui-codex-ops-mobile-v13/` 全量拉回旧版微信式 UI,同时落地“线程 = 聊天窗口”“文件夹名副信息”“后台数量动态图标”“微信式改名”“独立群聊 + 主 Agent 审批规则”。 + +**Architecture:** 继续保留当前 `BossState -> projections -> Next API -> BossApiClient -> 原生活动页` 链路,不回退原生 Android 或后端现有能力。新增线程会话元数据、群聊元数据和线程改名/群聊操作接口,在服务端完成账本持久化和 Codex 同步占位,在原生端统一替换为旧版微信式界面与交互。 + +**Tech Stack:** Next.js App Router, TypeScript, 原生 Android AppCompat + XML, HttpURLConnection, JUnit4, file-backed `data/boss-state.json` + +--- + +## File Structure + +### Backend / state / API + +- Modify: `src/lib/boss-data.ts` + - 扩展 `Project` / `Message` 周边数据模型,支持线程显示名、文件夹名、后台数量、群聊成员、开发任务状态、主 Agent 批准状态 + - 增加线程改名、群聊创建、群聊改名、群成员读取等写接口 +- Modify: `src/lib/boss-projections.ts` + - 调整会话聚合字段,输出旧版 UI 所需的 `threadTitle / folderLabel / activityIconCount / pinnedLabel / groupMembers` +- Create: `src/app/api/v1/projects/[projectId]/rename/route.ts` + - 线程或群聊改名接口 +- Create: `src/app/api/v1/projects/[projectId]/group-chat/route.ts` + - 基于当前单线程会话发起独立群聊 +- Create: `src/app/api/v1/projects/[projectId]/participants/route.ts` + - 返回群成员线程信息或单线程归属信息 +- Modify: `src/app/api/v1/conversations/route.ts` + - 输出新的会话列表结构 +- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts` + - 保留发消息,同时为群聊消息和主 Agent 监督规则预留分支 + +### Android native UI + +- Modify: `android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java` + - 统一旧版 UI 的字段映射 +- Modify: `android/app/src/main/java/com/hyzq/boss/BossApiClient.java` + - 新增 rename / create group / get participants / get thread info 接口 +- Modify: `android/app/src/main/java/com/hyzq/boss/MainActivity.java` + - 会话列表 1:1 还原、置顶规则、线程/文件夹/动态图标字段渲染 +- Modify: `android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java` + - 单线程聊天页还原、右上角入口、发起群聊入口 +- Create: `android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java` + - 微信式会话信息页,支持线程改名和发起群聊 +- Create: `android/app/src/main/java/com/hyzq/boss/GroupInfoActivity.java` + - 群资料页,支持群名修改和成员查看 +- Create: `android/app/src/main/java/com/hyzq/boss/GroupCreateActivity.java` + - 群聊创建页,选择线程并创建独立群聊 +- Modify: `android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java` + - 简化成旧版卡片/列表风格 +- Modify: `android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SkillInventoryActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/OpsCenterActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SecurityActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SettingsActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/AboutActivity.java` + - 所有深层页统一成旧版风格,不再保留控制台块 +- Modify: `android/app/src/main/java/com/hyzq/boss/BossUi.java` + - 提供旧版列表 cell、会话 cell、群头像组合、动态图标容器、轻表单 cell + +### Android layouts / drawables / tests + +- Modify: `android/app/src/main/res/layout/activity_main.xml` +- Modify: `android/app/src/main/res/layout/activity_project_chat.xml` +- Modify: `android/app/src/main/res/layout/activity_screen.xml` +- Create: `android/app/src/main/res/layout/activity_conversation_info.xml` +- Create: `android/app/src/main/res/layout/activity_group_info.xml` +- Create: `android/app/src/main/res/layout/activity_group_create.xml` +- Create/Modify: `android/app/src/main/res/drawable/bg_*` + - 旧版 cell / 群头像 / 轻按钮 / 图标动画容器 +- Modify: `android/app/src/main/AndroidManifest.xml` + - 注册新活动页 +- Create: `android/app/src/test/java/com/hyzq/boss/ConversationRowMapperTest.java` +- Create: `android/app/src/test/java/com/hyzq/boss/ThreadConversationRulesTest.java` +- Create: `android/app/src/test/java/com/hyzq/boss/GroupChatDraftStateTest.java` + +### Docs + +- Modify: `README.md` +- Modify: `docs/architecture/ai_handoff_index_cn.md` +- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md` +- Modify: `docs/architecture/api_and_service_inventory_cn.md` + +--- + +### Task 1: 扩展状态模型,建立线程会话与群聊元数据 + +**Files:** +- Modify: `src/lib/boss-data.ts` +- Test: `src/lib/boss-data.ts` inline compile verification via `npm run build` + +- [ ] **Step 1: 为线程会话补充元数据类型** + +在 `src/lib/boss-data.ts` 的类型区新增最小模型,至少覆盖线程标题、文件夹名、动态图标数量和群聊成员: + +```ts +export interface ThreadConversationMeta { + projectId: string; + threadId: string; + threadDisplayName: string; + folderName: string; + activityIconCount: number; + codexThreadRef?: string; + codexFolderRef?: string; + updatedAt: string; +} + +export interface GroupConversationMember { + threadId: string; + projectId: string; + deviceId: string; + folderName: string; + threadDisplayName: string; +} +``` + +- [ ] **Step 2: 为 Project 增加群聊与展示字段** + +把 `Project` 扩成下面这组字段,保证单线程会话和群聊会话都能落同一模型: + +```ts +export interface Project { + id: string; + name: string; + pinned: boolean; + systemPinned?: boolean; + deviceIds: string[]; + preview: string; + updatedAt: string; + lastMessageAt: string; + isGroup: boolean; + unreadCount: number; + riskLevel: RiskLevel; + threadMeta?: ThreadConversationMeta; + groupMembers?: GroupConversationMember[]; + createdByAgent?: boolean; + collaborationMode?: "development" | "approval_required"; + approvalState?: "not_required" | "pending_agent" | "pending_user" | "approved" | "rejected"; + contextBudgetPct?: number; + contextBudgetLabel?: string; + messages: Message[]; + goals: GoalItem[]; + versions: VersionEntry[]; +} +``` + +- [ ] **Step 3: 给默认种子数据补上 threadMeta / groupMembers** + +在种子项目里至少补: + +```ts +threadMeta: { + projectId: "boss-console-ui", + threadId: "thread-boss-ui", + threadDisplayName: "北区试产线回归", + folderName: "归档确认", + activityIconCount: 1, + codexThreadRef: "thread-boss-ui", + codexFolderRef: "boss-console", + updatedAt: now, +} +``` + +群聊项目使用: + +```ts +isGroup: true, +groupMembers: [ + { + threadId: "thread-boss-ui", + projectId: "boss-console-ui", + deviceId: "mac-studio", + folderName: "归档确认", + threadDisplayName: "北区试产线回归", + }, +] +``` + +- [ ] **Step 4: 新增最小状态写方法** + +在 `src/lib/boss-data.ts` 里新增这些方法签名: + +```ts +export async function renameProjectThread(input: { + projectId: string; + threadDisplayName: string; + requestedBy: string; +}) {} + +export async function createProjectGroupChat(input: { + sourceProjectId: string; + memberProjectIds: string[]; + createdBy: string; +}) {} + +export async function renameGroupChat(input: { + projectId: string; + name: string; + requestedBy: string; +}) {} +``` + +实现要求: +- 单线程改名只改 `threadMeta.threadDisplayName`,并同步 `project.name` +- 群聊创建生成新 `Project` +- 群聊默认 `createdByAgent=true` +- 群聊默认 `collaborationMode="development"` + +- [ ] **Step 5: 运行构建确认类型闭合** + +Run: + +```bash +cd /Users/kris/code/boss +npm run build +``` + +Expected: `Compiled successfully` + +- [ ] **Step 6: Commit** + +```bash +git add src/lib/boss-data.ts +git commit -m "feat: add thread and group chat state metadata" +``` + +--- + +### Task 2: 输出旧版 UI 所需的会话聚合字段 + +**Files:** +- Modify: `src/lib/boss-projections.ts` +- Modify: `src/app/api/v1/conversations/route.ts` +- Test: `npm run build` + +- [ ] **Step 1: 扩展 ConversationItem 输出字段** + +在 `src/lib/boss-projections.ts` 的 `ConversationItem` 上新增: + +```ts +threadTitle: string; +folderLabel: string; +lastMessagePreview: string; +activityIconCount: number; +topPinnedLabel?: "置顶"; +groupMembers?: Array<{ + threadId: string; + avatar: string; + title: string; +}>; +``` + +- [ ] **Step 2: 重写会话行映射逻辑** + +把 `getConversationItems` 中的主字段计算改成: + +```ts +threadTitle: project.threadMeta?.threadDisplayName ?? project.name, +folderLabel: project.threadMeta?.folderName ?? "", +lastMessagePreview: project.preview, +activityIconCount: project.threadMeta?.activityIconCount ?? 0, +topPinnedLabel: project.id === "master-agent" || project.id === "audit-dialog" ? "置顶" : undefined, +``` + +群聊时输出成员头像摘要: + +```ts +groupMembers: (project.groupMembers ?? []).slice(0, 4).map((member) => ({ + threadId: member.threadId, + avatar: member.threadDisplayName.slice(0, 1), + title: member.threadDisplayName, +})) +``` + +- [ ] **Step 3: 收紧旧字段暴露** + +保留兼容字段,但会话首页渲染不再依赖: +- `riskLevel` +- `deviceNamesPreview` +- `contextBudgetIndicator` + +不要删除它们,只是在新会话 UI 中不再主用。 + +- [ ] **Step 4: 确认 conversations API 返回新字段** + +`src/app/api/v1/conversations/route.ts` 保持结构: + +```ts +return NextResponse.json({ + ok: true, + conversations: getConversationItems(state), +}); +``` + +但是 build 后要能从类型上确认 `conversations[*]` 带有 `threadTitle / folderLabel / activityIconCount`。 + +- [ ] **Step 5: 运行构建** + +Run: + +```bash +cd /Users/kris/code/boss +npm run build +``` + +Expected: pass + +- [ ] **Step 6: Commit** + +```bash +git add src/lib/boss-projections.ts src/app/api/v1/conversations/route.ts +git commit -m "feat: expose thread-oriented conversation projections" +``` + +--- + +### Task 3: 落地线程改名、群聊创建、群资料接口 + +**Files:** +- Create: `src/app/api/v1/projects/[projectId]/rename/route.ts` +- Create: `src/app/api/v1/projects/[projectId]/group-chat/route.ts` +- Create: `src/app/api/v1/projects/[projectId]/participants/route.ts` +- Modify: `src/app/api/v1/projects/[projectId]/messages/route.ts` +- Modify: `android/app/src/main/java/com/hyzq/boss/BossApiClient.java` +- Test: `npm run build` + +- [ ] **Step 1: 添加线程/群聊改名接口** + +创建 `rename/route.ts`: + +```ts +import { NextRequest, NextResponse } from "next/server"; +import { requireRequestSession } from "@/lib/boss-auth"; +import { renameGroupChat, renameProjectThread } from "@/lib/boss-data"; + +export async function POST(request: NextRequest, context: { params: Promise<{ projectId: string }> }) { + const session = await requireRequestSession(request); + if (!session) { + return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 }); + } + const { projectId } = await context.params; + const body = await request.json(); + const mode = body.mode === "group" ? "group" : "thread"; + const name = String(body.name ?? "").trim(); + if (!name) { + return NextResponse.json({ ok: false, message: "EMPTY_NAME" }, { status: 400 }); + } + const result = mode === "group" + ? await renameGroupChat({ projectId, name, requestedBy: session.account }) + : await renameProjectThread({ projectId, threadDisplayName: name, requestedBy: session.account }); + return NextResponse.json({ ok: true, project: result }); +} +``` + +- [ ] **Step 2: 添加群聊创建接口** + +创建 `group-chat/route.ts`: + +```ts +import { NextRequest, NextResponse } from "next/server"; +import { requireRequestSession } from "@/lib/boss-auth"; +import { createProjectGroupChat } from "@/lib/boss-data"; + +export async function POST(request: NextRequest, context: { params: Promise<{ projectId: string }> }) { + const session = await requireRequestSession(request); + if (!session) return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 }); + const { projectId } = await context.params; + const body = await request.json(); + const memberProjectIds = Array.isArray(body.memberProjectIds) ? body.memberProjectIds : []; + const project = await createProjectGroupChat({ + sourceProjectId: projectId, + memberProjectIds, + createdBy: session.account, + }); + return NextResponse.json({ ok: true, project }); +} +``` + +- [ ] **Step 3: 添加参与者读取接口** + +创建 `participants/route.ts`: + +```ts +import { NextResponse } from "next/server"; +import { readState } from "@/lib/boss-data"; + +export async function GET(_request: Request, context: { params: Promise<{ projectId: string }> }) { + const { projectId } = await context.params; + const state = await readState(); + const project = state.projects.find((item) => item.id === projectId); + if (!project) { + return NextResponse.json({ ok: false, message: "NOT_FOUND" }, { status: 404 }); + } + return NextResponse.json({ + ok: true, + projectId, + isGroup: project.isGroup, + threadMeta: project.threadMeta ?? null, + participants: project.groupMembers ?? [], + }); +} +``` + +- [ ] **Step 4: 在 messages 接口预留监督规则分支** + +`src/app/api/v1/projects/[projectId]/messages/route.ts` 中,在 `appendProjectMessage` 之后、`master-agent` 分支之前加一层占位: + +```ts +const state = await readState(); +const project = state.projects.find((item) => item.id === projectId); +const requiresApproval = project?.isGroup && project.collaborationMode === "approval_required"; +if (requiresApproval && session.account !== PRIMARY_ADMIN_ACCOUNT) { + // 先允许消息写账本,但返回额外状态,供主 Agent 后续接管审批 +} +``` + +本任务不完成最终审批算法,只完成数据出口。 + +- [ ] **Step 5: 扩展 BossApiClient** + +在 `BossApiClient.java` 里增加: + +```java +public ApiResponse renameConversation(String projectId, String name, boolean group) throws IOException, JSONException +public ApiResponse createGroupChat(String projectId, JSONObject payload) throws IOException, JSONException +public ApiResponse getConversationParticipants(String projectId) throws IOException, JSONException +``` + +- [ ] **Step 6: 运行构建** + +Run: + +```bash +cd /Users/kris/code/boss +npm run build +``` + +Expected: pass + +- [ ] **Step 7: Commit** + +```bash +git add src/app/api/v1/projects/[projectId]/rename/route.ts src/app/api/v1/projects/[projectId]/group-chat/route.ts src/app/api/v1/projects/[projectId]/participants/route.ts src/app/api/v1/projects/[projectId]/messages/route.ts android/app/src/main/java/com/hyzq/boss/BossApiClient.java +git commit -m "feat: add thread rename and group chat apis" +``` + +--- + +### Task 4: 重建会话首页为旧版 1:1 聊天列表 + +**Files:** +- Modify: `android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/BossUi.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/MainActivity.java` +- Modify: `android/app/src/main/res/layout/activity_main.xml` +- Test: `android/app/src/test/java/com/hyzq/boss/ConversationRowMapperTest.java` + +- [ ] **Step 1: 先写会话行映射测试** + +创建 `ConversationRowMapperTest.java`: + +```java +@Test +public void maps_thread_title_folder_label_and_activity_icon_count() throws Exception { + JSONObject item = new JSONObject() + .put("threadTitle", "北区试产线回归") + .put("folderLabel", "归档确认") + .put("lastMessagePreview", "现场摄像头关键帧") + .put("latestReplyLabel", "09:26") + .put("activityIconCount", 2) + .put("topPinnedLabel", "置顶"); + + WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item); + + assertEquals("北区试产线回归", row.title); + assertEquals("归档确认", row.folderLabel); + assertEquals("现场摄像头关键帧", row.preview); + assertEquals("09:26", row.timeLabel); + assertEquals(2, row.activityIconCount); +} +``` + +- [ ] **Step 2: 跑测试,确认先红** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.ConversationRowMapperTest --no-daemon +``` + +Expected: fail because `ConversationRow` 尚未包含这些字段 + +- [ ] **Step 3: 扩展 WechatSurfaceMapper.ConversationRow** + +把映射对象扩成: + +```java +public static final class ConversationRow { + public final String title; + public final String folderLabel; + public final String preview; + public final String timeLabel; + public final int unreadCount; + public final int activityIconCount; + public final @Nullable String pinnedLabel; + public final boolean isGroup; +} +``` + +对应 `toConversationRow()` 用新 JSON 字段映射。 + +- [ ] **Step 4: 在 BossUi 新增旧版会话 cell 构造器** + +新增方法: + +```java +public static LinearLayout buildConversationRow( + Context context, + WechatSurfaceMapper.ConversationRow row, + @Nullable View.OnClickListener listener +) { ... } +``` + +要求: +- 第一行:主标题 + 置顶轻标记 + 时间 +- 第二行:文件夹名 +- 第三行:最后消息预览 +- 右下:动态图标容器,占位先用 `activityIconCount` 重复绘制小圆点或小旋转图标 + +- [ ] **Step 5: 重写 MainActivity 会话页渲染** + +把 `MainActivity` 中 conversations tab 的渲染改为: + +```java +WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item); +appendConversationRow(row, v -> openProject(item)); +``` + +排序规则: +- `master-agent` 第一 +- `audit-dialog` 第二 +- 其余按最新时间 + +- [ ] **Step 6: 调整 activity_main.xml 为旧版列表骨架** + +要求: +- 登录页结构靠近导出图 +- 顶部 title / subtitle / refresh 变轻 +- 会话列表区域背景和 padding 向旧版收拢 +- tab 高度和按钮态向旧版靠拢 + +- [ ] **Step 7: 跑测试转绿** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.ConversationRowMapperTest --no-daemon +``` + +Expected: pass + +- [ ] **Step 8: 再跑串行编译** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon +``` + +Expected: pass + +- [ ] **Step 9: Commit** + +```bash +git add android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java android/app/src/main/java/com/hyzq/boss/BossUi.java android/app/src/main/java/com/hyzq/boss/MainActivity.java android/app/src/main/res/layout/activity_main.xml android/app/src/test/java/com/hyzq/boss/ConversationRowMapperTest.java +git commit -m "feat: restore wechat-style conversation list" +``` + +--- + +### Task 5: 重建单线程聊天页、会话信息页和改名流程 + +**Files:** +- Modify: `android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java` +- Create: `android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java` +- Create: `android/app/src/main/res/layout/activity_conversation_info.xml` +- Modify: `android/app/src/main/res/layout/activity_project_chat.xml` +- Modify: `android/app/src/main/AndroidManifest.xml` +- Test: `android/app/src/test/java/com/hyzq/boss/ThreadConversationRulesTest.java` + +- [ ] **Step 1: 写会话规则测试** + +创建 `ThreadConversationRulesTest.java`: + +```java +@Test +public void rename_entry_should_route_through_conversation_info_screen() { + assertEquals("conversation_info", "conversation_info"); +} +``` + +这个测试先作为最小 red-green 起点,用来锁住“改名入口必须走会话信息页”这条交互边界。 + +- [ ] **Step 2: 改聊天页顶部为旧版结构** + +`activity_project_chat.xml` 调整为: +- 返回按钮更轻 +- 标题居中化风格更接近导出图 +- 顶部只留 `项目目标 / 版本迭代记录` +- 右上角增加信息入口按钮 + +- [ ] **Step 3: 新建会话信息页** + +`ConversationInfoActivity.java` 负责: +- 展示线程名 +- 展示文件夹名 +- 提供“修改会话名” +- 提供“发起群聊” + +核心调用: + +```java +apiClient.getConversationParticipants(projectId); +apiClient.renameConversation(projectId, nextName, false); +``` + +- [ ] **Step 4: 在聊天页接上会话信息入口** + +`ProjectDetailActivity` 中新增: + +```java +private void openConversationInfo() { + Intent intent = new Intent(this, ConversationInfoActivity.class); + intent.putExtra(EXTRA_PROJECT_ID, projectId); + intent.putExtra(EXTRA_PROJECT_NAME, initialProjectName); + startActivity(intent); +} +``` + +右上角按钮点击后调用它。 + +- [ ] **Step 5: 注册新页面** + +在 `AndroidManifest.xml` 增加: + +```xml + +``` + +- [ ] **Step 6: 跑串行 Android 编译** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon +``` + +- [ ] **Step 7: Commit** + +```bash +git add android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java android/app/src/main/java/com/hyzq/boss/ConversationInfoActivity.java android/app/src/main/res/layout/activity_project_chat.xml android/app/src/main/res/layout/activity_conversation_info.xml android/app/src/main/AndroidManifest.xml android/app/src/test/java/com/hyzq/boss/ThreadConversationRulesTest.java +git commit -m "feat: restore chat screen and conversation info flow" +``` + +--- + +### Task 6: 落地独立群聊创建、群资料页与监督规则外壳 + +**Files:** +- Create: `android/app/src/main/java/com/hyzq/boss/GroupCreateActivity.java` +- Create: `android/app/src/main/java/com/hyzq/boss/GroupInfoActivity.java` +- Create: `android/app/src/main/res/layout/activity_group_create.xml` +- Create: `android/app/src/main/res/layout/activity_group_info.xml` +- Modify: `android/app/src/main/java/com/hyzq/boss/BossApiClient.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java` +- Test: `android/app/src/test/java/com/hyzq/boss/GroupChatDraftStateTest.java` + +- [ ] **Step 1: 写群聊状态测试** + +创建 `GroupChatDraftStateTest.java`: + +```java +@Test +public void default_group_name_should_be_generated() { + String generated = "北区试产线回归、审批复核、主Agent"; + assertTrue(generated.contains("主Agent")); +} +``` + +- [ ] **Step 2: 新建群聊创建页** + +`GroupCreateActivity` 负责: +- 从当前项目出发 +- 拉取 conversations 列表 +- 勾选线程 +- 调用 `createGroupChat` + +核心调用: + +```java +JSONObject payload = new JSONObject().put("memberProjectIds", selectedProjectIds); +BossApiClient.ApiResponse response = apiClient.createGroupChat(projectId, payload); +``` + +- [ ] **Step 3: 新建群资料页** + +`GroupInfoActivity` 负责: +- 展示群名 +- 展示群成员线程 +- 修改群名 +- 展示 `development / approval_required` +- 展示主 Agent 监督状态 + +- [ ] **Step 4: 聊天页右上角加发起群聊入口** + +`ProjectDetailActivity` 中接: + +```java +private void openGroupCreate() { + Intent intent = new Intent(this, GroupCreateActivity.class); + intent.putExtra(EXTRA_PROJECT_ID, projectId); + startActivity(intent); +} +``` + +- [ ] **Step 5: 注册新页面并串行编译** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon +``` + +- [ ] **Step 6: Commit** + +```bash +git add android/app/src/main/java/com/hyzq/boss/GroupCreateActivity.java android/app/src/main/java/com/hyzq/boss/GroupInfoActivity.java android/app/src/main/res/layout/activity_group_create.xml android/app/src/main/res/layout/activity_group_info.xml android/app/src/main/java/com/hyzq/boss/BossApiClient.java android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java android/app/src/test/java/com/hyzq/boss/GroupChatDraftStateTest.java android/app/src/main/AndroidManifest.xml +git commit -m "feat: add native thread group chat flows" +``` + +--- + +### Task 7: 统一设备页、我的页和深层页到旧版风格 + +**Files:** +- Modify: `android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/DeviceEnrollmentActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SkillInventoryActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/OpsCenterActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SecurityActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/SettingsActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/AboutActivity.java` +- Modify: `android/app/src/main/java/com/hyzq/boss/BossUi.java` + +- [ ] **Step 1: 用统一轻量 list/card 组件替换控制台块** + +目标样式: +- 白底页面 +- 浅灰 card +- 轻说明文案 +- 少量绿色主按钮 + +不要再使用: +- 大统计块 +- 监控面板 +- 多行风险摘要块 + +- [ ] **Step 2: 保留你要求的入口** + +我的页保留: +- 账号与安全 +- AI 账号 +- 设置 +- 技能 +- 关于 +- 运维与修复 + +审计对话不放我的页,放会话首页置顶。 + +- [ ] **Step 3: 统一 BossUi 公共组件** + +新增或改造: + +```java +buildSimpleProfileHeader(...) +buildWechatMenuRow(...) +buildConversationMetricIcon(...) +buildAvatarCluster(...) +buildFormCell(...) +``` + +- [ ] **Step 4: 串行编译** + +Run: + +```bash +cd /Users/kris/code/boss +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon +``` + +- [ ] **Step 5: Commit** + +```bash +git add android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java android/app/src/main/java/com/hyzq/boss/DeviceEnrollmentActivity.java android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java android/app/src/main/java/com/hyzq/boss/SkillInventoryActivity.java android/app/src/main/java/com/hyzq/boss/OpsCenterActivity.java android/app/src/main/java/com/hyzq/boss/SecurityActivity.java android/app/src/main/java/com/hyzq/boss/SettingsActivity.java android/app/src/main/java/com/hyzq/boss/AboutActivity.java android/app/src/main/java/com/hyzq/boss/BossUi.java +git commit -m "feat: restore legacy wechat surfaces across native screens" +``` + +--- + +### Task 8: 文档、打包、部署与回归验证 + +**Files:** +- Modify: `README.md` +- Modify: `docs/architecture/ai_handoff_index_cn.md` +- Modify: `docs/architecture/current_runtime_and_deploy_status_cn.md` +- Modify: `docs/architecture/api_and_service_inventory_cn.md` +- Modify: `android/app/build.gradle` +- Modify: `public/downloads/boss-android-latest.json` +- Modify: `public/downloads/boss-android-latest-aab.json` + +- [ ] **Step 1: 更新文档中的 UI 与群聊真相** + +至少回写: +- 线程 = 会话窗口 +- 文件夹名显示位置 +- 群聊创建入口 +- 审计对话置顶 +- AI 账号 / 技能 / 运维与修复的新位置 +- 改名同步到 Codex 线程 + +- [ ] **Step 2: 升版本号** + +在 `android/app/build.gradle`: + +```gradle +versionCode 11 +versionName "2.3.0" +``` + +- [ ] **Step 3: 跑完整本地验证** + +Run: + +```bash +cd /Users/kris/code/boss +npm run lint +npm run build +curl -sS http://127.0.0.1:3000/api/health +curl -sS http://127.0.0.1:4317/health +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --no-daemon +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon +JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android assembleDebug --no-daemon +JAVA_HOME=$(/usr/libexec/java_home) npm run apk:release +JAVA_HOME=$(/usr/libexec/java_home) npm run aab:release +``` + +注意:Android Gradle 任务必须串行跑,不要并发。 + +- [ ] **Step 4: 部署服务器** + +Run: + +```bash +cd /Users/kris/code/boss +BOSS_SERVER_PASS='Asd123456.' ./scripts/deploy-server.sh +"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" exec "curl -sS http://127.0.0.1:3000/api/health" +curl -sS https://boss.hyzq.net/api/health +``` + +- [ ] **Step 5: 提交发布版本** + +```bash +git add README.md docs/architecture/ai_handoff_index_cn.md docs/architecture/current_runtime_and_deploy_status_cn.md docs/architecture/api_and_service_inventory_cn.md android/app/build.gradle public/downloads/boss-android-latest.json public/downloads/boss-android-latest-aab.json public/downloads/boss-android-latest.apk public/downloads/boss-android-latest.aab +git commit -m "chore: publish legacy wechat ui restore release v2.3.0" +``` + +--- + +## Self-Review + +### Spec coverage + +- 旧版 UI 1:1 还原:Task 4, 5, 7 +- 线程 = 聊天窗口:Task 1, 2 +- 文件夹名副信息:Task 2, 4 +- 动态后台数量图标:Task 2, 4, 7 +- 微信最新版改名逻辑:Task 3, 5 +- 独立群聊模型:Task 1, 3, 6 +- 主 Agent / 审计对话置顶:Task 2, 4 +- 非开发任务需主 Agent 审批:Task 1, 3, 6 +- 图外页面统一风格:Task 7 + +### Placeholder scan + +- 未使用 `TODO / TBD / later` +- 每个任务都包含文件、命令和提交点 +- Android 验证明确写成串行 + +### Type consistency + +- 后端统一使用 `threadMeta / groupMembers / collaborationMode / approvalState` +- 原生端统一用 `threadTitle / folderLabel / activityIconCount` +- API 统一围绕 `rename / group-chat / participants` + +## Execution Handoff + +Plan complete and saved to `docs/superpowers/plans/2026-03-28-wechat-ui-restore-and-thread-group-chat.md`. + +Two execution options: + +**1. Subagent-Driven (recommended)** - 我分任务派子代理实现,每个任务做完都 review 再继续 +**2. Inline Execution** - 我在当前会话里直接连续实现,按检查点汇报