# dsh-code-pill 设计文档

## 1. 产品定位与本次扩展

Code Pill 用于 DSH 对话中的行内代码：薄背景、克制的语法色、可选文件标记。
设置页注册到宿主 `settings.section`，不建立独立服务器，不向消息插入交互按钮。
0.3.0 增加六套深浅配对预设、自定义颜色、文件标记、排版参数、代码块颜色与配置导入导出，并将 Font Lab 接入第二个「字体」Tab。字体即时应用，代码外观保留草稿和显式保存，两者独立存储与清理。
工具调用行（读取／写入／编辑）里的文件路径也渲染成胶囊：宿主把路径渲染成行摘要而不是行内代码，行内代码管线看不到它，插件按宿主自己的行标记识别并单独装饰。

## 2. 核心约束

1. **不替换消息子节点。** 默认渲染管线只给 React 管理的 code 加 class/data 属性；语法色用 CSS Custom Highlight，文件标记用伪元素。可选「显示平滑」只在运行中的回复里改写现有 Text 的 `nodeValue` 来控制揭示进度，不替换节点；关闭、卸载时恢复完整文字。
2. **宁可少染，不误伤术语。** 标识符、路径、URL、文件名默认 plain，只有明确表达式和命令启用启发式扫描。
3. **增量更新。** 九个持久 Highlight 集合按 code 增删 Range，不在流式更新时重建全文。
4. **草稿隔离。** 设置页面由 React 渲染独立预览，使用 `data-dshcp-preview` 排除聊天渲染管线。修改草稿不影响真实聊天。
5. **显式保存。** 只有“保存并应用”写浏览器存储、更新渲染；取消恢复已保存配置，关闭页面丢弃草稿。
6. **单一色源。** `src/settings-core.cjs` 定义色板；CSS 生成器、设置预览和审计读取同一数据。`src/styles.css` 只定义几何、伪元素和界面布局。
7. **不覆盖宿主安装。** 开发产物只写工作区，不修改 DSH 安装目录、Profile 或生产插件。

## 3. 语义与文件标记

解析类别为 kwc/kwd/str/com/num/fn/typ/cst/prm；默认文字 plain 加前五类构成六个独立颜色。
fn/typ/cst/prm 并入 plain：行内表达式不是完整编辑器，不必把所有角色拆色。
不承诺完整语言解析；精确高亮使用带语言的宿主代码块。

文件标记只用于命中的文件名，不用于普通表达式：

| 模式 | 行为 |
| --- | --- |
| off | 不显示标记 |
| label | 文件名前显示语言缩写 |
| icon | 文件名前显示单色文件图标 |
| both | 文件名前图标、文件名后语言缩写 |

图标为本地 CSS SVG mask，继承当前文字色，无 CDN、无品牌 Logo、无消息子节点插入。
徽章使用独立的实色背景与文字色，避免叠层背景使审计失真。
文件检测支持常用扩展名、特殊 basename、Windows 分隔符与中文路径；有空白的路径仍保守降级。

### 3.1 聊天文件路径

路径渲染独立在 `src/path-renderer.js`：展示位置适配器返回元素、路径和种类，共用装饰与对账清理；行内代码保留独立语法管线。
更新按影响范围增量处理，开销与会话长度无关：文本变化只复核受影响的候选形状元素及其归属内祖先链，结构变化只重扫变更子树（新增/删除节点、容器语义属性），仅初始挂载与设置变更做一次全量对账；与归属无关的变更（如侧栏）经相关性探针直接跳过。

| 展示位置 | 识别边界 |
| --- | --- |
| 工具摘要 | `data-tool` + `data-variant`，只处理 read/write/edit 变体行头里的 fileLink/summary |
| 正文文件引用 | 聊天流内宿主 fileMention 按钮，排除技能引用、附件与工具卡片 |
| 搜索路径 | `data-search=paths` 的路径行及 `data-search=matches` 的文件名；不处理匹配内容和行号 |
| 读取标题 | `data-read` 内代码栏的 title；不重复已有语言标签 |
| 路径标签 | 聊天流内 `data-path-label`，从完整 title 取路径，保留宿主截断结构 |

除工具摘要外必须处于 `data-chat-flow` 内，预览、可编辑区域、附件和 pre 排除。没有语义标记的部分采用已核实的 CSS-module 局部名后缀回退；不依赖哈希前缀，但宿主改局部名仍可能漏染，需要版本回归。未知结构不扫描全文猜测。图片预览引用若缺少可信路径 title，保留宿主外观，不根据任意链接别名推断路径或徽章。

明确的文件容器允许含空格、未知扩展名和长路径；路径身份与语言徽章分离，徽章只取 basename/扩展名。缺少语义保证的文本仍用保守形状判断。路径单色，不拆分语法色。

配置键沿用 `toolPath`（默认开启），界面显示“聊天文件路径”，关闭时撤销上述所有路径装饰。终端命令、ANSI 输出、diff 增删色和读取正文继续由宿主负责。

### 3.2 思考文字彩虹刷入

可选效果（默认关闭，配置键 `thinkRainbow`）：新单词出现时分配一个固定初始颜色，保持 160ms，再只向宿主正文色淡出，约 400ms 后移除高亮。同一单词不轮换色相；不同新词依次分配五种初始色，快速流式显示时形成短尾彩虹。独立在 `src/think-ink.js`，动画不参与宿主正文的追加调度。

| 约束 | 做法 |
| --- | --- |
| 范围 | 运行中的思考行（`data-variant=think` + `data-state=running`）里的展开正文（`data-markdown-variant=compact`）和折叠预览摘要（`data-streaming`）；代码块、设置预览除外 |
| 不改宿主节点 | 只在 scope 元素上加 `data-dshcp-ink`；颜色全部走 CSS Custom Highlight |
| 新增文字 | `StaticRange` 保留 nodeValue 追加重写时的偏移；只处理新增尾部，半词续写延长原范围，不改变初始色相或重置出生时间；非追加改动先撤掉该节点旧范围，再在预算内处理新尾部 |
| 固定词色与淡出 | 5 个固定色相 × 4 档透明混色，共 20 个 Highlight；保持 160ms 后按 80ms 三档淡向宿主色，约 400ms 后移除，不写死白色。色相仅由单词编号决定，与年龄无关 |
| 工作预算 | 正文／摘要共享最多 16 个活跃词，超出窗口立即还原最旧词，不排队播放；每批最多处理 16 个词，只对尾部 128 字符及 48 字符上下文分词，优先最新节点，其余文字同样登记为历史、以后不补播；原生 Intl.Segmenter 不可用时用有界词段降级 |
| 调度 | 单个合并 setTimeout 按下一档到期时间调度，最小间隔 50ms；不使用动画 RAF，不为每个词创建定时器，无活跃词时不再调度 |
| 不播放 | 历史内容（scope 首次登记时已有超过 120 字）、结算重挂载、单次新增超过 1200 字、超过 48 字符的长词、代码块、系统「减少动态效果」 |
| 色板 | 明度由主题变量 `--dshcp-ink-l` 决定（浅色 48%，深色 66%），底色为 `--dsw-alias-label-tertiary`；纯装饰，不属于预设色板对比度审计 |

设置页开关在选择预设时保持不变：它是行为选项，不属于预设外观。

### 3.3 折叠动作行着色

可选效果（默认关闭，配置键 `rowTint`）：让一长串折叠行里的「图标 + 动作 + 完成状态」一眼可分。普通折叠行由 DisclosureRow 渲染，行根带 `data-variant` / `data-tool` / `data-state`；技能与 Cordis 执行卡片有独立头部，新增工具等上下文提示则按聊天 `context` flow 和 slot 位置定位。类别与状态着色仍是纯 CSS，不改宿主属性和子节点；标准行、独立卡片、上下文提示分别使用经过核对的结构选择器，不猜本地化标题或参数。

| 项 | 做法 |
| --- | --- |
| 类别色 | `ROW_CATEGORIES` 统一定义读取、搜索、写入／编辑／交付、命令与终端、思考、会话与事件、代理与编排、任务与目标、定时与提醒、技能、提问与确认、工具与上下文 12 类及工具标识、名称、预览示例；只上到图标与动作名，动作名向宿主灰回混 18%，悬停回满色，描述保持宿主色 |
| 分类优先级 | 先按 `data-variant`，再按具体 `data-tool` 细分 `others`，最后失败／中断覆盖；每个 owner 重设类别变量，嵌套行不继承外层失败色。未知 MCP／插件工具使用工具类别兜底，不根据翻译文案或参数猜测 |
| 独立头部 | 技能按 `data-tool="skill"` 的直接头部与末尾 TextShimmer 定位，适配隐藏状态 span；Cordis 运行／停止／移除按直接头部的图标、动作名 span 定位，准备态仍走标准 DisclosureRow；上下文提示限定在聊天 `context` flow 的 `conversation.chat.node` 下的 DisclosureRow，不扩散到普通用户消息 |
| 状态色 | 失败行图标与动作名换红，中断行换琥珀，覆盖类别色；运行中保持类别色（宿主自带闪光）；成功不加色，避免满屏绿色 |
| bash 行 | 不走 DisclosureRow，行根自己带 `data-sample="bash"`，按同一规则着色 |
| 完成状态词 | 摘要末尾的已完成／已交付／成功等词，只在 `others` 与交付文件行里识别，要求行状态与词义一致（成功行只染完成词，失败行只染失败词，中断行只染中断词）；英文状态词必须自成一词（前面不是字母或数字，所以 `incomplete` 不染）；中文词不加边界，因为宿主自己的文案是粘连的（“交付失败”“处理失败”），但成功类只认带“已”的“已完成／已交付”，裸的“完成／成功”不认（所以 `任务完成` 不染）；`2/4 已完成` 这类进度未满的不染；动作名、命令描述、路径不参与；用 StaticRange + CSS Custom Highlight 上色 |
| 色板 | 内置默认值是 `settings-core` 的 `ROW_TINTS`（单一色源）；用户自定义存为配置 `rowColors`（`light`/`dark` 各 15 项（12 类别 + 3 状态），可部分覆盖，严格校验 #rrggbb，缺省回落默认，旧配置自动补齐），随主题输出 `--dshcp-row-*` 变量；类别色避开红、绿、琥珀；状态色单独定义，因为宿主绿色令牌在浅色主题下对白底只有 2.3:1；对白色与 #1e1e1e 页面均 ≥ 4.5:1，由 `tests/settings.test.mjs` 核验 |

自定义颜色在「实时预览」下方的「自定义动作行颜色」高级区编辑：与代码色板共用浅色／深色切换，取色器 + 完整 #RRGGBB（失焦校验，非法恢复原值），五个代表类别与状态示例在开关开启后实时反映草稿，关闭时保持宿主灰阶；低对比度（对当前预览背景 < 4.5:1）只提醒不禁止保存，「恢复行颜色默认」同时恢复两个主题。行颜色不属于预设：选择预设、导入导出都保留，不会把预设标成 custom。内置默认色经测试核验 ≥ 4.5:1，自定义色不保证。

颜色只是辅助线索：图标形状和动作文字才是主要信息，色觉差异下仍可分辨。着色规则只在开关开启时注入；状态词区间在开关关闭、卸载时撤销。设置页开关在选择预设时保持不变。

### 3.4 显示平滑

可选效果（默认关闭，配置键 `displaySmooth`）：保留宿主 `assistant-step` 组件及其 Markdown、代码块和交互，只在外层包装一个显示控制器。网络分块先登记为完整文字，再按每帧字符预算逐步写入现有 Text 节点；运行中速度随积压自适应，回合结束后有界排空，避免最后一段突然发布。

| 约束 | 做法 |
| --- | --- |
| 默认与降级 | 默认关闭时不替换宿主组件；缺少 slots/React 时不启用。系统「减少动态效果」开启时保持宿主即时显示 |
| 作用范围 | 仅 `data.status=running` 的助手回复及其收尾队列；已结束的历史消息不播放，不接管独立工具行。思考区（`data-variant="think"`、`data-markdown-variant="compact"`、`data-streaming`）由 `think-ink` 刷入节奏，平滑不截断同一 Text 节点：彩虹着色按原文偏移量定位，截断会让区间越界、文字成片消失 |
| 进入会话 | 引擎挂载时把回复已有内容整体登记为已显示，只有之后真正到达的文字才进入揭示队列；避免切回会话时重播旧正文并带动视口 |
| 格式与结构 | 宿主先交出代码块、引用、列表、表格、标题等块级结构而正文尚未揭示时，给该块加 `data-dshcp-smooth-hold`，由 CSS 只隐藏绘制；每帧按「块内是否已有可见文字」统一核对并撤下，不依赖该块是否轮到揭示队列（长思考区会占满帧预算）。标记不是宿主属性，不改变 DOM 归属与布局参与 |
| 文字与节点 | 按 Unicode 码点揭示；保留 Text 节点身份、React 组件和事件处理。自身写入按「写入前值／写入后值」精确配对，不靠实时值判断归属；同一批多条 `characterData` 记录按节点聚合，只采信该批结束时的宿主真实值；非追加修改保留共同前缀，宿主清空或改空白时丢弃该节点缓冲 |
| 结构重排 | 宿主成形内联元素或更换块类型时会把同一段正文换成新节点。被移除的节点先把「已显示到哪」记入有界退役池，新节点首次登记时与其中已显示文字对齐：完整重合或属于已显示片段的部分直接视为已显示，只有真正新增的文字进入揭示队列；尚未揭示完就被重排时保持当前进度继续展开，不回到开头 |
| 滚动跟随 | 文字与滚动共用 RAF，帧时间最多计 32ms。滚动所有权优先归宿主：会话根带 `data-chat-following-tail` 时插件完全不写 `scrollTop`，只同步位置；宿主不跟随时才用阻尼补位，单帧位移最多 8px，且底部变化超过逐字增长量时直接让位。缺少 `data-conversation-scroll` 时仍逐帧揭示，只是不跟随 |
| 阅读控制 | 仅在原本接近底部时跟随；向上滚轮会记录明确的用户意图，拖动或离开底部同样停止抢滚，只有真正回到底部才恢复 |
| 生命周期 | 设置关闭、减少动态效果或插件卸载会断开 observer/RAF/滚动监听、撤下全部 `data-dshcp-smooth-hold` 并恢复完整文字；每次重新启用新建包装组件，避免复用已销毁引擎的实例 |

实现位于 `src/display-smooth.js`。它属于可选的显示调度功能，与彩虹刷色不同，会暂时让 DOM 可见文字少于宿主已收到的完整文字；选择、复制和辅助技术看到的是当前已揭示内容。

## 4. 设置数据

浏览器 key 为 `dsh-code-pill.settings.v1`；配置 `version: 1`。
保存范围是当前浏览器、当前 origin，不是账户同步，也不是主机 Profile 配置。
保存失败保留草稿并显示错误，不声称已保存。无效的已有配置回落默认并提示。
跨窗口 storage 事件更新当前渲染，不强行覆盖另一个页面正在编辑的草稿。

代码外观的保存／取消／恢复默认操作栏在表单顶部使用 `position: sticky; top: 0`，相对宿主设置的滚动区域吸附，不使用脱离表单的底部 fixed 浮条。操作栏保留正常布局占位、使用宿主实色背景和局部层级，窄屏换行；仍须显式保存，滚动或改开关不隐式应用到聊天。

| 字段 | 含义 / 范围 |
| --- | --- |
| preset | amber/readable/cool/editor/contrast/minimal/custom |
| syntax | 行内语法着色布尔开关 |
| marker | off/label/icon/both |
| toolPath | 聊天文件路径胶囊布尔开关，默认开启 |
| thinkRainbow | 思考文字彩虹刷入布尔开关，默认关闭 |
| rowTint | 折叠动作行着色布尔开关，默认关闭 |
| displaySmooth | 回复文字逐帧揭示与底部平滑跟随布尔开关，默认关闭 |
| rowColors | 行着色的 15 个颜色：`light`/`dark` 各含 12 个类别色与 ok/warn/err 状态色，可部分覆盖，缺省为内置色板 |
| fontScale | 0.8–1.1，相对正文 em |
| radius | 0–10px |
| padding | 水平 0–0.6em |
| bgOpacity | 0–0.2 |
| blockTheme | host/preset |
| light、dark | 各含 plain/kwc/kwd/str/com/num/bg/badgeBg/badgeText |

默认保留琥珀色与语言徽章，字号 0.94em、圆角 4px、水平内边距 0.25em。
代码块默认 host：这是可组合扩展，不能默认夺走其他主题插件的代码块配色。
选择 preset 时，按当前主题生成 `--shiki-*` 变量；返回 host 会移除插件的变量覆盖。

JSON 导入必须通过配置版本、枚举、数值范围、颜色格式与未知字段校验。
不接受任意 CSS、远程图片地址、脚本或主题代码；导入只进入草稿。
导出为配置 JSON 文本，不包含聊天内容、凭据或账户数据。

## 5. 六套配对预设与审计

- amber：琥珀经典，延续签名色。
- readable：柔和阅读，中性基调。
- cool：冷调清晰，青蓝基调。
- editor：编辑器经典，熟悉的蓝/绿/暖色语法信号。
- contrast：高对比，更强的文字明暗差。
- minimal：素雅简约，中性灰默认文字与克制的语法色；几何默认更紧凑（圆角 3px、水平内边距 0.2em、底色强度 0.025），语法着色开启、语言文字标记与字号 0.94× 沿用默认，不隐藏任何功能。

每套均分别设计 light/dark，非简单颜色反转。
预设选择替换色板、语法／标记／代码块外观与排版草稿；`toolPath`、`sentenceFallback`、`thinkRainbow`、`rowTint`、`displaySmooth` 与 `rowColors` 是独立行为配置，选择预设时保留。修改任何外观参数标记 custom。

内置色板需按默认排版通过审计：六个文字角色对页面背景与合成 pill 背景 ≥4.5:1，徽章文字对徽章底色 ≥4.5:1。
页面审计背景为白色与 `#1e1e1e`，不能据此宣称对所有宿主主题都合规。
自定义色板只提示，不禁止保存；审计提醒基于当前预览背景与当前底色强度。
色盲模拟为辅助设计检查，不等于医学验证或所有视觉障碍下都能分辨的保证。
数值以 `node scripts/color-audit.mjs` 的当前输出为准，不在本文复制第二份色板表。

## 6. 渲染与生命周期

MutationObserver 监听 childList 与 characterData，受影响的 code 入 Set，RAF 合并处理。
宿主不存在已核实的稳定聊天 selector 时保留 body fallback，但 pending 为空不安排 RAF。
处理时重新核验 code 的资格，排除 pre/a/button、内含按钮/链接/SVG 与设置预览区域。

快照包含文本、首节点身份和子节点数。子节点变化使快照失效，避免同文字替换 Text 后旧 Range 空掉但跳过更新。
迁入排除区域、脱离 DOM 时清除 class、data 与 Range；迁出或重新插入后重新建立。
配置变化更新样式、清除旧 Range 并重新排队；关闭 syntax 保留 pill 与可选文件标记。
卸载清理 slot 注册、store 订阅/storage 事件、observer、RAF、样式、Highlight 与装饰属性。

句子级降级（`sentenceFallback`，默认开启）处理宿主 Markdown 解析把成对反引号连同周围正文并进同一个 code span 的消息：检测命中后只加 `data-dshcp-sentence` 标记，文字经普通级联恢复正文颜色与正文字体（压过本插件自己的胶囊 `!important` 规则），跳过 token 化与徽章，胶囊底色保留。不修改宿主子节点；`::highlight` 伪元素作用在文字区间上，不受元素级 color 影响。检测是启发式：片段含词字符且无句读、尾巴有足够的散文词；双反引号定界的合法代码无法逐字符区分，会被一并降级（只影响颜色/字体），设置开关可整项关闭。

无 Highlight API：pill + 文件标记，不染 token。非单文本节点：安全退化为 plain。
高对比 forced-colors 由系统接管色彩；不强制保留自定义 RGB。

路径渲染优先以聊天流内的消息边界（`data-chat-flow-kind`）为 owner，回退到聊天流或独立工具行，保存 owner → 已装饰目标的映射。嵌套边界只拥有归属于自己的目标。
文本、子节点及相关语义属性变化将 owner 入队，RAF 先完成整批旧归属清理，再统一应用新装饰，避免跨容器移动互相撤销。稳定目标按路径、种类与标记模式差量写入；失效、移出聊天、断开连接和卸载时撤销装饰。观察器区分宿主与插件自身的 class 写入，不监听插件装饰 data，避免自触发循环。工具失败／停止摘要保留宿主状态色。
只修改 class/data，保留宿主子节点、点击处理、焦点边框和阴影。

思考新词刷入与路径管线共用观察器：新增词的范围在同一微任务内登记，不推迟宿主文本显示；后续仅由一个有界定时器推进淡出档位，无活跃词时停止调度。无关工作区列表文本不进入动画队列。开关关闭、减少动态效果、卸载时清除定时器、Highlight、标记与样式。

显示平滑通过 `conversation.chat.node` 的既有 `assistant-step` 条目包装宿主组件，不注册第二个回复视图。配置关闭时恢复原组件，并主动停止仍挂载的引擎；每个引擎拥有自己的文字 observer、ResizeObserver、RAF、退役池、块级保持标记与端口事件清理。退役池只保存本引擎移除过的文字及其已显示长度，节点被移除时入池、新节点首次登记时按已显示前缀继承，避免流式 Markdown 重排把整段重播一遍。滚动不在插件自己的所有权里：宿主声明跟随尾部时插件不写滚动位置，仅在其不跟随时补齐帧间增长。默认管线不创建这些资源。

## 7. 设置页集成

复用宿主 React 和 `@deepseek-ai/dsh-client-ui-primitives` 的 Button、Switch、Input。
通过 `ctx.slots.inject('settings.section', ...)` 等待扩展入口，由 slot 生命周期拥有注册与注销。
没有 slots 或缺少 UI 模块时，只禁用设置页面，聊天渲染继续。
不引入运行时 React 副本；React/ReactDOM 开发依赖只用于浏览器测试。

颜色输入提供 color picker 与完整 #RRGGBB 文本；文本失焦校验，非法输入恢复原值并提示。
预设卡片使用当前主题的真实胶囊样式展示示例，而非只展示色点。实时预览包含中文段落、文件名、声明、字符串、命令、代码块，以及五个代表动作类别和三个状态示例；动作行着色关闭时预览保持宿主灰阶，不伪装成已生效。代码颜色与 15 项动作行颜色分别收纳在按需展开的高级区。
两个 Tab 共用标题、宽度与存储位置说明，并明确区分代码外观的显式保存和字体的即时应用。字体高级槽位默认只显示字体栈，完整分类／搜索选择器按需展开；清除按钮明确覆盖全部字体与高级配置，CSS 复制提供成功或失败反馈。
宿主代码块预览为示意，不假称独立测试页已经复现宿主完整 Shiki 高亮器。

## 8. 验证入口

- `node tests/tokenizer.test.mjs`：分类、区间、防误伤、文件/命令检测。
- `node tests/settings.test.mjs`：预设、严格配置、CSS、序列化与审计。
- `node tests/client-smoke.test.mjs`：模块加载、body-null 降级与生命周期。
- `node tests/browser-render.test.mjs`：真实 Chromium 颜色、徽章、主题与卸载。
- `node tests/dynamic-render.test.mjs`：流式节点替换、区域迁移、配置更新与降级。
- `node tests/settings-browser.test.mjs`：真实 React 草稿、保存、预设保留全部行为开关、灰阶／着色预览、折叠高级区、字体即时设置、导入、窄屏与清理；宿主控件是结构测试替身，非宿主整体截图验证。
- `node tests/tool-path.test.mjs`：宿主工具行路径胶囊、徽章模式、开关与清理；测试页复刻宿主的行标记，不是宿主整页截图验证。
- `node tests/think-ink.test.mjs`：思考文字彩虹刷入的像素采样、流式增量、StaticRange 不折叠、历史/结算不重播、减少动态效果、开关与卸载；测试页复刻宿主思考行的 DOM 契约，不是宿主整页截图验证。
- `node tests/row-tint.test.mjs`：折叠动作行着色的类别色、状态色、完成状态词、悬停、动态更新、开关与卸载；并核对开启前后宿主 DOM 逐字节一致；测试页复刻宿主 DisclosureRow 结构，不是宿主整页截图验证。
- `node tests/display-smooth.test.mjs`：真实 React/Chromium 中验证默认关闭、分块逐帧揭示、8px 跟随上限、结束排空、手动阅读、开关/卸载恢复与减少动态效果，块级结构不得先于文字出现、进入会话不重播既有正文、滚动所有权（宿主跟随时插件零滚动写入，宿主让出时由插件受 8px 约束补位），以及思考区与代码块共存时思考文字不被平滑截断；使用宿主条目和滚动端口结构替身，不是生产宿主整页验收。
- `node scripts/color-audit.mjs`：六套默认预设配对主题审计。

源码修改后运行 build 更新 lib/client.js。构建不安装，不更新 Profile，不执行 Git 发布。
