27 KiB
WeChat Native UI Rollback 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: Restore the Android app to the previously approved WeChat-like UI and interaction model while keeping the current native Android architecture, Boss API integration, login recovery, and OTA pipeline.
Architecture: Keep BossApiClient, current activities, login restore, OTA delivery, and backend routes intact. Add a small pure-Java surface-mapping helper with unit tests so the “allowed” WeChat-style information density is explicit, then rework MainActivity, shared UI helpers, and the core activities to render simple list-driven surfaces and a chat-first conversation page. Advanced ops capability stays in the codebase but leaves the first-level UI.
Tech Stack: Android AppCompat, XML layouts, Java 21, Gradle 8, JUnit4, existing Boss APIs, adb, existing npm run apk:release / npm run aab:release / scripts/deploy-server.sh.
File Structure
New files
android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java- Pure-Java contract for root tabs, conversation rows, device rows, my-page menus, and project quick actions.
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java- Unit tests for WeChat-style information trimming and tab/menu contract.
android/app/src/main/res/layout/activity_project_chat.xml- Chat-first project detail layout with lightweight header strip and bottom composer.
android/app/src/main/res/drawable/bg_list_row.xml- Flat white list-cell background with subtle divider feel.
android/app/src/main/res/drawable/bg_tab_active.xml- Active bottom-tab background.
android/app/src/main/res/drawable/bg_tab_inactive.xml- Inactive bottom-tab background.
android/app/src/main/res/drawable/bg_message_incoming.xml- Incoming message bubble background.
android/app/src/main/res/drawable/bg_message_outgoing.xml- Outgoing message bubble background.
scripts/verify-native-wechat-release.sh- Local verification wrapper for build, health checks, artifacts, and docs.
Modified files
android/app/src/main/java/com/hyzq/boss/BossUi.java- Shared list-row, avatar, unread badge, bubble, and chip builders.
android/app/src/main/java/com/hyzq/boss/BossScreenActivity.java- Base screen support for alternate layouts and lighter headers.
android/app/src/main/java/com/hyzq/boss/MainActivity.java- Root shell, tab state, conversations list, devices list, my-page menu, and return behavior.
android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java- Chat-first surface with only
项目目标 / 版本记录as lightweight actions.
- Chat-first surface with only
android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.java- Simpler device detail first screen.
android/app/src/main/java/com/hyzq/boss/SecurityActivity.java- WeChat-style simple list and session summary.
android/app/src/main/java/com/hyzq/boss/SettingsActivity.java- Lighter settings presentation.
android/app/src/main/java/com/hyzq/boss/SkillInventoryActivity.java- Skill rows instead of stacked heavy cards.
android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java- Simpler account list presentation.
android/app/src/main/java/com/hyzq/boss/AboutActivity.java- Cleaner About/OTA surface with advanced entry placement.
android/app/src/main/res/layout/activity_main.xml- Root login and tab shell layout.
android/app/src/main/res/layout/activity_screen.xml- Standard secondary-page shell layout.
android/app/src/main/res/values/colors.xml- WeChat-like flat palette.
android/app/src/main/res/values/styles.xml- White window background, no dashboard gradient.
android/app/build.gradle- Version bump for the rollback release build.
README.md- New native UI direction and build status.
docs/architecture/current_runtime_and_deploy_status_cn.md- Runtime truth after rollback.
docs/architecture/ai_handoff_index_cn.md- Effective Android surface summary.
docs/architecture/repo_map_cn.md- New layout / helper file map if structure changes.
Task 1: Freeze the WeChat Surface Contract in Unit Tests
Files:
-
Create:
android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java -
Create:
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java -
Test:
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java -
Step 1: Write the failing test
package com.hyzq.boss;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import org.json.JSONObject;
import org.junit.Test;
import java.util.Arrays;
public class WechatSurfaceMapperTest {
@Test
public void toConversationRow_keepsOnlyWechatFields() throws Exception {
JSONObject source = new JSONObject()
.put("projectTitle", "Boss 移动控制台")
.put("preview", "主 Agent 已回复")
.put("latestReplyLabel", "昨天")
.put("unreadCount", 3)
.put("riskLevel", "urgent")
.put("activeDeviceCount", 2);
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(source);
assertEquals("Boss 移动控制台", row.title);
assertEquals("主 Agent 已回复", row.preview);
assertEquals("昨天", row.timeLabel);
assertEquals(3, row.unreadCount);
assertFalse(row.preview.contains("设备"));
}
@Test
public void toDeviceRow_keepsOnlySimpleSubtitle() throws Exception {
JSONObject source = new JSONObject()
.put("name", "Mac Studio")
.put("status", "online")
.put("account", "17600003315")
.put("quota5h", 68)
.put("quota7d", 81);
WechatSurfaceMapper.DeviceRow row = WechatSurfaceMapper.toDeviceRow(source);
assertEquals("Mac Studio", row.title);
assertEquals("在线 · 17600003315", row.subtitle);
}
@Test
public void rootMeMenuTitles_matchApprovedSimpleMenu() {
assertEquals(
Arrays.asList("账号与安全", "AI 账号", "设置", "技能", "关于"),
WechatSurfaceMapper.rootMeMenuTitles()
);
}
@Test
public void projectQuickActions_keepOnlyGoalsAndVersions() {
assertEquals(
Arrays.asList("项目目标", "版本记录"),
WechatSurfaceMapper.projectQuickActions()
);
}
}
- Step 2: Run test to verify it fails
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: FAIL with cannot find symbol or ClassNotFoundException for WechatSurfaceMapper.
- Step 3: Write minimal implementation
package com.hyzq.boss;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.List;
public final class WechatSurfaceMapper {
private WechatSurfaceMapper() {}
public static final class ConversationRow {
public final String title;
public final String preview;
public final String timeLabel;
public final int unreadCount;
public ConversationRow(String title, String preview, String timeLabel, int unreadCount) {
this.title = title;
this.preview = preview;
this.timeLabel = timeLabel;
this.unreadCount = unreadCount;
}
}
public static final class DeviceRow {
public final String title;
public final String subtitle;
public DeviceRow(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
}
}
public static ConversationRow toConversationRow(JSONObject item) {
return new ConversationRow(
item.optString("projectTitle", "未命名会话"),
item.optString("preview", "暂无消息"),
item.optString("latestReplyLabel", ""),
item.optInt("unreadCount", 0)
);
}
public static DeviceRow toDeviceRow(JSONObject item) {
String status = "online".equals(item.optString("status")) ? "在线" : "离线";
String account = item.optString("account", "");
String subtitle = account.isEmpty() ? status : status + " · " + account;
return new DeviceRow(item.optString("name", "未命名设备"), subtitle);
}
public static List<String> rootMeMenuTitles() {
return Arrays.asList("账号与安全", "AI 账号", "设置", "技能", "关于");
}
public static List<String> projectQuickActions() {
return Arrays.asList("项目目标", "版本记录");
}
}
- Step 4: Run test to verify it passes
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: PASS, BUILD SUCCESSFUL.
- Step 5: Commit
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java
git commit -m "test: freeze wechat surface contract"
Task 2: Rebuild the Root Shell and Conversation List
Files:
-
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 -
Modify:
android/app/src/main/res/layout/activity_screen.xml -
Modify:
android/app/src/main/res/values/colors.xml -
Modify:
android/app/src/main/res/values/styles.xml -
Create:
android/app/src/main/res/drawable/bg_list_row.xml -
Create:
android/app/src/main/res/drawable/bg_tab_active.xml -
Create:
android/app/src/main/res/drawable/bg_tab_inactive.xml -
Modify:
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java -
Step 1: Write the failing test
Extend WechatSurfaceMapperTest.java with root-shell expectations:
@Test
public void rootTabOrder_isWechatStyle() {
assertEquals(Arrays.asList("会话", "设备", "我的"), WechatSurfaceMapper.rootTabLabels());
}
@Test
public void mainPage_doesNotExposeOpsEntry() {
assertFalse(WechatSurfaceMapper.rootMeMenuTitles().contains("运维与修复"));
}
- Step 2: Run test to verify it fails
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: FAIL because rootTabLabels() does not exist.
- Step 3: Write minimal implementation
Add the missing contract method:
public static List<String> rootTabLabels() {
return Arrays.asList("会话", "设备", "我的");
}
Then wire the UI around that contract.
Update BossUi.java to add list-oriented builders:
public static LinearLayout buildListRow(
Context context,
String leadingText,
String title,
String subtitle,
String trailingText,
int unreadCount,
@Nullable View.OnClickListener listener
) {
LinearLayout row = new LinearLayout(context);
row.setOrientation(LinearLayout.HORIZONTAL);
row.setBackgroundResource(R.drawable.bg_list_row);
row.setPadding(dp(context, 16), dp(context, 14), dp(context, 16), dp(context, 14));
if (listener != null) row.setOnClickListener(listener);
return row;
}
Update MainActivity.java so the root render paths use WechatSurfaceMapper instead of card-heavy metadata:
private void renderConversationsRoot() {
screenContent.removeAllViews();
if (conversationsData == null || conversationsData.length() == 0) {
screenContent.addView(BossUi.buildEmptyCard(this, "当前没有会话数据。"));
return;
}
for (int i = 0; i < conversationsData.length(); i++) {
JSONObject item = conversationsData.optJSONObject(i);
if (item == null) continue;
WechatSurfaceMapper.ConversationRow row = WechatSurfaceMapper.toConversationRow(item);
String projectId = item.optString("projectId", "");
screenContent.addView(BossUi.buildListRow(
this,
item.optString("avatar", item.optString("projectTitle", "会").substring(0, 1)),
row.title,
row.preview,
row.timeLabel,
row.unreadCount,
v -> openProject(projectId, row.title)
));
}
}
Update activity_main.xml / activity_screen.xml to remove dashboard framing:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/boss_surface">
<Button
android:id="@+id/tab_conversations"
android:background="@drawable/bg_tab_active"
android:text="会话" />
- Step 4: Run tests and compile verification
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android :app:compileDebugJavaWithJavac --no-daemon
Expected:
-
Unit tests PASS
-
Java compile PASS
-
Step 5: Commit
cd /Users/kris/code/boss
git add 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/main/res/layout/activity_screen.xml android/app/src/main/res/values/colors.xml android/app/src/main/res/values/styles.xml android/app/src/main/res/drawable/bg_list_row.xml android/app/src/main/res/drawable/bg_tab_active.xml android/app/src/main/res/drawable/bg_tab_inactive.xml android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java
git commit -m "feat: restore wechat-style root shell"
Task 3: Rebuild Project Detail into a Chat-First Surface
Files:
-
Modify:
android/app/src/main/java/com/hyzq/boss/BossScreenActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java -
Modify:
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java -
Modify:
android/app/src/main/java/com/hyzq/boss/BossUi.java -
Create:
android/app/src/main/res/layout/activity_project_chat.xml -
Create:
android/app/src/main/res/drawable/bg_message_incoming.xml -
Create:
android/app/src/main/res/drawable/bg_message_outgoing.xml -
Step 1: Write the failing test
Extend WechatSurfaceMapperTest.java:
@Test
public void projectPrimarySections_keepOnlyChatEssentials() {
assertEquals(
Arrays.asList("quick_actions", "messages", "composer"),
WechatSurfaceMapper.projectPrimarySections()
);
}
- Step 2: Run test to verify it fails
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: FAIL because the helper still allows the old action shape or the assertions are not yet satisfied.
- Step 3: Write minimal implementation
Teach BossScreenActivity to allow an alternate layout:
protected int getLayoutResId() {
return R.layout.activity_screen;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResId());
...
}
Then make ProjectDetailActivity use a chat layout and strip the heavy cards:
@Override
protected int getLayoutResId() {
return R.layout.activity_project_chat;
}
private void renderProject(JSONObject payload) {
JSONObject project = payload.optJSONObject("project");
JSONArray messages = project == null ? null : project.optJSONArray("messages");
configureScreen(project == null ? "项目聊天" : project.optString("name", "项目聊天"), "");
replaceContent();
appendQuickActions("项目目标", v -> openGoals(), "版本记录", v -> openVersions());
renderMessages(messages);
}
and add the missing helper contract:
public static List<String> projectPrimarySections() {
return Arrays.asList("quick_actions", "messages", "composer");
}
Render message bubbles through BossUi instead of generic cards:
public static LinearLayout buildMessageBubble(
Context context,
boolean self,
String sender,
String body,
String meta
) {
LinearLayout bubble = new LinearLayout(context);
bubble.setBackgroundResource(self ? R.drawable.bg_message_outgoing : R.drawable.bg_message_incoming);
return bubble;
}
Do not render these old sections in the main chat surface:
-
当前主控身份 -
主 Agent 调度结论 -
线程预算卡片 -
实时 APP 日志 -
媒体与转发说明 -
Step 4: Run tests and screen compile verification
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --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
Expected:
-
Unit tests PASS
-
Java compile PASS
-
Debug assemble PASS
-
Step 5: Commit
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/BossScreenActivity.java android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java android/app/src/main/java/com/hyzq/boss/BossUi.java android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java android/app/src/main/res/layout/activity_project_chat.xml android/app/src/main/res/drawable/bg_message_incoming.xml android/app/src/main/res/drawable/bg_message_outgoing.xml
git commit -m "feat: restore wechat-style project chat page"
Task 4: Simplify Devices and Me Surfaces, Demote Advanced Ops
Files:
-
Modify:
android/app/src/main/java/com/hyzq/boss/MainActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.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/SkillInventoryActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/AboutActivity.java -
Modify:
android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java -
Modify:
android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java -
Step 1: Write the failing test
Extend WechatSurfaceMapperTest.java:
@Test
public void rootMeMenuTitles_keepApprovedOrder() {
assertEquals(
Arrays.asList("账号与安全", "AI 账号", "设置", "技能", "关于"),
WechatSurfaceMapper.rootMeMenuTitles()
);
}
@Test
public void advancedEntryTitle_movesOpsOutOfMainMePage() {
assertEquals("高级与调试", WechatSurfaceMapper.advancedEntryTitle());
}
- Step 2: Run test to verify it fails
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
Expected: FAIL until the mapper and page rendering fully stop leaking quota / ops content.
- Step 3: Write minimal implementation
Use WechatSurfaceMapper rows in MainActivity.renderDevicesRoot():
private void renderDevicesRoot() {
screenContent.removeAllViews();
screenContent.addView(BossUi.buildMenuRow(this, "添加设备", "通过绑定码接入新设备", null, v -> {
startActivity(new Intent(this, DeviceEnrollmentActivity.class));
}));
for (int i = 0; i < devicesData.length(); i++) {
JSONObject item = devicesData.optJSONObject(i);
if (item == null) continue;
WechatSurfaceMapper.DeviceRow row = WechatSurfaceMapper.toDeviceRow(item);
screenContent.addView(BossUi.buildListRow(
this,
item.optString("avatar", "设"),
row.title,
row.subtitle,
"",
0,
v -> openDevice(item.optString("id"), row.title)
));
}
}
Simplify renderMeRoot() to only approved rows:
screenContent.addView(BossUi.buildMenuRow(this, "账号与安全", "登录与会话", null, v -> startActivity(new Intent(this, SecurityActivity.class))));
screenContent.addView(BossUi.buildMenuRow(this, "AI 账号", "主 GPT / 备用 GPT / API 容灾", null, v -> startActivity(new Intent(this, AiAccountsActivity.class))));
screenContent.addView(BossUi.buildMenuRow(this, "设置", "默认首页与提醒行为", null, v -> startActivity(new Intent(this, SettingsActivity.class))));
screenContent.addView(BossUi.buildMenuRow(this, "技能", "当前设备 Skill 清单", null, v -> startActivity(new Intent(this, SkillInventoryActivity.class))));
screenContent.addView(BossUi.buildMenuRow(this, "关于", "版本与更新", null, v -> startActivity(new Intent(this, AboutActivity.class))));
Move advanced entry deeper by placing it under AboutActivity as a non-primary menu row:
Button advanced = BossUi.buildSecondaryButton(this, "高级与调试");
advanced.setOnClickListener(v -> startActivity(new Intent(this, OpsCenterActivity.class)));
and add the helper contract:
public static String advancedEntryTitle() {
return "高级与调试";
}
DeviceDetailActivity should keep only:
- simple device summary
查看技能编辑
and stop rendering related thread cards / enrollment draft cards on the first screen.
- Step 4: Run tests and full debug verification
Run:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android testDebugUnitTest --tests com.hyzq.boss.WechatSurfaceMapperTest --no-daemon
JAVA_HOME=$(/usr/libexec/java_home) ./android/gradlew -p ./android assembleDebug --no-daemon
adb -s 8KE0219724012168 shell am start -W -n com.hyzq.boss/.MainActivity
adb -s 8KE0219724012168 shell pidof com.hyzq.boss
Expected:
-
Unit tests PASS
-
Debug assemble PASS
-
MainActivitystarts -
pidofreturns a process id -
Step 5: Commit
cd /Users/kris/code/boss
git add android/app/src/main/java/com/hyzq/boss/MainActivity.java android/app/src/main/java/com/hyzq/boss/DeviceDetailActivity.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/SkillInventoryActivity.java android/app/src/main/java/com/hyzq/boss/AiAccountsActivity.java android/app/src/main/java/com/hyzq/boss/AboutActivity.java android/app/src/main/java/com/hyzq/boss/WechatSurfaceMapper.java android/app/src/test/java/com/hyzq/boss/WechatSurfaceMapperTest.java
git commit -m "feat: simplify device and me surfaces"
Task 5: Verification, Release Packaging, Deployment, and Docs
Files:
-
Create:
scripts/verify-native-wechat-release.sh -
Modify:
android/app/build.gradle -
Modify:
README.md -
Modify:
docs/architecture/current_runtime_and_deploy_status_cn.md -
Modify:
docs/architecture/ai_handoff_index_cn.md -
Modify:
docs/architecture/repo_map_cn.md -
Step 1: Write the failing release verification script
Create scripts/verify-native-wechat-release.sh:
#!/bin/zsh
set -euo pipefail
cd /Users/kris/code/boss
npm run lint
npm run build
curl -fsS http://127.0.0.1:3000/api/health >/dev/null
curl -fsS http://127.0.0.1:4317/health >/dev/null
test -f android/app/build/outputs/apk/release/boss-android-v2.1.2-release.apk
test -f android/app/build/outputs/bundle/release/boss-android-v2.1.2-release.aab
rg -q '微信式' README.md
rg -q '2.1.2' docs/architecture/current_runtime_and_deploy_status_cn.md
- Step 2: Run it to verify it fails
Run:
cd /Users/kris/code/boss
zsh ./scripts/verify-native-wechat-release.sh
Expected: FAIL because the 2.1.2 artifacts and updated docs do not exist yet.
- Step 3: Write minimal release implementation
Bump the Android version:
versionCode 9
versionName "2.1.2"
Update docs to state:
- native UI has returned to WeChat-style interaction
- root tabs are
会话 / 设备 / 我的 - chat page keeps only
项目目标 / 版本记录
Then build and publish:
cd /Users/kris/code/boss
JAVA_HOME=$(/usr/libexec/java_home) npm run apk:release
JAVA_HOME=$(/usr/libexec/java_home) npm run aab:release
- Step 4: Run release verification and deploy
Run:
cd /Users/kris/code/boss
zsh ./scripts/verify-native-wechat-release.sh
adb -s 8KE0219724012168 install -r /Users/kris/code/boss/android/app/build/outputs/apk/release/boss-android-v2.1.2-release.apk
adb -s 8KE0219724012168 shell am start -W -n com.hyzq.boss/.MainActivity
./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
curl -sS https://boss.hyzq.net/downloads/boss-android-latest.json
curl -sS https://boss.hyzq.net/downloads/boss-android-latest-aab.json
Expected:
-
Verification script PASS
-
APK install PASS
-
MainActivitylaunch PASS -
remote
/api/healthPASS -
public health PASS
-
public APK/AAB metadata show
2.1.2 / versionCode 9 -
Step 5: Commit and publish
cd /Users/kris/code/boss
git add scripts/verify-native-wechat-release.sh android/app/build.gradle README.md docs/architecture/current_runtime_and_deploy_status_cn.md docs/architecture/ai_handoff_index_cn.md docs/architecture/repo_map_cn.md public/downloads
git commit -m "feat: ship wechat-style native rollback release"
git push gitea HEAD:refs/heads/codex/native-boss-android-2-1-0
Self-Review Checklist
- Spec coverage:
- 一级导航微信式化:Task 2
- 会话首页极简列表:Task 2
- 聊天页只保留项目目标/版本记录:Task 3
- 设备页 / 我的页简单列表:Task 4
- 返回逻辑与状态保持:Task 2 + Task 4
- 构建 / 真机 / 部署 / 文档:Task 5
- Placeholder scan:
- No
TBD/TODO/ “similar to” - Every task has exact files, commands, and code snippets
- No
- Type consistency:
WechatSurfaceMapperis the single contract source for root tabs, conversation rows, device rows, and quick actions