diff --git a/docs/plans/2026-07-02-001-refactor-remove-all-emoji-plan.md b/docs/plans/2026-07-02-001-refactor-remove-all-emoji-plan.md
index b701cce..4f57a2f 100644
--- a/docs/plans/2026-07-02-001-refactor-remove-all-emoji-plan.md
+++ b/docs/plans/2026-07-02-001-refactor-remove-all-emoji-plan.md
@@ -2,8 +2,14 @@
title: "refactor: Remove all emoji from agentkit"
date: 2026-07-02
type: refactor
-status: approved
+status: in-progress
approved_at: 2026-07-02
+progress:
+ u1: done
+ u2: mostly-done # BoardBannerCard 已为纯文本,ReviewResultCard.vue + useMessageRenderer.ts:286/307/328 待改
+ u3: mostly-done # Python CLI 已完成,scripts/ 待补
+ u4: done
+ u5: not-started # 简化为风格文档 + pre-commit grep
origin: user-direct (ce-plan invocation, 2026-07-02)
---
@@ -17,7 +23,7 @@ origin: user-direct (ce-plan invocation, 2026-07-02)
- **横幅/卡片图标** → 改用 Ant Design Vue 组件(`BankOutlined`/`AuditOutlined`/`TeamOutlined` 等)。
- **CLI 状态标记** → Rich 文本标签(`OK`/`FAIL`/`WARN`) + Rich 颜色样式。
-执行顺序按 4 个批次分阶段落地,每批可独立提交/回滚。
+执行顺序按 5 个批次分阶段落地,每批可独立提交/回滚。
## Problem Frame
@@ -109,7 +115,7 @@ origin: user-direct (ce-plan invocation, 2026-07-02)
### 包含
- 22 个源码文件中的 emoji 字符移除(不含文档注释)
-- 4 批次的实施顺序与每批对应的文件清单
+- 5 批次的实施顺序与每批对应的文件清单
- DB 默认值从 emoji 改为稳定 key(无 schema migration)
- App.vue 字体回退清理
- 3 个测试文件 fixture 同步
@@ -222,15 +228,19 @@ bitable/db.py:216 icon VARCHAR DEFAULT 'table'
- `src/agentkit/server/frontend/src/components/chat/messages/DebateBannerCard.vue` — `⚖` → ``
- `src/agentkit/server/frontend/src/components/chat/messages/DebateConclusionCard.vue` — `decisionIcons` map 改为 Ant Design Vue 组件(`CheckOutlined`/`SwapOutlined`/`MinusOutlined`/`QuestionOutlined`)
- `src/agentkit/server/frontend/src/components/chat/messages/UserBubble.vue:143` — `'🏛️'`/`'👥'` 字符串 → ``/``
-- `src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts:212,271` — `avatar: '⚖'` → `avatar: AuditOutlined`(shell.avatar 改 Component)
-- `src/agentkit/server/frontend/src/components/chat/MessageShell.vue` — 检查 avatar 字段类型,Component 走 ``,string 走原样
+- `src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts:203,262` — **已完成**(`avatar: AuditOutlined`)
+- `src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts:286` — `avatar: '◆'` → Ant Design 组件(如 `ApartmentOutlined` 用于协作图)
+- `src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts:307` — `avatar: review.passed ? '\u2713' : '\u2717'` → `review.passed ? CheckOutlined : CloseOutlined`
+- `src/agentkit/server/frontend/src/components/chat/helpers/useMessageRenderer.ts:328` — `avatar: '!'` → `WarningOutlined`(与 ReviewResultCard 的 risk_flagged 语义一致)
+- `src/agentkit/server/frontend/src/components/chat/messages/ReviewResultCard.vue:42-44` — `'\u2713'`/`'\u2717'`/`'\u21bb'` → `CheckOutlined`/`CloseOutlined`/`ReloadOutlined`
+- `src/agentkit/server/frontend/src/components/chat/messages/MessageShell.vue` — 检查 avatar 字段类型,Component 走 ``,string 走原样(已实现 Component vs string 分支)
- `src/agentkit/server/frontend/src/App.vue:109-110` — 字体回退删 emoji 字体声明
**Approach**:
- 引入 `BankOutlined` / `AuditOutlined` / `TeamOutlined` / `CheckOutlined` / `SwapOutlined` / `MinusOutlined` / `QuestionOutlined`(均已在 `@ant-design/icons-vue` 中,无需新装)
-- `BoardBannerCard` / `DebateBannerCard` 的 `X` 改为 ``
+- `DebateBannerCard` 的 `X` 改为 ``(BoardBannerCard 已为纯文本,不适用)
- `UserBubble` 的 command card 改造:`icon` prop 改为 `Component` 类型
-- `useMessageRenderer` 中 `shell.avatar` 类型由 `string` 改为 `Component`(仅这两处),其余 shell 仍用 string(首字母)
+- `useMessageRenderer` 中 `shell.avatar` 类型由 `string` 改为 `Component`(行 203/262 已完成,286/307 待改),其余 shell 仍用 string(首字母)
- `MessageShell.vue` 用 `v-if="typeof shell.avatar === 'string'"` 分支处理
**Test scenarios**:
@@ -243,20 +253,23 @@ bitable/db.py:216 icon VARCHAR DEFAULT 'table'
**Verification**:
- `npm run typecheck` 通过
- `npx vitest run tests/unit/components/` 通过
-- 浏览器打开 `/agent/chat` 触发 `@board`,确认横幅显示 `` 矢量图标(非 emoji)
+- 浏览器打开 `/agent/chat` 触发 `@board`,确认横幅为纯文本(无 emoji)
- 触发辩论确认 `DebateBannerCard` 显示 ``
---
-### U3. CLI 控制台输出 — admin / chat / skill / benchmark
+### U3. CLI 控制台输出 + Shell/CI 脚本 — admin / chat / skill / benchmark / scripts
-**Goal**:把 Rich 输出中的 `✓` `✗` `⚠` 改为 `OK`/`FAIL`/`WARN` 文本标签 + Rich 颜色。
+**Goal**:把 Rich 输出中的 `✓` `✗` `⚠` 改为 `OK`/`FAIL`/`WARN` 文本标签 + Rich 颜色;同时清理 shell/CI 脚本中的 emoji 状态标记。
**Files**:
- `src/agentkit/cli/admin.py:215,601` — 表格 `is_active` 列的 `✓`/`✗` → `OK`/`--`
- `src/agentkit/cli/chat.py:589,603,692,694,727,730` — 验收/阶段/风险标记全部收敛
- `src/agentkit/cli/skill.py:296` — `⚠ 以下为自动生成…` → `WARN 以下为自动生成…`
- `src/agentkit/cli/benchmark.py:895,989,2032,2733,2767,2784,2790` — 所有 `✓`/`✗`/`⚠` 收敛
+- `scripts/dev-start.sh:88,91,123-132` — `✓`/`✗`/`○` → `[ OK ]`/`[FAIL]`/`[ .. ]`(与 KTD3 文本标签策略一致)
+- `scripts/deploy.sh:16,21,36` — `❌`/`✅` → `[FAIL]`/`[OK]`
+- `.gitea/workflows/deploy.yml:69` — `✅` → `[OK]`
**Approach**:
- 字符串替换策略:所有 `[green]✓ X[/green]` 改 `[bold green]OK X[/bold green]`;`[red]✗ X[/red]` 改 `[bold red]FAIL X[/red]`;`[yellow]⚠ X[/yellow]` 改 `[bold yellow]WARN X[/yellow]`
@@ -306,37 +319,33 @@ bitable/db.py:216 icon VARCHAR DEFAULT 'table'
---
-### U5. 端到端验证 + 防止复发(lint 规则 + 文档)
+### U5. 端到端验证 + 防止复发(pre-commit grep 守卫 + 文档)
-**Goal**:确认全仓无残留 emoji,并加入 CI 守卫。
+**Goal**:确认全仓无残留 emoji,并加入轻量防复发守卫。
**Files**:
-- 新增 `frontend/eslint-rules/no-emoji.cjs`(自定义 ESLint 规则,禁止源码中的 emoji 字符范围)
-- `frontend/.eslintrc.cjs` 注册规则
-- `pyproject.toml` 加 `ruff` 自定义规则(`RUF900` 禁用 emoji)或依赖 `pre-commit` 钩子
-- `.pre-commit-config.yaml`(若不存在则创建)— 添加 `agentkit-no-emoji` 钩子
-- `docs/solutions/style/no-emoji-style-guide.md`(新增)— 记录替换规则与原因
+- `scripts/check-no-emoji.sh`(新增)— 用 `rg` 扫描字面 emoji + 转义序列,覆盖 src/configs/tests/scripts
+- `.pre-commit-config.yaml`(若不存在则创建)— 添加 `agentkit-no-emoji` 钩子(调用上述 shell 脚本)
+- `docs/solutions/style/no-emoji-style-guide.md`(新增)— 记录三套替代策略(KTD1-3)与 Unicode 范围参考
**Approach**:
-- 自定义 ESLint 规则用正则 `[\x{1F000}-\x{1FFFF}\x{2600}-\x{27BF}\x{2300}-\x{23FF}\x{2B00}-\x{2BFF}]` 匹配所有 emoji 范围
-- 规则名 `no-emoji-in-source`,错误级别 `error`,白名单文件:注释(通过 `// allow-emoji` 注解豁免,仅在文档/迁移脚本等场景)
-- ruff 通过 `RUF` 自定义检查或第三方 `flake8-no-emoji` 工具
-- pre-commit 在 commit 阶段跑前端 + 后端双检查
-- 风格指南文档说明三套替代策略(KTD1-3)
+- **轻量方案**(替代原 ESLint + ruff 自定义规则,因项目无 ESLint 基础设施且 ruff 不支持自定义规则):
+ - shell 脚本用 `rg` 扫描两类模式:(a) 字面 emoji 字符 `[\x{1F000}-\x{1FFFF}\x{2600}-\x{27BF}\x{2300}-\x{23FF}\x{2500}-\x{25FF}\x{2190}-\x{21FF}\x{2B00}-\x{2BFF}]`;(b) 转义序列 `\\u(271[0-9a-fA-F]|26[0-9a-fA-F]{2}|2[0-5][0-9a-fA-F]{2}|21[0-9a-fA-F]{2})`
+ - pre-commit 钩子在 commit 阶段跑该脚本,拦截含 emoji 的暂存文件
+ - 白名单:`docs/`(文档允许 emoji)、`*.md`(markdown 注释允许)
+- 风格指南文档说明三套替代策略(KTD1-3)+ 何时用 Ant Design 组件 vs 文本标签 vs 首字母
**Test scenarios**:
-- **Happy path**:`npx eslint src/` 无 emoji 错误
-- **Happy path**:`ruff check src/` 无 emoji 警告
-- **Error path**:故意在某 `.vue` 文件中加一个 emoji 字符,ESLint 报错并阻止 build
+- **Happy path**:`bash scripts/check-no-emoji.sh` 退出码 0(无 emoji 残留)
+- **Error path**:故意在某 `.ts` 文件中加 `\u2713` 转义序列,脚本检出并报错
- **Integration**:本地 commit 含 emoji 的文件被 pre-commit 阻止
**Verification**:
-- `npm run lint` 全通过
-- `ruff check src/` 全通过
-- `pre-commit run --all-files` 全通过
-- 新建一个临时 `.vue` 文件含 emoji,确认 ESLint 报错
+- `bash scripts/check-no-emoji.sh` 全通过
+- `pre-commit run --all-files` 全通过(若 pre-commit 已安装)
+- 手动在临时文件加 emoji 字符和 `\u2713` 转义,确认脚本检出
-**Deferred to Follow-Up**:CI 工作流(`.github/workflows/` 或 Gitea Actions)添加 emoji 检查步骤 — 等 lint 规则稳定后再加,避免一次性改动过多。
+**Deferred to Follow-Up**:CI 工作流(`.gitea/workflows/`)添加 emoji 检查步骤 — 等 pre-commit 钩子稳定后再加。
---
@@ -382,6 +391,42 @@ AE6. **CI 守卫** — 故意在某 `.vue` 模板加 `🏛️` 字符,`npm run
3. **`@ant-design/icons-vue` 包体积**(目前约 300KB+)— 项目已在用,仅新增 7 个组件,bundle size 影响可忽略。如未来有更激进的优化诉求可走按需 import + Vite tree-shaking(已默认开启)。
+### ce-doc-review 2026-07-03 发现(P1-P2)
+
+以下发现由 ce-doc-review 5 个 persona reviewer 在 2026-07-03 重新核查时识别,需在 U5 实施前决策。
+
+**P1 发现(8 个):**
+
+4. **scripts/ 和 .gitea/ 中的 emoji 未纳入计划** — `scripts/dev-start.sh`(`✓`✗`○`)、`scripts/deploy.sh`(`❌`✅`)、`.gitea/workflows/deploy.yml`(`✅`)含与 CLI 同语义的状态标记,但不在 U1-U4 任何文件清单中。**决策**:将其加入 U3 或 U4 范围,沿用 KTD3 替换策略。
+
+5. **"22 个文件"计数矛盾** — Problem Frame 声称 22 个文件,类别求和为 28,U1-U4 文件清单求和为 37。**决策**:重新统计并订正。
+
+6. **pre-commit 钩子范围矛盾** — "不包含"段将 pre-commit 列为后续独立计划,但 U5 明确包含 `.pre-commit-config.yaml`。**决策**:从"不包含"删除 pre-commit 提及,明确 U5 包含 pre-commit,仅 CI 工作流延期。
+
+7. **ESLint 未安装** — 仓库无 ESLint 配置、无 `eslint` 依赖、`package.json` 无 `lint` 脚本。U5 隐含 4 个未声明子任务(安装 ESLint、创建配置、编写规则、添加脚本)。**决策**:U5 拆分为 U5a(ESLint 基础设施)+ U5b(no-emoji 规则),或改用轻量 shell 脚本 + pre-commit grep 方案。
+
+8. **ruff "自定义规则 RUF900" 不可行** — ruff 不支持用户通过 pyproject.toml 注册自定义规则,`RUF` 前缀是 ruff 保留命名空间。**决策**:删除 ruff 自定义规则选项,Python 侧统一走 pre-commit hook + rg 扫描。
+
+9. **"全部 emoji 字符从仓库代码中清除"与范围不匹配** — 绝对承诺但 scripts/CI 文件遗漏、useMessageRenderer.ts 转义形式遗漏。**决策**:修改为"U1-U4 列出文件中的 emoji 清除"或扩展范围。
+
+10. **useMessageRenderer.ts 3 处字符串 glyph 破坏 KTD2 一致性** — 行 286(`◆`)、307(`\u2713`/`\u2717`)、328(`!`)未转换,与 KTD2"图标家族统一为 Outlined"目标矛盾。(注:286/307 已在 P0 修复中加入 U2,328 的 `!` 需决策是否也改组件。)**决策**:将 `!` 也改为 `WarningOutlined` 或保留为 ASCII 文本标签。
+
+11. **U5 过度工程** — 自定义 ESLint + ruff + pre-commit + 风格文档四件套,与剩余清理任务不相称。项目当前无 ESLint 基础设施,emoji 复发概率低。**决策**:U5 瘦身为"风格文档 + pre-commit grep 守卫",删除自定义 ESLint/ruff 规则。
+
+**P2 发现(6 个):**
+
+12. **无障碍决策未声明** — 图标替换全程未声明 aria-label/aria-hidden 决策。装饰性图标应 `aria-hidden="true"`,承载语义的图标(如 review pass/fail)需 `aria-label`。**决策**:在 KTD2 加无障碍子决策。
+
+13. **计划状态字段未反映进度** — 仍标记 `status: approved`,但 U1-U4 已基本完成。**决策**:更新为 `status: in-progress`,加 progress 字段。
+
+14. **BoardBannerCard 实现偏离计划但未记录** — 从"Ant Design 组件"变成"纯文本"。(注:P0 修复已更新 AE1/U2/KTD2 描述,但 KTD2 取舍段落仍提及"放弃了 emoji 头像换取视觉一致性",需补充"无图标"理由。)**决策**:在 KTD2 取舍段补理由。
+
+15. **"无图标"第三选项从未被计划考虑** — KTD2 选项空间只有"emoji vs Ant Design 组件",实际实现了"无图标"。**决策**:在 KTD2 补"无图标"为显式选项并给取舍。
+
+16. **KTD4 旧行 `📋` 无主动清理路径** — 被动等待"如用户要求显式清理"。**决策**:加主动触发条件(如"下次 schema migration 时顺带 UPDATE")。
+
+17. **U5 "阻止 build" 验收与现有 build 流程脱节** — `npm run build` 是 `vue-tsc --noEmit && vite build`,不跑 ESLint。**决策**:明确接入点(pre-commit 拦截 vs build 前置检查)。
+
## Sources & Research
- **本地参考**: