30 KiB
| title | date | type | status | approved_at | progress | origin | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| refactor: Remove all emoji from agentkit | 2026-07-02 | refactor | in-progress | 2026-07-02 |
|
user-direct (ce-plan invocation, 2026-07-02) |
refactor: Remove all emoji from agentkit
Summary
@board 私董会数据恢复的修复已就位。但项目长期混用 emoji(专家头像、CLI 状态、私董会横幅、bitable 默认图标等),与既有的 Ant Design Vue Outlined 图标家族视觉风格不一致,且跨字体/OS 渲染不稳定。本次重构一次性把全部 emoji 收敛到三套等价替代:
- 头像/单字符位 → 统一走
expertIdentity.ts风格的「CJK/ASCII 首字符大写」;YAML/DB 中仍是字符串字段,前端渲染照常。 - 横幅/卡片图标 → 改用 Ant Design Vue 组件(
BankOutlined/AuditOutlined/TeamOutlined等)。 - CLI 状态标记 → Rich 文本标签(
OK/FAIL/WARN) + Rich 颜色样式。
执行顺序按 5 个批次分阶段落地,每批可独立提交/回滚。
Problem Frame
现状
全仓 22 个文件含 emoji 字符,覆盖 7 个语义类别(专家头像、bitable 默认、私董会横幅、辩论横幅、CLI 状态、终端提示、DB 默认值)。其中:
configs/experts/*.yaml15 个文件使用 emoji 作为 avatarbitable/db.py用📋作icon字段的 DB default(与models.py:80已有"table"默认不一致)chat.py把🏛️ 私董会开始:…写入SqliteConversationStore,作为无障碍/纯文本回退BoardBannerCard.vue、DebateBannerCard.vue、DebateConclusionCard.vue、UserBubble.vue直接渲染 emoji- 4 个 CLI 文件用
✓✗⚠作状态标记 - 3 个测试文件把 emoji 作为 fixture
触发原因
- 跨平台渲染不稳定:Linux 服务器无 Noto Color Emoji 时私董会横幅显示豆腐方块
- 视觉风格不一致:与项目其余 Ant Design Vue Outlined 图标家族(1.5px stroke)不协调
- DB schema 漂移:
bitable/models.py:80已迁到稳定 key"table",但bitable/db.py:68,216ORM/SQL 仍用📋
期望效果
- 全部 emoji 字符从仓库代码中清除(注释、文档除外)
- 视觉风格统一为 Ant Design Vue Outlined + 字符首字母
- 旧 Bitable 行的 emoji 值通过前端
resolveBitableIcon惰性回退到TableOutlined,无需迁移 - CLI 输出在所有终端(包括无 emoji 字体)下稳定显示
Key Technical Decisions
KTD1:专家头像改为「首字符大写」策略,与 expertIdentity.ts 行为对齐
决策:YAML 中 avatar 字段从 emoji 改为对应专家名的首字符大写(中文取首个 CJK 字,英文取首字母大写)。保留 IBoardExpert.avatar 字段(不删),值由后端 ExpertConfig 解析或前端 pickExpertIdentity 兜底。
理由:
frontend/src/components/chat/helpers/expertIdentity.ts:55的pickExpertIdentity默认就是首字符策略- 删除字段会破坏既有 WebSocket payload(
board_started.experts[].avatar)契约 - 字符位渲染跨字体稳定
取舍:放弃了 emoji 头像的「人格化表达」,换取视觉一致性与跨平台稳定。Lead/主持人仍可通过 color token + tag 区分。
KTD2:横幅/卡片图标改用 Ant Design Vue 组件,shell.avatar 改为 Component 类型
决策:BoardBannerCard / DebateBannerCard / DebateConclusionCard / UserBubble / useMessageRenderer.ts 引入 Ant Design Vue 组件(如 <BankOutlined>/<AuditOutlined>/<TeamOutlined>/<CheckOutlined>),把 shell.avatar 字段从 string 改为 Component 类型。
理由:
- 项目图标家族已统一为 Outlined(
Sidebar、Tabs、Tool call cards) useMessageRenderer.ts现有shell.avatar字段在MessageShell.vue渲染,与后端expert_avatar字段不冲突(那是单个专家的 avatar)
影响:MessageShell.vue 接收 shell 的 avatar 字段如果是 Component 类型则用 <component :is="..." />;如果是 string(首字母)则原样渲染。
KTD3:CLI 状态标记用 Rich 文本标签 + 颜色,弃用 ✓ ✗ ⚠
决策:OK / FAIL / WARN 作为文本标签,配合 Rich [green] / [red] / [yellow] 颜色。横幅标题用 [OK 验收结果] / [WARN 风险标记] 形式保留 emoji 缺失的视觉强度。
理由:
- 终端字体差异:Windows Terminal / 容器 tty / 旧版 macOS Terminal 对 Unicode 符号渲染不一致
- 颜色已能传达同样信息量
- 与 Python
rich库的最佳实践一致(标签 + 颜色)
KTD4:Bitable DB 默认值从 📋 改为 table,旧数据惰性收敛
决策:
bitable/db.py:68ORMdefault="📋"→default="table"bitable/db.py:216SQLDEFAULT '📋'→DEFAULT 'table'- 不写迁移脚本 — 前端
resolveBitableIcon已对未知值回退到TableOutlined,下次访问旧行时自动收敛 - 新建行直接用
table;旧行 render 时也是TableOutlined,零差异
理由:
bitable/models.py:80(Pydantic)已经是"table",ORM 端对齐消除双默认值- 避免引入 Alembic 迁移;旧数据下次访问收敛
bitable.ts:73和bitableIcons.ts:86已说明「legacy emoji 字符串自动回退」
已知限制:旧行在 DB 中仍是 📋 字符串。若未来要做 DB 备份快照或导出/导入,可能需要清理脚本。本次不处理。
KTD5:App.vue 字体回退去掉 emoji 字体声明
决策:App.vue:109-110 中的 'Apple Color Emoji'、'Segoe UI Emoji'、'Segoe UI Symbol'、'Noto Sans Emoji' 字体回退删除。
理由:既然不再渲染任何 emoji 字符,浏览器/系统不会下载这些字体;删去减少 30KB+ 的潜在字体下载请求。保留 sans-serif 作为最终回退。
KTD6:测试 fixture 同步更新,保持断言真实
决策:3 个测试文件中的 emoji fixture(🤖 🎯 🐱 💡 🦊 🐼 🏛️)改为对应的首字母大写(A/T/C/I/F/P 等),断言中的 expect(avatars[0].textContent).toBe('🤖') 同步改为 'A'。
理由:restoreBoardStateFromMessages 的 7 个新单元测试已锁定「缺 avatar/缺 color 走 fallback」行为,fixture 改字母不会绕过 fallback 链(仍由 pickExpertIdentity(name) 决定)。
Scope Boundaries
包含
- 22 个源码文件中的 emoji 字符移除(不含文档注释)
- 5 批次的实施顺序与每批对应的文件清单
- DB 默认值从 emoji 改为稳定 key(无 schema migration)
- App.vue 字体回退清理
- 3 个测试文件 fixture 同步
- 验证:typecheck / pytest / vitest / 视觉冒烟
不包含(Deferred to Follow-Up Work)
- emoji 自动检测(CI 守卫 / pre-commit 钩子)— 防止新增 emoji 复发,作为后续独立计划
- Bitable 旧行清理脚本(DB 备份/导出场景下需要时再做)
@ant-design/icons-vue包增量依赖 — 该包已是项目依赖(bitableIcons.ts现有 import),无新增- CLI 国际化(i18n) —
OK/FAIL/WARN目前硬编码中英混排;国际化是更大范围重构,本次不动 - Tauri 桌面端 emoji 字体 — Tauri 客户端的 emoji 字体回退不在本计划范围
- avatar 字段语义升级(如改成
avatar_url支持真实头像图片)— 是产品级决策,超出本次范围
System-Wide Impact
| 受影响方 | 影响 |
|---|---|
| 终端用户(Web GUI) | 私董会/辩论横幅、专家头像、Bitable 图标视觉变化;语义不变 |
| 终端用户(CLI) | agentkit CLI 表格/状态标记从符号改为文本标签;颜色保留 |
| 终端用户(Tauri 桌面) | 间接通过 Web GUI 同步 |
| 开发者 | 写新代码时不能直接用 emoji 字符;后续建议加 lint 规则 |
| 运营/部署 | 无(不涉及端口、配置、依赖增减) |
| 测试 | 3 个 vitest fixture 文件需同步更新断言;不影响测试覆盖度 |
High-Level Technical Design
视觉风格统一(KTD1+KTD2)的目标是把混用状态收敛成两条规则:
┌─────────────────────────────────────────────────────┐
│ 头像/单字符位 │
│ • YAML avatar 字段 → "S"/"B"/"P" 等首字符 │
│ • 前端 expertIdentity.ts 兜底(如缺 avatar) │
│ • ExpertMessage/StickyModeHeader/BoardBannerCard │
│ 都按 string 渲染字符 │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ 横幅/卡片图标 │
│ • BoardBannerCard: <BankOutlined /> │
│ • DebateBannerCard: <AuditOutlined /> │
│ • DebateConclusionCard: 4 个决策图标 = 4 个组件 │
│ • UserBubble command card: <BankOutlined /> 私董会 │
│ <TeamOutlined /> 团 │
│ • useMessageRenderer shell.avatar 改为 Component │
│ MessageShell 用 <component :is=...> 渲染 │
└─────────────────────────────────────────────────────┘
CLI 状态机收敛(KTD3):
旧: 新:
"✓" "✗" "⚠" "OK" "FAIL" "WARN"
[green]✓ X[/green] [bold green]OK X[/bold green]
[red]✗ X[/red] [bold red]FAIL X[/bold red]
[yellow]⚠ X[/yellow] [bold yellow]WARN X[/bold yellow]
DB schema 收敛(KTD4):
bitable/db.py:68 icon = Column(String, default="table")
bitable/db.py:216 icon VARCHAR DEFAULT 'table'
↓
旧 DB 行: '📋' → 前端 resolveBitableIcon 命中 DEFAULT_BITABLE_ICON='table' → 渲染 TableOutlined
新 DB 行: 'table' → 渲染 TableOutlined (与旧行一致)
Implementation Units
U1. 数据/契约层 — avatar 字段、持久化文本、DB 默认值
Goal:把数据层/契约层的 emoji 全部收敛到字符串默认值或首字符。
Files:
configs/experts/*.yaml(15 个文件:apple/private_board/team/tech_lead 等)— avatar 字段从 emoji 改首字符大写src/agentkit/bitable/db.py:68— ORM default📋→tablesrc/agentkit/bitable/db.py:216— SQLDEFAULT '📋'→DEFAULT 'table'src/agentkit/server/routes/chat.py:304,306—🏛️ 私董会开始:…→私董会开始:…src/agentkit/server/frontend/src/stores/chatStream.ts:1149—🏛️ 私董会开始:…→私董会开始:…src/agentkit/core/plan_schema.py:107,122—📋/⚠️→[Plan ...]/WARNsrc/agentkit/experts/registry.py:85— 注释📊改为纯文字
Approach:
- YAML avatar 字段值:英文名取首字母大写(
steve_jobs→S),中文名取首 CJK 字(张三→张) - 后端
chat.py与前端chatStream.ts的board_started持久化文本保持语义一致(去 emoji 字符本身不影响 message_type/board_started metadata) plan_schema.py:to_readable()是给人工看的报告,文本用纯文字更稳
Test scenarios:
- Happy path:
configs/experts/steve_jobs.yaml加载后expert.avatar == "S" - Happy path:
FileModel新实例icon == "table" - Happy path:
_apply_v1_schema生成的表icon列默认值为'table' - Edge case:现有 emoji DB 行(如
icon='📋')通过resolveBitableIcon仍渲染为TableOutlined
Verification:
pytest tests/unit/experts -k "config or registry"通过pytest tests/unit/bitable -k "schema or model"通过- 启动 backend 调用
@board,确认 DB 中board_started消息 content 为私董会开始:...(无 emoji)
U2. 前端 UI 组件 — 横幅、卡片、命令 chip
Goal:把 emoji 图标改用 Ant Design Vue 组件。
Files:
src/agentkit/server/frontend/src/components/chat/messages/BoardBannerCard.vue—🏛️→<BankOutlined />src/agentkit/server/frontend/src/components/chat/messages/DebateBannerCard.vue—⚖→<AuditOutlined />src/agentkit/server/frontend/src/components/chat/messages/DebateConclusionCard.vue—decisionIconsmap 改为 Ant Design Vue 组件(CheckOutlined/SwapOutlined/MinusOutlined/QuestionOutlined)src/agentkit/server/frontend/src/components/chat/messages/UserBubble.vue:143—'🏛️'/'👥'字符串 →<BankOutlined />/<TeamOutlined />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 : CloseOutlinedsrc/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/ReloadOutlinedsrc/agentkit/server/frontend/src/components/chat/messages/MessageShell.vue— 检查 avatar 字段类型,Component 走<component :is="..." />,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中,无需新装) DebateBannerCard的<span class="...__icon">X</span>改为<component :is="X" class="...__icon" />(BoardBannerCard 已为纯文本,不适用)UserBubble的 command card 改造:iconprop 改为Component类型useMessageRenderer中shell.avatar类型由string改为Component(行 203/262 已完成,286/307 待改),其余 shell 仍用 string(首字母)MessageShell.vue用v-if="typeof shell.avatar === 'string'"分支处理
Test scenarios:
- Happy path:
BoardBannerCard渲染时包含BankOutlinedSVG path - Happy path:
DebateBannerCard渲染时包含AuditOutlinedSVG path - Happy path:
DebateConclusionCard decision="adopt"渲染CheckOutlined - Happy path:
UserBubble解析@board:alice, bob时 command icon 为BankOutlined - Edge case:
shell.avatar是 string(如expert_initial)时仍原样渲染,不被当作 component
Verification:
npm run typecheck通过npx vitest run tests/unit/components/通过- 浏览器打开
/agent/chat触发@board,确认横幅为纯文本(无 emoji) - 触发辩论确认
DebateBannerCard显示<AuditOutlined />
U3. CLI 控制台输出 + Shell/CI 脚本 — admin / chat / skill / benchmark / scripts
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] - 表格列中的
✓/✗用OK/--(失败用--而非FAIL因为列宽有限) - 横幅标题的
⚠ 风险标记改WARN 风险标记(保留全部大写作为视觉强度替代)
Test scenarios:
- Happy path:
agentkit admin list-users输出包含OK而非✓ - Happy path:
agentkit chat触发的 phase completion 打印[OK] 阶段名:summary - Error path:phase 失败时打印
[FAIL] 阶段名:error - Integration:
agentkit benchmark在失败用例上打印[FAIL](无 emoji)
Verification:
pytest tests/unit/cli -k "admin or chat or skill or benchmark"通过- 手动跑
agentkit admin list-users/agentkit chat "test"/agentkit benchmark list确认输出无 emoji
U4. 终端前端 + 测试 fixture + 字体回退
Goal:清理剩余的终端提示、测试 fixture、字体回退。
Files:
src/agentkit/server/frontend/src/stores/terminal.ts:251,262,266,270,275—⚠⏳✓✗→WARNPENDINGOKREJECTED/TIMEOUTsrc/agentkit/server/frontend/src/components/terminal/CommandHistory.vue:20—✓/✗→OK/FAILsrc/agentkit/server/frontend/tests/unit/stores/chatStream.test.ts:731—avatar: '🦊'→avatar: 'F'src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts:22—content: '🏛️ 私董会开始:…'→content: '私董会开始:…'src/agentkit/server/frontend/tests/unit/stores/chatStore.test.ts:33,40—avatar: '🦊'/'🐼'→avatar: 'F'/'P'src/agentkit/server/frontend/tests/unit/components/StickyModeHeader.test.ts— 所有 emoji fixture 改首字母src/agentkit/server/frontend/src/components/chat/messages/TeamPlanCard.vue:67,82,127— 注释更新(已说明弃用,保留为历史说明即可,无运行影响)
Approach:
- 终端消息用
[WARN]/[PENDING]/[OK]/[REJECTED]/[TIMEOUT]文本格式(与 CLI KTD3 保持一致) - 测试 fixture 改为对应名称首字母(
StickyModeHeader.test.ts中avatar: '🤖'→avatar: 'A',expect(avatars[0].textContent).toBe('A')) chatStore.test.ts的board_startedcontent 改私董会开始:AI 未来(与 U1 后端持久化文本一致)
Test scenarios:
- Happy path:
CommandHistory渲染 exit_code=0 时显示OK、非 0 时显示FAIL - Happy path:
StickyModeHeader.test.ts中expect(avatars[0].textContent).toBe('A')通过 - Happy path:
chatStore.test.tsrestoreBoardStateFromMessages测试对新的非-emoji content 仍正确解析 - Edge case:终端 store 中
appendOutput的 ANSI 颜色(\x1b[33m)保留,仅替换前缀文本
Verification:
npm run typecheck通过npx vitest run tests/unit/全通过- 终端面板审批流程人工冒烟
U5. 端到端验证 + 防止复发(pre-commit grep 守卫 + 文档)
Goal:确认全仓无残留 emoji,并加入轻量防复发守卫。
Files:
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 + 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 注释允许)
- shell 脚本用
- 风格指南文档说明三套替代策略(KTD1-3)+ 何时用 Ant Design 组件 vs 文本标签 vs 首字母
Test scenarios:
- Happy path:
bash scripts/check-no-emoji.sh退出码 0(无 emoji 残留) - Error path:故意在某
.ts文件中加\u2713转义序列,脚本检出并报错 - Integration:本地 commit 含 emoji 的文件被 pre-commit 阻止
Verification:
bash scripts/check-no-emoji.sh全通过pre-commit run --all-files全通过(若 pre-commit 已安装)- 手动在临时文件加 emoji 字符和
\u2713转义,确认脚本检出
Deferred to Follow-Up:CI 工作流(.gitea/workflows/)添加 emoji 检查步骤 — 等 pre-commit 钩子稳定后再加。
Risks & Dependencies
| 风险 | 缓解 |
|---|---|
| Ant Design Vue 图标视觉与原 emoji 风格差异大,用户不适应 | U2 完成后做视觉冒烟;如不接受可回退到 string 字符首字母策略(KTD1) |
useMessageRenderer.ts 的 shell.avatar 改 Component 类型影响 MessageShell.vue 之外的消费者 |
全仓 grep shell.avatar / message.shell.avatar 确认仅 MessageShell.vue 消费 |
CLI 输出改为 OK/FAIL 文本会改变宽度,可能破坏现有对齐 |
表格用 -- 而非 FAIL(列宽更短) |
Bitable 旧行不清理,未来 DB 导出/快照会有 📋 字符串 |
文档记录 KTD4 限制;后续可加迁移脚本 |
| pre-commit / 自定义 ESLint 规则本身可能误报(CJK 字符、注释中的 emoji) | 规则用明确的 Unicode range;白名单机制支持 // allow-emoji 行级豁免 |
| 测试 fixture 改首字母可能与某个测试断言的「fallback 行为」冲突 | U4 前先跑一遍 vitest 全量测试,建立基线;逐个 fixture 改并立即跑对应测试 |
依赖关系:
- U1 独立(数据/契约层)
- U2 独立(前端 UI)
- U3 独立(CLI)
- U4 依赖 U1(chatStore.test.ts content 需与 U1 后端持久化文本一致)
- U5 依赖 U1-U4 全部完成
实施顺序:U1 → U2 → U3 → U4 → U5。每批独立可提交/可回滚。
Acceptance Examples
AE1. 私董会横幅显示矢量图标 — 触发 @board 测试主题,确认 BoardBannerCard 渲染 <BankOutlined /> 矢量图标(SVG),不再显示 🏛️ 字符。
AE2. Bitable 默认图标稳定 — 创建新 Bitable 文件,icon 字段在 DB 中为 'table',UI 渲染 TableOutlined。已存在的 emoji 行通过前端 resolveBitableIcon 自动收敛。
AE3. CLI 状态无 emoji — 运行 agentkit admin list-users,表格中 is_active=true 显示 OK,is_active=false 显示 --,无 ✓/✗ 字符。
AE4. 专家头像首字符 — @board steve_jobs, charlie_munger 私董会,BoardBannerCard 中 Steve Jobs 头像显示 S、Charlie Munger 头像显示 C(不再显示 🍎/🧠)。
AE5. 测试 fixture 与生产代码一致 — npm run typecheck + npx vitest run + pytest tests/unit/ 三套全通过,无 emoji 残留。
AE6. CI 守卫 — 故意在某 .vue 模板加 🏛️ 字符,npm run lint 报错并阻止。
Open Questions
-
useMessageRenderer.ts的shell.avatar类型升级是否需要更平滑(保留 string 但用约定__ICON__BankOutlined)?— 当前方案改为Component是更类型安全的,但若MessageShell.vue之外有第三方消费方可能破坏。默认决定:U2 实施前先全仓 grep 确认无外部消费者。 -
Bitable
📋旧行是否要做一次性清理脚本?— KTD4 决定惰性收敛,文档记录为 follow-up。如用户要求显式清理,U5 后可加一个agentkit bitable migrate-icons命令。 -
@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 个):
-
scripts/ 和 .gitea/ 中的 emoji 未纳入计划 —
scripts/dev-start.sh(✓✗○)、scripts/deploy.sh(❌✅)、.gitea/workflows/deploy.yml(✅`)含与 CLI 同语义的状态标记,但不在 U1-U4 任何文件清单中。决策:将其加入 U3 或 U4 范围,沿用 KTD3 替换策略。 -
"22 个文件"计数矛盾 — Problem Frame 声称 22 个文件,类别求和为 28,U1-U4 文件清单求和为 37。决策:重新统计并订正。
-
pre-commit 钩子范围矛盾 — "不包含"段将 pre-commit 列为后续独立计划,但 U5 明确包含
.pre-commit-config.yaml。决策:从"不包含"删除 pre-commit 提及,明确 U5 包含 pre-commit,仅 CI 工作流延期。 -
ESLint 未安装 — 仓库无 ESLint 配置、无
eslint依赖、package.json无lint脚本。U5 隐含 4 个未声明子任务(安装 ESLint、创建配置、编写规则、添加脚本)。决策:U5 拆分为 U5a(ESLint 基础设施)+ U5b(no-emoji 规则),或改用轻量 shell 脚本 + pre-commit grep 方案。 -
ruff "自定义规则 RUF900" 不可行 — ruff 不支持用户通过 pyproject.toml 注册自定义规则,
RUF前缀是 ruff 保留命名空间。决策:删除 ruff 自定义规则选项,Python 侧统一走 pre-commit hook + rg 扫描。 -
"全部 emoji 字符从仓库代码中清除"与范围不匹配 — 绝对承诺但 scripts/CI 文件遗漏、useMessageRenderer.ts 转义形式遗漏。决策:修改为"U1-U4 列出文件中的 emoji 清除"或扩展范围。
-
useMessageRenderer.ts 3 处字符串 glyph 破坏 KTD2 一致性 — 行 286(
◆)、307(\u2713/\u2717)、328(!)未转换,与 KTD2"图标家族统一为 Outlined"目标矛盾。(注:286/307 已在 P0 修复中加入 U2,328 的!需决策是否也改组件。)决策:将!也改为WarningOutlined或保留为 ASCII 文本标签。 -
U5 过度工程 — 自定义 ESLint + ruff + pre-commit + 风格文档四件套,与剩余清理任务不相称。项目当前无 ESLint 基础设施,emoji 复发概率低。决策:U5 瘦身为"风格文档 + pre-commit grep 守卫",删除自定义 ESLint/ruff 规则。
P2 发现(6 个):
-
无障碍决策未声明 — 图标替换全程未声明 aria-label/aria-hidden 决策。装饰性图标应
aria-hidden="true",承载语义的图标(如 review pass/fail)需aria-label。决策:在 KTD2 加无障碍子决策。 -
计划状态字段未反映进度 — 仍标记
status: approved,但 U1-U4 已基本完成。决策:更新为status: in-progress,加 progress 字段。 -
BoardBannerCard 实现偏离计划但未记录 — 从"Ant Design 组件"变成"纯文本"。(注:P0 修复已更新 AE1/U2/KTD2 描述,但 KTD2 取舍段落仍提及"放弃了 emoji 头像换取视觉一致性",需补充"无图标"理由。)决策:在 KTD2 取舍段补理由。
-
"无图标"第三选项从未被计划考虑 — KTD2 选项空间只有"emoji vs Ant Design 组件",实际实现了"无图标"。决策:在 KTD2 补"无图标"为显式选项并给取舍。
-
KTD4 旧行
📋无主动清理路径 — 被动等待"如用户要求显式清理"。决策:加主动触发条件(如"下次 schema migration 时顺带 UPDATE")。 -
U5 "阻止 build" 验收与现有 build 流程脱节 —
npm run build是vue-tsc --noEmit && vite build,不跑 ESLint。决策:明确接入点(pre-commit 拦截 vs build 前置检查)。
Sources & Research
- 本地参考:
frontend/src/components/chat/helpers/expertIdentity.ts— 字符首字母策略的权威实现frontend/src/components/bitable/bitableIcons.ts:89—resolveBitableIcon的回退路径docs/plans/2026-06-19-001-feat-chat-area-vi-redesign-plan.md:192— BoardBannerCard 的设计说明(含🏛️)docs/plans/2026-07-01-001-feat-ui-ue-enhancement-plan.md:154-155— StickyModeHeader 的 emoji 头像渲染说明
- 项目记忆:
- 「UI components must use consistent color tokens; avoid hardcoded blue fallback colors」— 沿用到图标风格统一
- 「CSS token fallback values can cause unintended color changes when tokens load late」— Ant Design Vue 组件是设计良好的回退机制
- 无外部研究触发:emoji 替换是纯内部风格收敛,无外部 API/技术依赖。
Plan Metadata
- Depth: Standard(5 个 implementation units,跨前后端+CLI+DB+测试+lint 守卫)
- Expected commits: 5(每个 U 一个 commit;U5 包含 lint 规则可能拆 2 个)
- Risk profile: 中(无安全/支付/外部 API 风险,主要是视觉/UX 风险)
- Origin: 用户直接在 ce-plan 中提出(无 upstream brainstorm doc)
- Confidence: 中高(KTD1-4 都有项目内既有模式可遵循;KTD5/6 引入新机制,U5 留验证空间)