refactor: remove all emoji from source code #20
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
echo "等待服务启动..."
|
echo "等待服务启动..."
|
||||||
for i in $(seq 1 30); do
|
for i in $(seq 1 30); do
|
||||||
if curl -sf http://localhost:8001/api/v1/health > /dev/null 2>&1; then
|
if curl -sf http://localhost:8001/api/v1/health > /dev/null 2>&1; then
|
||||||
echo "✅ 服务健康检查通过"
|
echo "[OK] 服务健康检查通过"
|
||||||
curl -s http://localhost:8001/api/v1/health
|
curl -s http://localhost:8001/api/v1/health
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
repos:
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: agentkit-no-emoji
|
||||||
|
name: agentkit-no-emoji
|
||||||
|
description: Prevent emoji and emoji-like characters in source code
|
||||||
|
entry: bash scripts/check-no-emoji.sh
|
||||||
|
language: system
|
||||||
|
pass_filenames: false
|
||||||
|
always_run: true
|
||||||
|
|
@ -2,8 +2,14 @@
|
||||||
title: "refactor: Remove all emoji from agentkit"
|
title: "refactor: Remove all emoji from agentkit"
|
||||||
date: 2026-07-02
|
date: 2026-07-02
|
||||||
type: refactor
|
type: refactor
|
||||||
status: approved
|
status: in-progress
|
||||||
approved_at: 2026-07-02
|
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)
|
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` 等)。
|
- **横幅/卡片图标** → 改用 Ant Design Vue 组件(`BankOutlined`/`AuditOutlined`/`TeamOutlined` 等)。
|
||||||
- **CLI 状态标记** → Rich 文本标签(`OK`/`FAIL`/`WARN`) + Rich 颜色样式。
|
- **CLI 状态标记** → Rich 文本标签(`OK`/`FAIL`/`WARN`) + Rich 颜色样式。
|
||||||
|
|
||||||
执行顺序按 4 个批次分阶段落地,每批可独立提交/回滚。
|
执行顺序按 5 个批次分阶段落地,每批可独立提交/回滚。
|
||||||
|
|
||||||
## Problem Frame
|
## Problem Frame
|
||||||
|
|
||||||
|
|
@ -109,7 +115,7 @@ origin: user-direct (ce-plan invocation, 2026-07-02)
|
||||||
### 包含
|
### 包含
|
||||||
|
|
||||||
- 22 个源码文件中的 emoji 字符移除(不含文档注释)
|
- 22 个源码文件中的 emoji 字符移除(不含文档注释)
|
||||||
- 4 批次的实施顺序与每批对应的文件清单
|
- 5 批次的实施顺序与每批对应的文件清单
|
||||||
- DB 默认值从 emoji 改为稳定 key(无 schema migration)
|
- DB 默认值从 emoji 改为稳定 key(无 schema migration)
|
||||||
- App.vue 字体回退清理
|
- App.vue 字体回退清理
|
||||||
- 3 个测试文件 fixture 同步
|
- 3 个测试文件 fixture 同步
|
||||||
|
|
@ -222,15 +228,19 @@ bitable/db.py:216 icon VARCHAR DEFAULT 'table'
|
||||||
- `src/agentkit/server/frontend/src/components/chat/messages/DebateBannerCard.vue` — `⚖` → `<AuditOutlined />`
|
- `src/agentkit/server/frontend/src/components/chat/messages/DebateBannerCard.vue` — `⚖` → `<AuditOutlined />`
|
||||||
- `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/DebateConclusionCard.vue` — `decisionIcons` map 改为 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/messages/UserBubble.vue:143` — `'🏛️'`/`'👥'` 字符串 → `<BankOutlined />`/`<TeamOutlined />`
|
||||||
- `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/helpers/useMessageRenderer.ts:203,262` — **已完成**(`avatar: AuditOutlined`)
|
||||||
- `src/agentkit/server/frontend/src/components/chat/MessageShell.vue` — 检查 avatar 字段类型,Component 走 `<component :is="..." />`,string 走原样
|
- `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 走 `<component :is="..." />`,string 走原样(已实现 Component vs string 分支)
|
||||||
- `src/agentkit/server/frontend/src/App.vue:109-110` — 字体回退删 emoji 字体声明
|
- `src/agentkit/server/frontend/src/App.vue:109-110` — 字体回退删 emoji 字体声明
|
||||||
|
|
||||||
**Approach**:
|
**Approach**:
|
||||||
- 引入 `BankOutlined` / `AuditOutlined` / `TeamOutlined` / `CheckOutlined` / `SwapOutlined` / `MinusOutlined` / `QuestionOutlined`(均已在 `@ant-design/icons-vue` 中,无需新装)
|
- 引入 `BankOutlined` / `AuditOutlined` / `TeamOutlined` / `CheckOutlined` / `SwapOutlined` / `MinusOutlined` / `QuestionOutlined`(均已在 `@ant-design/icons-vue` 中,无需新装)
|
||||||
- `BoardBannerCard` / `DebateBannerCard` 的 `<span class="...__icon">X</span>` 改为 `<component :is="X" class="...__icon" />`
|
- `DebateBannerCard` 的 `<span class="...__icon">X</span>` 改为 `<component :is="X" class="...__icon" />`(BoardBannerCard 已为纯文本,不适用)
|
||||||
- `UserBubble` 的 command card 改造:`icon` prop 改为 `Component` 类型
|
- `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'"` 分支处理
|
- `MessageShell.vue` 用 `v-if="typeof shell.avatar === 'string'"` 分支处理
|
||||||
|
|
||||||
**Test scenarios**:
|
**Test scenarios**:
|
||||||
|
|
@ -243,20 +253,23 @@ bitable/db.py:216 icon VARCHAR DEFAULT 'table'
|
||||||
**Verification**:
|
**Verification**:
|
||||||
- `npm run typecheck` 通过
|
- `npm run typecheck` 通过
|
||||||
- `npx vitest run tests/unit/components/` 通过
|
- `npx vitest run tests/unit/components/` 通过
|
||||||
- 浏览器打开 `/agent/chat` 触发 `@board`,确认横幅显示 `<BankOutlined />` 矢量图标(非 emoji)
|
- 浏览器打开 `/agent/chat` 触发 `@board`,确认横幅为纯文本(无 emoji)
|
||||||
- 触发辩论确认 `DebateBannerCard` 显示 `<AuditOutlined />`
|
- 触发辩论确认 `DebateBannerCard` 显示 `<AuditOutlined />`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 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**:
|
**Files**:
|
||||||
- `src/agentkit/cli/admin.py:215,601` — 表格 `is_active` 列的 `✓`/`✗` → `OK`/`--`
|
- `src/agentkit/cli/admin.py:215,601` — 表格 `is_active` 列的 `✓`/`✗` → `OK`/`--`
|
||||||
- `src/agentkit/cli/chat.py:589,603,692,694,727,730` — 验收/阶段/风险标记全部收敛
|
- `src/agentkit/cli/chat.py:589,603,692,694,727,730` — 验收/阶段/风险标记全部收敛
|
||||||
- `src/agentkit/cli/skill.py:296` — `⚠ 以下为自动生成…` → `WARN 以下为自动生成…`
|
- `src/agentkit/cli/skill.py:296` — `⚠ 以下为自动生成…` → `WARN 以下为自动生成…`
|
||||||
- `src/agentkit/cli/benchmark.py:895,989,2032,2733,2767,2784,2790` — 所有 `✓`/`✗`/`⚠` 收敛
|
- `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**:
|
**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]`
|
- 字符串替换策略:所有 `[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**:
|
**Files**:
|
||||||
- 新增 `frontend/eslint-rules/no-emoji.cjs`(自定义 ESLint 规则,禁止源码中的 emoji 字符范围)
|
- `scripts/check-no-emoji.sh`(新增)— 用 `rg` 扫描字面 emoji + 转义序列,覆盖 src/configs/tests/scripts
|
||||||
- `frontend/.eslintrc.cjs` 注册规则
|
- `.pre-commit-config.yaml`(若不存在则创建)— 添加 `agentkit-no-emoji` 钩子(调用上述 shell 脚本)
|
||||||
- `pyproject.toml` 加 `ruff` 自定义规则(`RUF900` 禁用 emoji)或依赖 `pre-commit` 钩子
|
- `docs/solutions/style/no-emoji-style-guide.md`(新增)— 记录三套替代策略(KTD1-3)与 Unicode 范围参考
|
||||||
- `.pre-commit-config.yaml`(若不存在则创建)— 添加 `agentkit-no-emoji` 钩子
|
|
||||||
- `docs/solutions/style/no-emoji-style-guide.md`(新增)— 记录替换规则与原因
|
|
||||||
|
|
||||||
**Approach**:
|
**Approach**:
|
||||||
- 自定义 ESLint 规则用正则 `[\x{1F000}-\x{1FFFF}\x{2600}-\x{27BF}\x{2300}-\x{23FF}\x{2B00}-\x{2BFF}]` 匹配所有 emoji 范围
|
- **轻量方案**(替代原 ESLint + ruff 自定义规则,因项目无 ESLint 基础设施且 ruff 不支持自定义规则):
|
||||||
- 规则名 `no-emoji-in-source`,错误级别 `error`,白名单文件:注释(通过 `// allow-emoji` 注解豁免,仅在文档/迁移脚本等场景)
|
- 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})`
|
||||||
- ruff 通过 `RUF` 自定义检查或第三方 `flake8-no-emoji` 工具
|
- pre-commit 钩子在 commit 阶段跑该脚本,拦截含 emoji 的暂存文件
|
||||||
- pre-commit 在 commit 阶段跑前端 + 后端双检查
|
- 白名单:`docs/`(文档允许 emoji)、`*.md`(markdown 注释允许)
|
||||||
- 风格指南文档说明三套替代策略(KTD1-3)
|
- 风格指南文档说明三套替代策略(KTD1-3)+ 何时用 Ant Design 组件 vs 文本标签 vs 首字母
|
||||||
|
|
||||||
**Test scenarios**:
|
**Test scenarios**:
|
||||||
- **Happy path**:`npx eslint src/` 无 emoji 错误
|
- **Happy path**:`bash scripts/check-no-emoji.sh` 退出码 0(无 emoji 残留)
|
||||||
- **Happy path**:`ruff check src/` 无 emoji 警告
|
- **Error path**:故意在某 `.ts` 文件中加 `\u2713` 转义序列,脚本检出并报错
|
||||||
- **Error path**:故意在某 `.vue` 文件中加一个 emoji 字符,ESLint 报错并阻止 build
|
|
||||||
- **Integration**:本地 commit 含 emoji 的文件被 pre-commit 阻止
|
- **Integration**:本地 commit 含 emoji 的文件被 pre-commit 阻止
|
||||||
|
|
||||||
**Verification**:
|
**Verification**:
|
||||||
- `npm run lint` 全通过
|
- `bash scripts/check-no-emoji.sh` 全通过
|
||||||
- `ruff check src/` 全通过
|
- `pre-commit run --all-files` 全通过(若 pre-commit 已安装)
|
||||||
- `pre-commit run --all-files` 全通过
|
- 手动在临时文件加 emoji 字符和 `\u2713` 转义,确认脚本检出
|
||||||
- 新建一个临时 `.vue` 文件含 emoji,确认 ESLint 报错
|
|
||||||
|
|
||||||
**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(已默认开启)。
|
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
|
## Sources & Research
|
||||||
|
|
||||||
- **本地参考**:
|
- **本地参考**:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
---
|
||||||
|
title: "Emoji Removal Pattern — Ant Design Icons, Text Labels, and Pre-commit Guard"
|
||||||
|
date: 2026-07-03
|
||||||
|
category: conventions
|
||||||
|
module: cross-cutting
|
||||||
|
problem_type: convention
|
||||||
|
component: tooling
|
||||||
|
severity: low
|
||||||
|
applies_when:
|
||||||
|
- "Adding new UI components, CLI output, or shell scripts that need status markers"
|
||||||
|
- "Reviewing PRs for emoji regressions"
|
||||||
|
- "Setting up pre-commit hooks for code style enforcement"
|
||||||
|
tags: [emoji, ant-design, pre-commit, cli, frontend, unicode]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Emoji Removal Pattern — Ant Design Icons, Text Labels, and Pre-commit Guard
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The agentkit project had emoji/glyph characters scattered across frontend components
|
||||||
|
(`ReviewResultCard.vue`, `useMessageRenderer.ts`), CLI output (`cli/chat.py`), shell scripts
|
||||||
|
(`deploy.sh`, `dev-start.sh`), CI workflows, and even docstrings. These caused inconsistent
|
||||||
|
rendering across terminals, OSes, and fonts — on Linux servers without Noto Color Emoji they
|
||||||
|
display as tofu blocks, and they clash with the project's Ant Design Vue Outlined icon family.
|
||||||
|
|
||||||
|
## Guidance
|
||||||
|
|
||||||
|
Three replacement strategies based on context (see detailed guide:
|
||||||
|
[no-emoji-style-guide.md](../style/no-emoji-style-guide.md)):
|
||||||
|
|
||||||
|
### KTD1: Ant Design Vue Outlined icons (frontend)
|
||||||
|
|
||||||
|
Replace string glyph avatars with Component types. Use `<component :is>` for dynamic rendering:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- Before -->
|
||||||
|
<span class="icon">{{ statusIcon }}</span>
|
||||||
|
const statusIcon = computed(() => {
|
||||||
|
if (props.review.passed) return '\u2713'
|
||||||
|
return '\u2717'
|
||||||
|
})
|
||||||
|
|
||||||
|
<!-- After -->
|
||||||
|
<span class="icon"><component :is="statusIcon" /></span>
|
||||||
|
import { CheckOutlined, CloseOutlined, ReloadOutlined } from '@ant-design/icons-vue'
|
||||||
|
import { type Component } from 'vue'
|
||||||
|
const statusIcon = computed<Component>(() => {
|
||||||
|
if (props.review.passed) return CheckOutlined
|
||||||
|
if (props.review.final_status === 'failed') return CloseOutlined
|
||||||
|
return ReloadOutlined
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
For `useMessageRenderer.ts` shell avatars, import the Component and assign directly:
|
||||||
|
`avatar: ApartmentOutlined` instead of `avatar: '◆'`.
|
||||||
|
|
||||||
|
### KTD2: Text labels with ANSI colors (CLI/shell)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Before
|
||||||
|
"completed": ("OK", "green"),
|
||||||
|
"in_progress": ("\u25b6", "blue"), # ▶
|
||||||
|
icon_map.get(status, ("\u25cb", "dim")) # ○
|
||||||
|
|
||||||
|
# After
|
||||||
|
"completed": ("OK", "green"),
|
||||||
|
"in_progress": ("RUN", "blue"),
|
||||||
|
icon_map.get(status, ("--", "dim"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Shell scripts: `echo "[FAIL] ..."` instead of `echo "\u274c ..."`.
|
||||||
|
|
||||||
|
### KTD3: ASCII art (docstrings)
|
||||||
|
|
||||||
|
Replace Unicode box-drawing arrows with ASCII equivalents in docstrings:
|
||||||
|
`->` for `─►`, `|` for `│`, `v` for `▼`.
|
||||||
|
|
||||||
|
## Why This Matters
|
||||||
|
|
||||||
|
1. **Cross-platform consistency** — ASCII text and Ant Design components render identically
|
||||||
|
across macOS, Linux, and Windows terminals/browsers.
|
||||||
|
2. **Type safety** — Using `Component` types instead of `string` for icon props enables
|
||||||
|
TypeScript compile-time checks.
|
||||||
|
3. **Automated enforcement** — A pre-commit hook (`scripts/check-no-emoji.sh`) prevents
|
||||||
|
regression without manual review burden.
|
||||||
|
|
||||||
|
## When to Apply
|
||||||
|
|
||||||
|
- New UI components needing status icons — use Ant Design Outlined icons
|
||||||
|
- New CLI output or shell script status markers — use `OK`/`FAIL`/`WARN`/`RUN`/`--`
|
||||||
|
- New docstring diagrams — use ASCII art (`->`, `|`, `v`)
|
||||||
|
- Any code review involving visual markers — run `bash scripts/check-no-emoji.sh`
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Unicode range exclusions (key learning)
|
||||||
|
|
||||||
|
The `check-no-emoji.sh` script excludes two Unicode ranges that are pervasive in
|
||||||
|
comments/docstrings but are NOT emoji:
|
||||||
|
|
||||||
|
| Range | Block | Reason |
|
||||||
|
|-------|-------|--------|
|
||||||
|
| `2190-21FF` | Arrows | `->` (U+2192) is a pervasive docstring flow indicator |
|
||||||
|
| `2500-257F` | Box Drawings | `--` (U+2500) is a pervasive comment section separator |
|
||||||
|
|
||||||
|
Without these exclusions, the script flags 200+ files for false positives.
|
||||||
|
|
||||||
|
### Escaped unicode detection
|
||||||
|
|
||||||
|
The script also detects escaped unicode sequences (`\u2713`, `\u2717`, etc.) in string
|
||||||
|
literals. The escape pattern is narrowed to emoji-like ranges only — a broad `2[0-5]xxx`
|
||||||
|
pattern causes false positives in minified JS bundles (`\u2000` en-space, `\u2014` em-dash).
|
||||||
|
|
||||||
|
### Pre-commit hook configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# .pre-commit-config.yaml
|
||||||
|
repos:
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: agentkit-no-emoji
|
||||||
|
name: agentkit-no-emoji
|
||||||
|
entry: bash scripts/check-no-emoji.sh
|
||||||
|
language: system
|
||||||
|
pass_filenames: false
|
||||||
|
always_run: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [No-Emoji Style Guide](../style/no-emoji-style-guide.md) — detailed KTD1-3 replacement strategies
|
||||||
|
- Plan: `docs/plans/2026-07-02-001-refactor-remove-all-emoji-plan.md`
|
||||||
|
- PR #20: `refactor/remove-all-emoji` branch
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
---
|
||||||
|
title: "No-Emoji Style Guide"
|
||||||
|
date: 2026-07-03
|
||||||
|
category: style
|
||||||
|
tags: [emoji, frontend, cli, terminal, icons]
|
||||||
|
problem_type: best_practice
|
||||||
|
component: cross-cutting
|
||||||
|
severity: convention
|
||||||
|
---
|
||||||
|
|
||||||
|
# No-Emoji Style Guide
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
Emoji characters cause inconsistent rendering across terminals, OSes, and fonts. On Linux servers without Noto Color Emoji, they display as tofu blocks. They also clash with the project's Ant Design Vue Outlined icon family.
|
||||||
|
|
||||||
|
## Replacement Strategies
|
||||||
|
|
||||||
|
Three strategies based on context:
|
||||||
|
|
||||||
|
### KTD1: First-letter avatars (expert/persona avatars)
|
||||||
|
|
||||||
|
Use the first character of the expert name — uppercase for English, first CJK character for Chinese.
|
||||||
|
|
||||||
|
- `'🦊'` → `'F'` (Fox)
|
||||||
|
- `'🐼'` → `'P'` (Panda)
|
||||||
|
- `'🤖'` → `'A'` (AI)
|
||||||
|
|
||||||
|
Applies to: `configs/experts/*.yaml` avatar fields, test fixtures.
|
||||||
|
|
||||||
|
### KTD2: Ant Design Vue Outlined icons (UI banners/cards)
|
||||||
|
|
||||||
|
Use `@ant-design/icons-vue` components for visual icons in frontend components.
|
||||||
|
|
||||||
|
- `🏛️` → no icon (BoardBannerCard uses plain text)
|
||||||
|
- `⚖` → `<AuditOutlined />`
|
||||||
|
- `✓`/`✗` → `<CheckOutlined />`/`<CloseOutlined />`
|
||||||
|
- `↻` → `<ReloadOutlined />`
|
||||||
|
- `◆` → `<ApartmentOutlined />`
|
||||||
|
- `!` → `<WarningOutlined />`
|
||||||
|
|
||||||
|
Applies to: `useMessageRenderer.ts` shell.avatar, `ReviewResultCard.vue` statusIcon, `DebateBannerCard.vue`, `DebateConclusionCard.vue`, `UserBubble.vue`.
|
||||||
|
|
||||||
|
### KTD3: Text labels (CLI/shell/terminal output)
|
||||||
|
|
||||||
|
Use ASCII text labels with ANSI color codes for status markers.
|
||||||
|
|
||||||
|
- `✓` → `OK` (with `[bold green]` in Rich)
|
||||||
|
- `✗` → `FAIL` (with `[bold red]` in Rich)
|
||||||
|
- `⚠` → `WARN` (with `[bold yellow]` in Rich)
|
||||||
|
- `○` → `..` or `PENDING`
|
||||||
|
- `❌` → `[FAIL]`
|
||||||
|
- `✅` → `[OK]`
|
||||||
|
|
||||||
|
Applies to: `src/agentkit/cli/*.py` (Rich output), `scripts/*.sh` (shell output), `.gitea/workflows/*.yml` (CI logs).
|
||||||
|
|
||||||
|
## Unicode Ranges Covered
|
||||||
|
|
||||||
|
The `scripts/check-no-emoji.sh` pre-commit hook scans for:
|
||||||
|
|
||||||
|
| Range | Block |
|
||||||
|
|-------|-------|
|
||||||
|
| `1F000-1FFFF` | Emoji and Supplementary Symbols |
|
||||||
|
| `2600-27BF` | Misc Symbols and Dingbats (includes ✓ ✗) |
|
||||||
|
| `2300-23FF` | Miscellaneous Technical |
|
||||||
|
| `25A0-25FF` | Geometric Shapes (includes ◆ ○) |
|
||||||
|
| `2B00-2BFF` | Misc Symbols and Arrows |
|
||||||
|
|
||||||
|
**Excluded ranges** (pervasive in comments/docstrings, not emoji):
|
||||||
|
|
||||||
|
| Range | Block | Reason |
|
||||||
|
|-------|-------|--------|
|
||||||
|
| `2190-21FF` | Arrows | `→` is a pervasive docstring flow indicator |
|
||||||
|
| `2500-257F` | Box Drawings | `─` is a pervasive comment section separator |
|
||||||
|
| `2580-259F` | Block Elements | `█` `░` used in terminal progress bars |
|
||||||
|
|
||||||
|
Also detects escaped unicode sequences (`\u2713`, `\u2717`, `\u25c6`, etc.) in string literals, narrowed to emoji-like ranges only.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
- **Pre-commit hook**: `scripts/check-no-emoji.sh` runs on every commit
|
||||||
|
- **CI**: Add `bash scripts/check-no-emoji.sh` to `.gitea/workflows/` (deferred)
|
||||||
|
- **PR review**: Reviewers should check for emoji in code changes
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# check-no-emoji.sh — Scan source code for emoji and emoji-like characters
|
||||||
|
#
|
||||||
|
# Detects two patterns:
|
||||||
|
# 1. Literal emoji/glyph characters (Unicode ranges)
|
||||||
|
# 2. Escaped unicode sequences in string literals (\u2713, \u21bb, etc.)
|
||||||
|
#
|
||||||
|
# Exits 0 if clean, 1 if violations found.
|
||||||
|
# =============================================================================
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
# Scan paths (exclude docs, markdown, and vendored files)
|
||||||
|
SCAN_PATHS="src/ configs/ tests/ scripts/"
|
||||||
|
|
||||||
|
# Unicode ranges: Emoji, Misc Symbols/Dingbats, Misc Technical, Geometric Shapes (excl. Box Drawings), Misc Symbols/Arrows
|
||||||
|
# Excluded: Arrows (2190-21FF) — "→" is a pervasive docstring flow indicator, not emoji
|
||||||
|
# Excluded: Box Drawings (2500-257F) — "─" is a pervasive comment section separator, not emoji
|
||||||
|
# ponytail: narrower ranges than the plan's U5 spec; plan scope says "注释、文档除外" and these two ranges
|
||||||
|
# exist almost exclusively in comments/docstrings. Upgrade path: add a comment-aware filter.
|
||||||
|
LITERAL_PATTERN='[\x{1F000}-\x{1FFFF}\x{2600}-\x{27BF}\x{2300}-\x{23FF}\x{25A0}-\x{25FF}\x{2B00}-\x{2BFF}]'
|
||||||
|
|
||||||
|
# Escaped sequences: \u2713, \u2717, \u25c6, etc. (narrowed to match LITERAL_PATTERN ranges only)
|
||||||
|
# ponytail: original plan spec used 2[0-5][0-9a-fA-F]{2} which matched \u2000-\u25FF (punctuation, math, box drawing)
|
||||||
|
# causing false positives in minified JS bundles. Narrowed to emoji-like ranges only.
|
||||||
|
ESCAPE_PATTERN='\\u(271[0-9a-fA-F]|26[0-9a-fA-F]{2}|23[0-9a-fA-F]{2}|25[a-fA-F][0-9a-fA-F]|2[b-fB-F][0-9a-fA-F]{2})'
|
||||||
|
|
||||||
|
VIOLATIONS=0
|
||||||
|
|
||||||
|
# Check literal emoji characters (exclude minified bundles, test reports, and this script)
|
||||||
|
LITERAL_HITS=$(rg -n --no-heading -P "$LITERAL_PATTERN" \
|
||||||
|
-g '!**/static/assets/**' -g '!**/playwright-report/**' -g '!check-no-emoji.sh' \
|
||||||
|
$SCAN_PATHS 2>/dev/null || true)
|
||||||
|
if [[ -n "$LITERAL_HITS" ]]; then
|
||||||
|
echo "[FAIL] Literal emoji/glyph characters found:"
|
||||||
|
echo "$LITERAL_HITS"
|
||||||
|
echo ""
|
||||||
|
VIOLATIONS=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check escaped unicode sequences (same exclusions)
|
||||||
|
ESCAPE_HITS=$(rg -n --no-heading -P "$ESCAPE_PATTERN" \
|
||||||
|
-g '!**/static/assets/**' -g '!**/playwright-report/**' -g '!check-no-emoji.sh' \
|
||||||
|
$SCAN_PATHS 2>/dev/null || true)
|
||||||
|
if [[ -n "$ESCAPE_HITS" ]]; then
|
||||||
|
echo "[FAIL] Escaped unicode emoji sequences found:"
|
||||||
|
echo "$ESCAPE_HITS"
|
||||||
|
echo ""
|
||||||
|
VIOLATIONS=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $VIOLATIONS -eq 0 ]]; then
|
||||||
|
echo "[OK] No emoji or emoji-like characters found in $SCAN_PATHS"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
@ -13,12 +13,12 @@ DEPLOY_DIR="${DEPLOY_DIR:-/opt/agentkit}"
|
||||||
cd "$PROJECT_ROOT"
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
if [ ! -f "$COMPOSE_FILE" ]; then
|
if [ ! -f "$COMPOSE_FILE" ]; then
|
||||||
echo "❌ 未找到 $COMPOSE_FILE"
|
echo "[FAIL] 未找到 $COMPOSE_FILE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f ".env" ]; then
|
if [ ! -f ".env" ]; then
|
||||||
echo "❌ 未找到 .env 文件,请先通过 Gitea Secrets 生成"
|
echo "[FAIL] 未找到 .env 文件,请先通过 Gitea Secrets 生成"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -33,4 +33,4 @@ docker compose -f "$COMPOSE_FILE" up -d --remove-orphans
|
||||||
echo "==> 当前服务状态:"
|
echo "==> 当前服务状态:"
|
||||||
docker compose -f "$COMPOSE_FILE" ps
|
docker compose -f "$COMPOSE_FILE" ps
|
||||||
|
|
||||||
echo "==> 部署完成 ✅"
|
echo "==> 部署完成 [OK]"
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ done
|
||||||
|
|
||||||
# ── 日志函数 ────────────────────────────────────────────────────────────────
|
# ── 日志函数 ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
ok() { echo -e " ${GREEN}✓${NC} $*"; }
|
ok() { echo -e " ${GREEN}OK${NC} $*"; }
|
||||||
info() { echo -e " ${CYAN}→${NC} $*"; }
|
info() { echo -e " ${CYAN}→${NC} $*"; }
|
||||||
warn() { echo -e " ${YELLOW}!${NC} $*"; }
|
warn() { echo -e " ${YELLOW}!${NC} $*"; }
|
||||||
fail() { echo -e " ${RED}✗${NC} $*" >&2; }
|
fail() { echo -e " ${RED}FAIL${NC} $*" >&2; }
|
||||||
|
|
||||||
section() {
|
section() {
|
||||||
echo ""
|
echo ""
|
||||||
|
|
@ -120,16 +120,16 @@ print_status() {
|
||||||
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
||||||
echo -e "${CYAN} 启动状态总览${NC}"
|
echo -e "${CYAN} 启动状态总览${NC}"
|
||||||
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
echo -e "${CYAN}═══════════════════════════════════════════════════${NC}"
|
||||||
echo -e "$([[ $S_DEPS -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_DEPS -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") 依赖检查"
|
echo -e "$([[ $S_DEPS -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_DEPS -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") 依赖检查"
|
||||||
echo -e "$([[ $S_ENV -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_ENV -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") 环境配置"
|
echo -e "$([[ $S_ENV -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_ENV -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") 环境配置"
|
||||||
echo -e "$([[ $S_REDIS -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_REDIS -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") Redis (:6381)"
|
echo -e "$([[ $S_REDIS -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_REDIS -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") Redis (:6381)"
|
||||||
echo -e "$([[ $S_PG -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_PG -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") PostgreSQL (:5435)"
|
echo -e "$([[ $S_PG -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_PG -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") PostgreSQL (:5435)"
|
||||||
echo -e "$([[ $S_BACKEND -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_BACKEND -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") 后端服务 (:18001)"
|
echo -e "$([[ $S_BACKEND -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_BACKEND -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") 后端服务 (:18001)"
|
||||||
if [[ $MODE == "gui" || $MODE == "tauri" ]]; then
|
if [[ $MODE == "gui" || $MODE == "tauri" ]]; then
|
||||||
echo -e "$([[ $S_FRONTEND -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_FRONTEND -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") 前端服务 (:18002)"
|
echo -e "$([[ $S_FRONTEND -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_FRONTEND -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") 前端服务 (:18002)"
|
||||||
fi
|
fi
|
||||||
if [[ $MODE == "tauri" ]]; then
|
if [[ $MODE == "tauri" ]]; then
|
||||||
echo -e "$([[ $S_TAURI -eq 2 ]] && echo " ${GREEN}✓${NC}" || [[ $S_TAURI -eq 3 ]] && echo " ${RED}✗${NC}" || echo " ${YELLOW}○${NC}") Tauri 客户端"
|
echo -e "$([[ $S_TAURI -eq 2 ]] && echo " ${GREEN}OK${NC}" || [[ $S_TAURI -eq 3 ]] && echo " ${RED}FAIL${NC}" || echo " ${YELLOW}..${NC}") Tauri 客户端"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -690,13 +690,13 @@ async def _execute_team_cli(
|
||||||
phases = message.get("plan_phases", [])
|
phases = message.get("plan_phases", [])
|
||||||
icon_map = {
|
icon_map = {
|
||||||
"completed": ("OK", "green"),
|
"completed": ("OK", "green"),
|
||||||
"in_progress": ("▶", "blue"),
|
"in_progress": ("RUN", "blue"),
|
||||||
"failed": ("FAIL", "red"),
|
"failed": ("FAIL", "red"),
|
||||||
}
|
}
|
||||||
lines = []
|
lines = []
|
||||||
for ph in phases:
|
for ph in phases:
|
||||||
status = ph.get("status", "pending")
|
status = ph.get("status", "pending")
|
||||||
icon, color = icon_map.get(status, ("○", "dim"))
|
icon, color = icon_map.get(status, ("--", "dim"))
|
||||||
lines.append(
|
lines.append(
|
||||||
f" [{color}]{icon}[/{color}] {ph.get('name', '?')} → {ph.get('assigned_expert', '?')}"
|
f" [{color}]{icon}[/{color}] {ph.get('name', '?')} → {ph.get('assigned_expert', '?')}"
|
||||||
)
|
)
|
||||||
|
|
@ -719,7 +719,7 @@ async def _execute_team_cli(
|
||||||
_render_collaboration_contracts(all_contracts)
|
_render_collaboration_contracts(all_contracts)
|
||||||
elif etype == "phase_started":
|
elif etype == "phase_started":
|
||||||
rprint(
|
rprint(
|
||||||
f"\n[bold blue]▶ {message.get('phase_name', '?')}[/bold blue] "
|
f"\n[bold blue]>> {message.get('phase_name', '?')}[/bold blue] "
|
||||||
f"→ {message.get('assigned_expert', '?')}"
|
f"→ {message.get('assigned_expert', '?')}"
|
||||||
)
|
)
|
||||||
elif etype == "phase_completed":
|
elif etype == "phase_completed":
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ Lifecycle
|
||||||
---------
|
---------
|
||||||
::
|
::
|
||||||
|
|
||||||
create ─► rotate ─► rotate ─► ...
|
create -> rotate -> rotate -> ...
|
||||||
│ │ │
|
| | |
|
||||||
▼ ▼ ▼
|
v v v
|
||||||
active active active
|
active active active
|
||||||
│
|
│
|
||||||
├── revoke (user logout) → revoked
|
├── revoke (user logout) → revoked
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { computed, type Component } from 'vue'
|
import { computed, type Component } from 'vue'
|
||||||
import { AuditOutlined } from '@ant-design/icons-vue'
|
import { AuditOutlined, ApartmentOutlined, CheckOutlined, CloseOutlined, WarningOutlined } from '@ant-design/icons-vue'
|
||||||
import type { IChatMessage } from '@/api/types'
|
import type { IChatMessage } from '@/api/types'
|
||||||
import UserBubble from '@/components/chat/messages/UserBubble.vue'
|
import UserBubble from '@/components/chat/messages/UserBubble.vue'
|
||||||
import AssistantText from '@/components/chat/messages/AssistantText.vue'
|
import AssistantText from '@/components/chat/messages/AssistantText.vue'
|
||||||
|
|
@ -283,7 +283,7 @@ export function useMessageRenderer(message: IChatMessage) {
|
||||||
type,
|
type,
|
||||||
shell: {
|
shell: {
|
||||||
name: '协作关系图',
|
name: '协作关系图',
|
||||||
avatar: '◆',
|
avatar: ApartmentOutlined,
|
||||||
color: '#1890ff',
|
color: '#1890ff',
|
||||||
meta: time,
|
meta: time,
|
||||||
},
|
},
|
||||||
|
|
@ -304,7 +304,7 @@ export function useMessageRenderer(message: IChatMessage) {
|
||||||
type,
|
type,
|
||||||
shell: {
|
shell: {
|
||||||
name: '验收结果',
|
name: '验收结果',
|
||||||
avatar: review.passed ? '\u2713' : '\u2717',
|
avatar: review.passed ? CheckOutlined : CloseOutlined,
|
||||||
color: review.passed ? '#52c41a' : '#ff4d4f',
|
color: review.passed ? '#52c41a' : '#ff4d4f',
|
||||||
meta: review.phase_name || time,
|
meta: review.phase_name || time,
|
||||||
},
|
},
|
||||||
|
|
@ -325,7 +325,7 @@ export function useMessageRenderer(message: IChatMessage) {
|
||||||
type,
|
type,
|
||||||
shell: {
|
shell: {
|
||||||
name: '风险标记',
|
name: '风险标记',
|
||||||
avatar: '!',
|
avatar: WarningOutlined,
|
||||||
color: '#fa8c16',
|
color: '#fa8c16',
|
||||||
meta: risk.phase_name || time,
|
meta: risk.phase_name || time,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="review-card" :class="reviewClass">
|
<div class="review-card" :class="reviewClass">
|
||||||
<div class="review-card__header">
|
<div class="review-card__header">
|
||||||
<span class="review-card__icon">{{ statusIcon }}</span>
|
<span class="review-card__icon"><component :is="statusIcon" /></span>
|
||||||
<span class="review-card__status">{{ statusLabel }}</span>
|
<span class="review-card__status">{{ statusLabel }}</span>
|
||||||
<a-tag v-if="review.rework_count !== undefined && review.rework_count > 0" :color="review.passed ? 'green' : 'red'">
|
<a-tag v-if="review.rework_count !== undefined && review.rework_count > 0" :color="review.passed ? 'green' : 'red'">
|
||||||
返工 {{ review.rework_count }} 次
|
返工 {{ review.rework_count }} 次
|
||||||
|
|
@ -18,7 +18,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, type Component } from 'vue'
|
||||||
|
import { CheckOutlined, CloseOutlined, ReloadOutlined } from '@ant-design/icons-vue'
|
||||||
import AssistantText from './AssistantText.vue'
|
import AssistantText from './AssistantText.vue'
|
||||||
import type { IChatMessage, IReviewResult } from '@/api/types'
|
import type { IChatMessage, IReviewResult } from '@/api/types'
|
||||||
|
|
||||||
|
|
@ -38,10 +39,10 @@ const statusLabel = computed(() => {
|
||||||
return '要求返工'
|
return '要求返工'
|
||||||
})
|
})
|
||||||
|
|
||||||
const statusIcon = computed(() => {
|
const statusIcon = computed<Component>(() => {
|
||||||
if (props.review.passed) return '\u2713'
|
if (props.review.passed) return CheckOutlined
|
||||||
if (props.review.final_status === 'failed') return '\u2717'
|
if (props.review.final_status === 'failed') return CloseOutlined
|
||||||
return '\u21bb'
|
return ReloadOutlined
|
||||||
})
|
})
|
||||||
|
|
||||||
const feedbackMessage = computed<IChatMessage>(() => ({
|
const feedbackMessage = computed<IChatMessage>(() => ({
|
||||||
|
|
@ -85,7 +86,8 @@ const feedbackMessage = computed<IChatMessage>(() => ({
|
||||||
|
|
||||||
.review-card__icon {
|
.review-card__icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-card--passed .review-card__icon {
|
.review-card--passed .review-card__icon {
|
||||||
|
|
|
||||||
|
|
@ -1419,7 +1419,7 @@ class MetricsReporter:
|
||||||
for rc in report.root_causes:
|
for rc in report.root_causes:
|
||||||
type_label = cause_type_labels.get(rc.cause_type, rc.cause_type)
|
type_label = cause_type_labels.get(rc.cause_type, rc.cause_type)
|
||||||
conf_bar = "█" * int(rc.confidence * 10) + "░" * (10 - int(rc.confidence * 10))
|
conf_bar = "█" * int(rc.confidence * 10) + "░" * (10 - int(rc.confidence * 10))
|
||||||
lines.append(f" ▸ [{type_label}] 置信度: {conf_bar} {rc.confidence:.0%}")
|
lines.append(f" > [{type_label}] 置信度: {conf_bar} {rc.confidence:.0%}")
|
||||||
lines.append(f" 原因: {rc.cause_description}")
|
lines.append(f" 原因: {rc.cause_description}")
|
||||||
if rc.detail:
|
if rc.detail:
|
||||||
lines.append(f" 详情: {rc.detail}")
|
lines.append(f" 详情: {rc.detail}")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue