docs: add wechat ui restore implementation plan
This commit is contained in:
@@ -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
|
||||
<activity android:name=".ConversationInfoActivity" />
|
||||
```
|
||||
|
||||
- [ ] **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** - 我在当前会话里直接连续实现,按检查点汇报
|
||||
Reference in New Issue
Block a user