Skip to content

Commit 072215d

Browse files
committed
2 parents 25194d2 + 8bed430 commit 072215d

33 files changed

Lines changed: 1500 additions & 650 deletions

‎.trellis/spec/infra/linux-install-pipeline.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pwsh linux/99verifyInstall.ps1 -Preset Core|Full [-Step <id[]>] [-OutputFormat T
4242
- `config/install/linux-packages.psd1` 是 apt/pacman 系统包真源;`apps-config.json` 是 Linuxbrew CLI 真源。
4343
- pacman 需要刷新索引时使用单次 `-Syu --needed` 完成同步升级与安装,不允许 `-Sy` 后分离执行 `-S` 形成部分升级。
4444
- 03 组合发行版、brew、npm、pnpm、pip、go target,事务与 Auto Restore 由共享引擎和根编排器负责。
45-
- 04 只调用 `shell/deploy.sh`;交互式 shell 的 Linuxbrew PATH 由 `~/.bashrc.d/` 下 `homebrew.sh` 片段从已知 prefix 恢复,不直接追加 rc。登录 profile(bash `~/.profile`、zsh `~/.zprofile`)的 brew+fnm 环境由 04/shell deploy 的受管块负责(marker 包裹、幂等原位整段替换、写前时间戳 `.bak`、支持 dry-run,块内先 brew 后 fnm),01 不写 profile;流水线子进程由 `Initialize-LinuxBrewEnvironment` 与 ProfileTools 在组件判定前主动恢复。三层分别覆盖交互、登录与非交互场景。
45+
- 04 只调用 `shell/deploy.sh`;`~/.profile.d` 承载 login 与 interactive 共用的 Homebrew、package source、fnm、Node、Bun 与 pnpm 基础环境,login profile 与 rc 只维护受管 loader。Bash login target 按 `.bash_profile`、`.bash_login`、`.profile` 优先级选择,Zsh 使用 `.zprofile`;rc 仅在交互会话继续加载 `~/.bashrc.d`。所有 marker 块支持目标迁移、幂等替换、写前时间戳 `.bak` 和 dry-run;01 不写 profile。流水线子进程由 `Initialize-LinuxBrewEnvironment` 与 ProfileTools 在组件判定前主动恢复环境。
4646
- 05 选择 `Linux + core + cli`;08 选择 `Linux + cli + terminal-extras`,不安装 GUI。Delta 与 Tealdeer 只属于 Full `terminal-extras`,Core 明确排除。
4747
- 06 Auto 在 WSL 和无桌面环境选择 Server,并以内部 Skipped 退出 0;Desktop 使用发行版字体包和 `fc-cache`。
4848
- 07 复用共享 `ProfileTools.psm1`,Linux 只追加系统包、Docker 和 WSL 客体配置。
@@ -78,7 +78,7 @@ pwsh linux/99verifyInstall.ps1 -Preset Core|Full [-Step <id[]>] [-OutputFormat T
7878

7979
### 6. Tests Required
8080

81-
- Vitest:Stage 0 shallow clone、China/Auto Blocked、01/02 dry-run、01 不写 login profile、03 参数透传、04 临时 HOME、04 登录非交互 shell(`bash -lc`)brew/fnm/node/pnpm 可见、Homebrew shell fragment、deploy.sh 登录 profile 受管块(写入/幂等整段替换/时间戳备份/dry-run/bash-zsh 分派/marker 外内容保留)。
81+
- Vitest:Stage 0 shallow clone、China/Auto Blocked、01/02 dry-run、01 不写 login profile、03 参数透传、04 临时 HOME、04 login/interactive loader 经 `profile.d` 恢复 brew/fnm/node/pnpm、Bash profile 优先级与迁移、双目录同步、legacy rc loader、损坏 marker、备份/dry-run/幂等及 marker 外内容保留。
8282
- Pester:Ubuntu/Debian/WSL/Arch/ARM 平台模型,apt/pacman 分派,05/08 标签边界(Core 排除、Full 包含 Delta/Tealdeer),06 环境选择,07 WhatIf,WSL config 幂等/备份,Docker Preview。
8383
- Pester:99 单文档 JSON、精确步骤、未知步骤、清单名称来源、ARM Blocked 与 WSL systemd 状态。
8484
- 回归:macOS 07 公共 Profile Tools 抽取后保持原测试通过。

‎.trellis/spec/infra/package-sources.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
### 1. Scope / Trigger
88

9-
- Trigger: 修改 `config/network/package-sources*`、`scripts/pwsh/misc/Switch-Mirrors.ps1`、`scripts/pwsh/misc/package-sources/**`、`Invoke-PackageSourceBootstrap.ps1`、`scripts/bash/package-source-bootstrap.sh` 或 `shell/shared.d/package-sources.sh`。
9+
- Trigger: 修改 `config/network/package-sources*`、`scripts/pwsh/misc/Switch-Mirrors.ps1`、`scripts/pwsh/misc/package-sources/**`、`Invoke-PackageSourceBootstrap.ps1`、`scripts/bash/package-source-bootstrap.sh` 或 `shell/profile.d/05-package-sources.sh`。
1010
- Scope: macOS、Windows、Linux/WSL 安装链的 source 计划、应用、补应用、状态与恢复;字体、CLI、Profile 等叶子安装脚本不拥有镜像 URL。
1111
- Design intent: 官方网络正常时零写入;需要国内镜像时集中应用,并且只恢复本仓库实际修改的资源。
1212

@@ -60,14 +60,14 @@ powershell.exe -NoProfile -File ./scripts/pwsh/misc/Invoke-PackageSourceBootstra
6060
- `npm`、`pnpm`、`pip`、`go` 使用 chsrc command adapter;`debian`、`ubuntu`、`arch` 使用系统文件 snapshot;Docker 使用仓库自有 JSON adapter。
6161
- `nix` 使用 system adapter(`NixAdapter.psm1`)事务化修改 `/etc/nix/nix.conf` 的 `substituters`/`trusted-public-keys`(USTC → cache.nixos.org),并重启 nix-daemon;测试根用 `POWERSHELL_SCRIPTS_SYSTEM_SOURCE_ROOT`。`winget` Stage 1、`uv`、Cargo 在可靠结构化恢复实现前仍返回 Unsupported。
6262
- Windows Stage 0 只使用 `Microsoft.WinGet.Client` 结构化 cmdlets,首次 snapshot 不得被 China 重跑覆盖,成功 Restore 后删除 snapshot。
63-
- `shell/shared.d/package-sources.sh` 只允许 Homebrew/rustup 已知变量和 HTTPS 值,不能 `eval`、`source` 或导出任意变量名。
63+
- `shell/profile.d/05-package-sources.sh` 只允许 Homebrew/rustup 已知变量和 HTTPS 值,不能 `eval`、`source` 或导出任意变量名;加载结束后不得遗留辅助函数。
6464
- 新机顺序固定为:package manager -> PowerShell 7/chsrc bootstrap -> Stage 1 sources -> CLI/fonts/profile。macOS 物理编号为 `02 pwsh`、`03 sources`,避免 source 引擎依赖自身尚未安装的运行时。
6565
- 未实现 Linux 原生 Stage 0 系统源 adapter 时,PowerShell 7/chsrc 前的 China/Auto 必须返回 Blocked,不能静默回退 Direct。
6666
- 默认 QA 仅使用临时 HOME、伪命令和 fixture;真实 China/Auto Apply 必须获得单独明确批准。
6767
- PackageSources Pester 只保留参数、JSON/退出码、`-WhatIf` 和 legacy Docker 的少量 CLI 子进程合同;事务、drift、orphan、Auto 和 adapter 行为直接调用 `Invoke-PackageSourceAction`。
6868
- Stage 1 根安装编排器只能依赖稳定的 `Results[*].Rollback`;source 叶子可选提供顶层 `Rollback`,缺失时不得在严格模式下直接取属性或把成功步骤误报为 JSON 解析失败。
6969
- 进程内测试默认将 `PackageSources`/`DockerAdapter` 内的 `Invoke-WebRequest` Mock 为失败;需要探活的用例必须显式覆盖并断言调用。
70-
- Linux Pester 容器的 `/tmp` 为 `noexec`;Bash 伪命令必须放到仓库内 `tests/.tmp-executables/` 的唯一临时目录,并在 `AfterAll` 清理。状态、HOME 和配置 fixture 仍放在 `$TestDrive`。
70+
- Pester 的状态、HOME、配置与可执行 fixture 统一使用 `$TestDrive` 隔离;不得在仓库内创建共享临时可执行目录,避免宿主与容器以不同用户写入后产生权限冲突。Linux 容器验证必须实际执行伪命令,确保测试临时文件系统允许执行。
7171
- 统一 Pester 配置只将 `Remove-Item:ProgressAction` 默认为 `SilentlyContinue`,避免 PowerShell 7.5 的 `Removed x of y files` TestDrive 清理进度干扰断言查看;不得全局禁用 `$ProgressPreference` 或丢弃 stdout。
7272

7373
### 4. Validation & Error Matrix

‎.trellis/spec/shell-shared/package/comment-conventions.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
本规范适用于以下仍在维护的 Shell 文件:
66

77
- `shell/deploy.sh`
8+
- `shell/profile.d/*.sh`
89
- `shell/shared.d/*.sh`
910
- `shell/bash.d/*.sh`
1011
- `shell/zsh.d/*.zsh`
@@ -20,8 +21,8 @@ shebang 保持原样且位于第一行;无 shebang 时从首行开始使用等
2021
```sh
2122
#!/bin/bash
2223
# ======================================================================
23-
# 文件:node.sh
24-
# 作用:初始化 Node.js 工具链与 package.json 脚本选择命令。
24+
# 文件:20-node.sh
25+
# 作用:为 login 与 interactive shell 初始化 Node.js 基础环境。
2526
# 兼容性:Bash / Zsh。
2627
# ======================================================================
2728
```
@@ -122,5 +123,5 @@ sessions=$(zellij list-sessions --no-formatting)
122123
- [ ] 复杂函数才使用完整分隔块,并按需补充输出、副作用、设计意图。
123124
- [ ] 字段、条目、中文标点符合统一合同。
124125
- [ ] 局部说明解释原因或约束,不复述语法或记录临时步骤。
125-
- [ ] `node.sh` 的两个 pnpm 条件块位于同一 `pnpm` 标题下。
126+
- [ ] `profile.d/20-node.sh` 的 Bun、fnm 与 pnpm 环境块职责清晰,临时变量均已清理。
126127
- [ ] 目标范围外文件没有变更。

‎.trellis/spec/shell-shared/package/index.md‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
# Shell shared.d Package Guidelines
1+
# Shell Startup Package Guidelines
22

3-
> 适用于 `shell/shared.d/*.sh` 下的 bash/zsh 双 shell 配置片段。
4-
> 这些片段经 `deploy.sh` 软链接到 `~/.bashrc.d/`,bash 与 zsh 都会 source。
3+
> 适用于 `shell/profile.d/*.sh` 基础环境层、`shell/shared.d/*.sh` 共享交互层、
4+
> `shell/{bash,zsh}.d/` 专属交互层及 `shell/deploy.sh` 受管加载器。
55
66
## Scope
77

8-
- 包路径:`shell/shared.d`
9-
- shell 专属片段(`zle`/`bind -x` 等)属于 `shell/{bash,zsh}.d/`,不在本包
10-
- 部署机制:`shell/deploy.sh`(glob `*.sh` 软链 + rc 加载器)
8+
- 包路径:`shell/`
9+
- 基础环境片段属于 `profile.d`;共享与专属交互行为分别属于 `shared.d`、`bash.d`、`zsh.d`
10+
- 部署机制:`shell/deploy.sh`(双目录同步、login/interactive marker 与目标迁移)
1111

1212
## Pre-Development Checklist
13+
- [ ] **启动层归属**:先阅读 [Shell 启动层级规范](./startup-layers.md),确认片段属于基础环境还是交互层,并遵守 loader、幂等与副作用合同。
1314

1415
- [ ] **双 shell 兼容**:禁用 `zle`/`bind -x`/`mapfile`/zsh-only 数组语法;只用 `[[ ]]`/`local`/`case`/`$(...)` 等两者都支持的特性。
1516
- [ ] **条件式守护**:工具替换用 `command -v X >/dev/null 2>&1`,无 `else` 即回退系统原命令(需求:"没安装时回退")。
1617
- [ ] **不破坏性 alias**:语法不兼容的工具(`find→fd`、`grep→rg`)**不做 alias**,当独立命令用——alias 会炸掉依赖原语法的脚本/命令。只有行为兼容的(`bat→cat`,管道自动退化)才 alias。
1718
- [ ] **加载顺序无关**:函数体内引用其它文件的函数时,确认函数定义为惰性(source 时只定义、调用时才解析),不依赖 `*.sh` glob 顺序。若必须保证顺序,用文件名前缀数字而非隐式依赖。
1819
- [ ] **解析 CLI 输出前先找机器可读选项**:优先使用 `--json`、`--porcelain`、`--format`/`-F`、`--short`、`--no-formatting` 等无样式/结构化输出;展示列可以丰富,但真实参数必须从稳定字段解析,避免 ANSI 颜色或展示文案混入真实参数。
19-
- [ ] **package source env**:修改 `package-sources.sh` 前阅读 [Package Source Transactions](../../infra/package-sources.md),只加载明确白名单的 HTTPS 变量。
20+
- [ ] **package source env**:修改 `profile.d/05-package-sources.sh` 前阅读 [Package Source Transactions](../../infra/package-sources.md),只加载明确白名单的 HTTPS 变量。
2021
- [ ] **加任何 init 前,先全局 grep**:`eval "$(zoxide init ...)"`、`eval "$(starship init ...)"` 等初始化代码极易跨文件重复。新增前先 `grep -r "<tool>" shell/` 确认未被别处初始化(见下方 Anti-pattern)。
2122
- [ ] **注释规范**:按 [活跃脚本注释规范](./comment-conventions.md) 组织文件头、配置章节、函数契约与局部说明。
2223

@@ -62,7 +63,7 @@
6263

6364
### 1. Scope / Trigger
6465

65-
- 在 `shell/shared.d` 新增或重命名环境变量模板时适用;目标是阻止占位值被部署并 source。
66+
- 在 `shell/shared.d` 新增或重命名交互式环境变量模板时适用;目标是阻止占位值被部署并 source。
6667

6768
### 2. Signatures
6869

@@ -72,7 +73,7 @@
7273

7374
### 3. Contracts
7475

75-
- `sync_dir "$SHARED_DIR" "sh" false` 只部署活动 `*.sh` 文件。
76+
- `sync_dir "$SHARED_DIR" "$INTERACTIVE_CONFIG_DIR" "sh" false` 只部署活动 `*.sh` 文件。
7677
- `*.example.sh` 与 `*.sample.sh` 即使误以 `.sh` 结尾,也必须被显式跳过。
7778
- 模板不得包含真实 secret;真实 `*.local.sh` 必须保持 gitignore。
7879

@@ -133,5 +134,4 @@ Correct: env.local.sh.example # 仅作为模板,不参与部署
133134

134135
## Out of Scope
135136

136-
- `bash.d`/`zsh.d` 的 widget/快捷键(zle/readline 专属)。
137137
- `scripts/bash/`(独立包,有自己的 vitest 测试规范,见 `bash-scripts` spec)。
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Shell 启动层级规范
2+
3+
## Scenario: login 与 interactive shell 共用基础环境
4+
5+
### 1. Scope / Trigger
6+
7+
- Trigger:修改 `shell/profile.d/**`、`shell/shared.d/**`、`shell/bash.d/**`、`shell/zsh.d/**`、`shell/deploy.sh` 或 Linux shell 部署与验证入口。
8+
- Scope:Bash 3.2+ 与 Zsh;login profile、interactive rc、片段同步、marker 迁移与启动副作用边界。
9+
- Design intent:基础环境只有一个实现,login 与 interactive 均可恢复工具链;alias、补全、prompt、网络探测和 TTY 行为只进入交互层。
10+
11+
### 2. Signatures
12+
13+
目录与部署目标:
14+
15+
```text
16+
shell/profile.d/*.sh -> ~/.profile.d/*.sh
17+
shell/shared.d/*.sh -> ~/.bashrc.d/*.sh
18+
shell/bash.d/*.sh -> ~/.bashrc.d/*.sh
19+
shell/zsh.d/*.zsh -> ~/.bashrc.d/*.sh
20+
```
21+
22+
受管入口:
23+
24+
```bash
25+
bash shell/deploy.sh [--dry-run] [--shell bash|zsh] [--exclude <pattern>]
26+
```
27+
28+
稳定 marker:
29+
30+
```text
31+
# >>> powershell-scripts login env >>>
32+
# <<< powershell-scripts login env <<<
33+
# >>> powershell-scripts interactive env >>>
34+
# <<< powershell-scripts interactive env <<<
35+
```
36+
37+
### 3. Contracts
38+
39+
- `profile.d` 是 login 与 interactive 共用的安静、幂等基础环境层;只允许环境变量、幂等 PATH 变更与受控工具环境生成。
40+
- `profile.d` 禁止 alias、补全、prompt、键位、交互函数、网络探测、后台进程和 stdout/stderr 输出;临时函数与变量必须在片段结束前清理。
41+
- `shared.d` 只放 Bash/Zsh 共享交互行为;`bash.d` 与 `zsh.d` 只放对应 shell 专属交互行为。交互片段 source 时不得无条件输出。
42+
- login loader 只 source `~/.profile.d/*.sh`。interactive loader 先 source `~/.profile.d/*.sh`,再仅在 `$-` 含 `i` 时 source `~/.bashrc.d/*.sh`;loader 不得 `return` 或 `exit`。
43+
- 写入用户 profile/rc 的受管块必须保持可直接阅读:只保留简短职责注释、顺序加载循环和交互守卫;解析、迁移、备份等实现细节留在 `deploy.sh`,不得泄漏进用户配置。
44+
- Bash login target 按 `.bash_profile`、`.bash_login`、`.profile` 选择第一个已存在文件;都不存在时创建 `.profile`。Zsh 固定使用 `.zprofile`。
45+
- 每次 Bash 部署从非活动候选删除精确 login marker block;目标变化时完成迁移,不保留双重入口。marker 外用户内容逐行保留。
46+
- 只有 start marker 时受管范围延伸到文件尾并由新 block 修复;孤立 end marker 视为用户内容,不删除。
47+
- 内容变化前为既有非空文件创建 `YYYY-MM-DD_HH-MM-SS.bak`;内容相同不写入、不备份。dry-run 只报告,不创建目录、文件、链接或备份。
48+
- `--exclude` 同时按源文件 basename 作用于 profile 与交互片段;模板 `*.example.sh`、`*.sample.sh` 永不部署。
49+
- `profile.d/20-node.sh` 非交互执行 `fnm env`,交互执行 `fnm env --use-on-cd`;生成或 eval 失败均安静降级,且仅在成功后记录当前会话模式。
50+
- Homebrew、package source、fnm、Bun 与 pnpm 环境分别由 `profile.d/05-package-sources.sh`、`10-homebrew.sh`、`20-node.sh` 单点拥有;不得在 loader 或交互片段复制。
51+
- `shell/shared.d/env.local.sh` 保持交互层与 PowerShell 解析合同,不进入 profile 层,不读取、记录或输出真实内容。
52+
53+
片段归属清单:
54+
55+
| 层 | 文件 | 归属依据 |
56+
|---|---|---|
57+
| 基础环境 | `profile.d/05-package-sources.sh`、`10-homebrew.sh`、`20-node.sh` | 安静恢复 package source、Homebrew、fnm、Bun 与 pnpm;login 必需 |
58+
| 共享交互 | `10-carapace.sh`、`90-atuin.sh`、`aliases.sh`、`modern-tools.sh`、`python.sh`、`tmux.sh`、`zellij.sh`、`bluetooth.sh`、`package-scripts.sh` | alias、补全或面向终端的交互命令 |
59+
| 共享交互 | `fzf-helpers.sh`、`fzf-preview.sh`、`browser-debug.sh`、`claude-profile.sh`、`selfhosted.sh`、`vscode.sh`、`ai.sh` | 交互函数、fzf 生命周期或宿主工具命令 |
60+
| 共享交互 | `env.local.sh`、`path.sh`、`java.sh`、`proxy.sh`、`git-delta.sh`、`zz-prompt.sh` | 私有配置桥接、交互 PATH/SDK hook、网络/TTY 探测或 prompt;不得提升到 login 层 |
61+
| Bash 交互 | `bash.d/fzf-history.sh`、`bash.d/shc-completion.sh` | Readline 与 Bash completion 专属 |
62+
| Zsh 交互 | `zsh.d/00-compinit.zsh`、`10-network.zsh`、`20-shc-completion.zsh`、`30-bun-completion.zsh`、`95-zsh-autosuggestions.zsh`、`99-k8s.zsh`、`fzf-history.zsh`、`zzz-zsh-syntax-highlighting.zsh` | compinit、ZLE、Zsh completion 与插件专属 |
63+
64+
### 4. Validation & Error Matrix
65+
66+
| Condition | Expected Behavior |
67+
|---|---|
68+
| Bash 三个候选均不存在 | 创建 `~/.profile` 并写入 login block |
69+
| `.bash_profile`、`.bash_login`、`.profile` 同时存在 | 只在 `.bash_profile` 保留 login block |
70+
| 当前 target 从 `.profile` 变为 `.bash_profile` | 写入新 target,并从旧 target 精确删除受管块 |
71+
| 只有 start marker | 替换从 start marker 到文件尾,恢复完整成对 marker |
72+
| 只有 end marker | 保留该行,并另行写入完整 block |
73+
| legacy rc 单行 loader 存在 | 删除旧 loader 段并写入成对 interactive block |
74+
| 非交互 login | 加载 profile 层;fnm 无 `--use-on-cd`;无 alias、补全、prompt、代理探测 |
75+
| interactive shell | 先加载 profile 层,再加载交互层;fnm 使用 `--use-on-cd` |
76+
| `fnm env` 生成或 eval 失败 | 安静继续后续片段,不记录成功模式 |
77+
| 重复部署或重复 source | loader、PATH 与成功初始化均不重复;无额外备份 |
78+
| dry-run | 日志描述目录、同步、目标、迁移与备份动作;文件系统零变化 |
79+
80+
### 5. Good / Base / Bad Cases
81+
82+
- Good:`bash -lc` 经有效 login profile 加载 `~/.profile.d`,恢复 Homebrew、fnm、Node 与 pnpm,但没有 `pscripts` alias。
83+
- Good:交互 Bash 经 rc block 重复 source `~/.profile.d` 后加载 `~/.bashrc.d`,获得 `--use-on-cd` 与交互命令,PATH 无重复。
84+
- Base:`env.local.sh`、`path.sh`、`java.sh`、`ai.sh`、`proxy.sh` 保留在交互层;它们分别依赖本机私有配置、交互函数/hook 或网络/TTY 行为。
85+
- Bad:login profile source 整个 `~/.bashrc.d`,或在 `deploy.sh` 内联复制 Homebrew/fnm 初始化。
86+
- Bad:为旧 `shared.d/homebrew.sh`、`package-sources.sh`、`node.sh` 保留转发 shim。
87+
88+
### 6. Tests Required
89+
90+
- Vitest 行为测试覆盖双目录同步、模板排除、stale symlink、Bash profile 优先级与迁移、Zsh target、legacy rc loader、损坏 marker、用户内容保留、dry-run、备份与幂等。
91+
- 使用 fake `fnm` 记录 argv:非交互 login 断言无 `--use-on-cd`,interactive Bash/Zsh 断言包含该参数;同时观察 Node/pnpm 可发现。
92+
- profile 片段重复 source 后断言 PATH 无重复,且不遗留 package source 辅助函数。
93+
- 非交互 login 断言不存在交互 alias/函数、补全、prompt 与代理自动探测。
94+
- 保留 `tests/ProfileLocalShellEnv.Tests.ps1`,证明 PowerShell 继续解析既有 `env.local.sh` 合同。
95+
- 语法门禁至少覆盖 `bash -n shell/deploy.sh`、Bash source smoke;环境提供 Zsh 时补充 Zsh source smoke。
96+
97+
### 7. Wrong vs Correct
98+
99+
#### Wrong
100+
101+
```bash
102+
# login profile 直接加载所有交互片段,并复制工具初始化。
103+
for rc in "$HOME/.bashrc.d/"*.sh; do source "$rc"; done
104+
eval "$(fnm env)"
105+
```
106+
107+
#### Correct
108+
109+
```bash
110+
# login 与 interactive shell 共用的基础环境,按文件名顺序加载。
111+
for config in "$HOME/.profile.d/"*.sh; do
112+
[ -r "$config" ] && . "$config"
113+
done
114+
unset config
115+
```
116+
117+
理由:启动入口只负责编排目录,环境实现集中在 `profile.d`,从而让 login 与 interactive 行为一致,又不把交互副作用带入非交互进程。
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"file": ".trellis/spec/guides/code-reuse-thinking-guide.md", "reason": "检查重复初始化与迁移遗漏"}
2+
{"file": ".trellis/spec/bash-scripts/package/index.md", "reason": "检查 Bash 测试范围与质量门禁"}

0 commit comments

Comments
 (0)