Skip to content

Commit e0b1600

Browse files
committed
feat(profile): 聚合环境工具缺失提示为单条输出
- 将 Profile 启动时分散的工具缺失提示收敛为一条聚合提示 - 引入轻量元数据表定义关键工具的平台支持和包管理器映射 - 按平台优先级选择包管理器:Windows(scoop>winget>choco)、macOS(brew)、Linux(brew>apt) - 当检测到 starship、zoxide、fnm 等工具缺失时,统一输出缺失工具列表和一行安装命令 - 保持“只提示不自动执行”的行为边界,不改变现有工具初始化顺序 - 添加对应的单元测试覆盖包管理器优先级、命令生成和跳过逻辑
1 parent cfbb78f commit e0b1600

4 files changed

Lines changed: 488 additions & 32 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
date: 2026-03-14
3+
topic: environment-install-hint
4+
---
5+
6+
# 环境工具安装提示聚合
7+
8+
## What We're Building
9+
10+
将 Profile 启动时分散输出的工具缺失提示收敛为一条聚合提示。在 `Initialize-Environment` 检测到 `starship``zoxide``fnm` 等工具缺失后,不再逐项输出多段安装说明,而是在遍历结束后统一告诉用户当前缺失了哪些工具,并给出一条可由用户手动执行的安装命令。
11+
12+
这次调整只改变提示体验,不引入自动安装,也不改变现有工具初始化顺序。目标是减少启动噪音,让用户在一次输出中就能看到完整的下一步操作。
13+
14+
## Why This Approach
15+
16+
讨论过三种方向:继续保留现有 `switch` 结构但延后输出、引入轻量元数据表做聚合、以及直接从 `apps-config.json` 推导安装命令。最终选择轻量元数据表方案,因为它能同时解决输出分散和维护分散两个问题。
17+
18+
相比之下,继续沿用 `switch` 只能修补展示方式,后续新增工具仍会继续堆分支;直接依赖 `apps-config.json` 虽然更“统一”,但会让 Profile 启动路径耦合到安装器配置,复杂度偏高,不符合当前需求规模。
19+
20+
## Key Decisions
21+
22+
- 保持“只提示,不自动执行”:安装动作仍由用户手动触发,避免 Profile 启动产生副作用。
23+
- 将缺失提示集中为一句话:避免同一次启动里出现多段重复的安装建议。
24+
- 安装命令只包含当前实际缺失的工具:不重复安装已存在工具。
25+
- 包管理器按平台自动选择:Windows 优先 `scoop`,其次 `winget`,最后 `choco`;macOS 使用 `brew`;Linux 优先 `brew`,其次 `apt`,其他包管理器暂不处理。
26+
- 推荐实现为“工具元数据表 + 缺失项收集 + 循环结束后统一输出”:在可维护性和改动规模之间取得平衡。
27+
- 当前讨论聚焦 PowerShell/Windows 启动体验:实现时可先按现有平台结构落地,再决定是否将同一聚合模式扩展到其他平台。
28+
29+
## Resolved Questions
30+
31+
- Linux 和 macOS 的包管理器规则需要单独定义,不能直接沿用 Windows 逻辑。
32+
- Linux 目前只覆盖 `brew``apt`,其余包管理器先不纳入本次范围,避免把简单提示逻辑扩成大而全映射表。
33+
34+
## Open Questions
35+
36+
- 暂无。当前方案已足够进入 planning 或直接实施。
37+
38+
## Next Steps
39+
40+
-> `/ce:plan` 用于整理具体改动步骤
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
---
2+
title: feat: consolidate profile install hints
3+
type: feat
4+
status: completed
5+
date: 2026-03-14
6+
origin: docs/brainstorms/2026-03-14-environment-install-hint-brainstorm.md
7+
---
8+
9+
# feat: consolidate profile install hints
10+
11+
## Overview
12+
13+
`profile/features/environment.ps1` 中按工具分散输出的缺失安装提示重构为一次性聚合输出,减少 Profile 启动噪音,同时保留“只提示、不自动执行”的行为边界。本计划直接承接 brainstorm 中已确认的决策:聚合提示、只包含当前缺失工具、按平台优先级选择包管理器、实现采用轻量元数据表而非直接耦合 `apps-config.json`(see brainstorm: `docs/brainstorms/2026-03-14-environment-install-hint-brainstorm.md`)。
14+
15+
这次改动聚焦提示体验与可维护性,不改变现有工具初始化顺序、缓存策略、懒加载行为,也不引入新的安装脚本执行路径。
16+
17+
## Problem Statement / Motivation
18+
19+
当前 `Initialize-Environment` 在工具缺失时直接在 `switch ($tool.Key)` 中输出多段平台特定文案,导致几个问题:
20+
21+
- 提示分散:同一次 shell 启动可能连续输出多段缺失说明,阅读成本高。
22+
- 维护分散:描述文案、平台分支、安装命令都散落在 `switch` 分支中,新增工具时容易继续扩散。
23+
- 跨平台逻辑不一致:Windows、macOS、Linux 的包管理器选择没有统一入口,Linux 新增 `brew > apt` 优先级后更需要集中处理。
24+
- 用户行动路径不够直接:当前输出是按工具分别提示,无法给出“一次性安装当前缺失工具”的单行命令。
25+
26+
仓库约束也要求这次重构保持保守:Profile 直接影响启动性能,不能为提示逻辑增加同步网络调用,也不能让提示失败影响 shell 启动(`CLAUDE.md:297`, `CLAUDE.md:298`)。
27+
28+
## Proposed Solution
29+
30+
### 1. 抽出轻量提示元数据
31+
32+
`profile/features/environment.ps1` 中为运行时“可提示的关键工具”增加一个小型元数据表,至少包含:
33+
34+
- 工具名与展示名
35+
- 简短说明文案
36+
- 当前平台是否应参与提示
37+
- 各支持包管理器对应的包名或安装片段
38+
39+
这个表只服务于 Profile 启动提示,不直接复用 `profile/installer/apps-config.json`,避免把完整安装器配置与启动路径耦合在一起。`apps-config.json` 仍可作为命名参考来源,特别是 `starship``zoxide``fnm``scoop` / `brew` 下的现有配置(`profile/installer/apps-config.json:92`, `profile/installer/apps-config.json:158`, `profile/installer/apps-config.json:182`, `profile/installer/apps-config.json:517`, `profile/installer/apps-config.json:646`, `profile/installer/apps-config.json:689`)。
40+
41+
### 2. 将“即时输出”改为“先收集后统一输出”
42+
43+
保留当前工具探测主流程和初始化闭包结构(`profile/features/environment.ps1:192`, `profile/features/environment.ps1:203`),但将缺失工具分支从“立即 `Write-Host`”改为“记录当前缺失且应提示的工具”。循环结束后再统一:
44+
45+
- 拼接缺失工具列表
46+
- 解析当前平台的首选包管理器
47+
- 基于缺失工具生成一条安装命令
48+
- 输出一句聚合提示和一行命令
49+
50+
当前分散提示的 `switch ($tool.Key)` 区域就是本次主要收敛点(`profile/features/environment.ps1:295`)。
51+
52+
### 3. 统一包管理器选择规则
53+
54+
将包管理器选择封装为明确规则:
55+
56+
- Windows:`scoop > winget > choco`
57+
- macOS:`brew`
58+
- Linux:`brew > apt`
59+
60+
只在当前机器检测到对应包管理器时才生成命令。若当前平台没有受支持的包管理器,或者所选包管理器缺少某个工具的映射,则仍输出单句缺失提示,但不输出命令,也不报错。
61+
62+
### 4. 保持手动安装边界
63+
64+
提示只提供用户可复制执行的一行命令,例如:
65+
66+
```powershell
67+
scoop install starship fnm
68+
```
69+
70+
或:
71+
72+
```powershell
73+
brew install starship zoxide fnm
74+
```
75+
76+
Profile 本身不调用安装脚本、不触发包管理器命令,也不自动修复环境。
77+
78+
## Flow & Edge Cases
79+
80+
本次计划按以下用户流覆盖:
81+
82+
1. 无缺失工具:不输出安装提示。
83+
2. 存在一个或多个缺失工具,且有受支持包管理器:输出一条聚合说明 + 一行安装命令。
84+
3. 存在缺失工具,但无受支持包管理器:仅输出一条聚合说明,不输出命令。
85+
4. 用户通过 `-SkipTools``-SkipStarship``-SkipZoxide` 等显式跳过工具初始化时:这些被跳过的工具不应继续制造额外提示噪音。
86+
5. 当前平台不适用的工具:保持现有平台边界,不因为聚合逻辑而扩大提示范围。
87+
88+
默认假设:
89+
90+
- Linux 的 `apt` 命令采用人工执行场景友好的单行形式,例如 `sudo apt install <packages>`,不依赖额外交互脚本。
91+
- 若首选包管理器只覆盖部分缺失工具,则优先保证“单句缺失说明”可用,再决定是否仅为可映射工具生成命令;实现时应避免同一次启动再次退回到逐项提示。
92+
93+
## Technical Considerations
94+
95+
- 性能:聚合逻辑必须建立在现有批量 `Get-Command` 检测之上,不增加外部进程调用,也不引入同步网络访问。
96+
- 健壮性:提示辅助函数若出现异常,必须安全降级为“安静失败”或仅输出缺失工具名,不能阻塞 `Initialize-Environment` 正常完成。
97+
- 结构:建议引入小型辅助函数,例如“选择包管理器”“格式化聚合命令”“生成缺失提示文案”,避免继续扩张单个 `switch`
98+
- 可维护性:元数据表应只覆盖当前真正需要提示的工具,先服务现有需求,不一次性抽象成通用安装框架。
99+
- 一致性:生成的一行命令只包含“当前缺失”的工具,不能把已安装工具一并塞入命令。
100+
101+
## System-Wide Impact
102+
103+
- **Interaction graph**`Initialize-Environment` 在完成工具存在性检查后,新增一段“聚合提示收尾”逻辑;不会改变工具初始化、别名注册和 `z` 懒加载路径。
104+
- **Error propagation**:提示构建失败不得影响后续 `Set-AliasProfile``Write-ProfileModeDecisionSummary` 等收尾步骤。
105+
- **State lifecycle risks**:本次变更只影响当前会话控制台输出,不写磁盘、不改缓存、不改环境变量持久层。
106+
- **API surface parity**`profile/installer/installApp.ps1` 继续承担“完整安装”入口,Profile 运行时提示仅承担“发现缺失并给出手动命令”职责。
107+
- **Integration test scenarios**
108+
- Windows 下缺失单工具,且 `scoop` 可用时,输出单命令。
109+
- Linux 下 `brew` 不可用、`apt` 可用时,回退为 `apt` 命令。
110+
- 缺失工具存在,但没有任何支持的包管理器时,不应抛错。
111+
- Skip 标志存在时,不应出现与被跳过工具相关的噪音提示。
112+
113+
## Acceptance Criteria
114+
115+
- [x] `Initialize-Environment` 在同一次启动中最多输出一组聚合安装提示,不再按工具逐项输出编号列表。
116+
- [x] 聚合提示只包含当前实际缺失且在当前平台应提示的工具。
117+
- [x] 安装命令按平台优先级自动选择包管理器:Windows `scoop > winget > choco`,macOS `brew`,Linux `brew > apt`
118+
- [x] 生成的安装命令只包含当前缺失工具,不包含已安装工具。
119+
- [x] 当没有受支持的包管理器或缺少包映射时,Profile 仍能正常启动,并退化为单句提示而不是报错或逐项刷屏。
120+
- [x] 保持“只提示,不自动执行”;运行时不调用 `installApp.ps1`,不调用包管理器安装命令。
121+
- [x] 添加或更新 Pester 测试,覆盖包管理器优先级、缺失工具聚合、无命令回退、Skip 标志抑制提示等场景。
122+
- [x] 根目录 `pnpm qa` 通过。
123+
124+
## Success Metrics
125+
126+
- 缺失工具场景下,启动输出从多段分散提示收敛为最多两行高信号输出。
127+
- 后续新增提示工具时,只需在元数据表和极少量辅助逻辑中补充信息,而不是继续扩张 `switch` 分支。
128+
- 现有 Profile 加载能力无回归,尤其是启动成功率和基本性能不退化。
129+
130+
## Dependencies & Risks
131+
132+
- 风险:提示元数据与 `apps-config.json` 中的包名可能长期漂移。
133+
缓解:把元数据表范围控制在少量关键工具,并在注释中标明 `apps-config.json` 为命名参考源。
134+
135+
- 风险:Linux 的 `apt` 映射当前不在现有安装清单中,需要本次自行定义最小支持集。
136+
缓解:只覆盖当前明确需要的工具,不扩展到所有包管理器。
137+
138+
- 风险:若不处理 Skip 标志,聚合后仍可能在“用户主动禁用工具初始化”的场景下输出不必要噪音。
139+
缓解:把 Skip 场景纳入 acceptance criteria 和测试。
140+
141+
- 风险:Profile 测试目前更偏模式与性能,新增提示逻辑若无专门测试,后续容易回归。
142+
缓解:为环境提示逻辑补充专门的单元测试,可选择新增测试文件,或在 `tests/ProfileMode.Tests.ps1` 基础上扩展。
143+
144+
## Sources & References
145+
146+
- **Origin brainstorm:** `docs/brainstorms/2026-03-14-environment-install-hint-brainstorm.md`
147+
- 延续的关键决策:聚合提示、只提示不执行、命令只覆盖当前缺失工具、按平台选择包管理器、Linux 仅支持 `brew > apt`
148+
- **Current implementation:** `profile/features/environment.ps1:192`, `profile/features/environment.ps1:203`, `profile/features/environment.ps1:295`, `profile/features/environment.ps1:314`
149+
- **Installer config reference:** `profile/installer/apps-config.json:92`, `profile/installer/apps-config.json:158`, `profile/installer/apps-config.json:182`, `profile/installer/apps-config.json:517`, `profile/installer/apps-config.json:646`, `profile/installer/apps-config.json:689`
150+
- **Repository constraints:** `CLAUDE.md:297`, `CLAUDE.md:298`
151+
- **Existing profile tests:** `tests/ProfileMode.Tests.ps1`, `tests/ProfileInstallHints.Tests.ps1`

0 commit comments

Comments
 (0)