Skip to content

Commit a5e11df

Browse files
committed
refactor(psutils): 抽取配置对象读取助手
1 parent b6faff8 commit a5e11df

21 files changed

Lines changed: 369 additions & 151 deletions

File tree

.trellis/spec/psutils/package/shared-config-resolver.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
- `Read-ConfigMarkdownFrontMatter -Path <string>`
2424
- Conversion helpers:
2525
- `ConvertTo-ConfigHashtable -InputObject <object>`
26+
- `Get-ConfigValue -Values <hashtable> -Name <string> [-DefaultValue <object>]`
2627
- `ConvertTo-ConfigKeyName -Name <string>`
2728
- `ConvertFrom-ConfigCliParameters -Parameters <hashtable> [-ExcludeKeys <string[]>]`
2829
- Scoped env:
@@ -37,6 +38,7 @@
3738
- `Resolve-DefaultEnvFiles -PrimaryBasePath <dir> -FallbackBasePath <dir>` only falls back when the primary directory has no default env file at all.
3839
- `CliParameters` converts explicit PowerShell parameters to snake_case keys and skips `$null`、empty strings and `ExcludeKeys`.
3940
- `MarkdownFrontMatter` returns parsed metadata plus `__content` for the Markdown body.
41+
- `Get-ConfigValue` performs shallow case-insensitive lookup only; it must not expand paths, environment variables, nested paths, or normalize key names.
4042
- Missing file sources return an empty table by default; `-ErrorOnMissing` changes that to `配置文件不存在: <path>`.
4143
- `Invoke-WithScopedEnvironment` must restore overwritten variables and remove newly created variables even when the script block throws.
4244
- `psutils/modules/config.psm1` must export public resolver functions and must not contain a second implementation of the parser.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# design: config helper extraction
2+
3+
## Scope
4+
5+
本任务只扩展 `psutils` 的 config 公共 API,并把 skills 安装器切换到公共 API。公共 API 只处理通用配置对象访问,不处理路径、环境变量、平台选择或安装计划。
6+
7+
## Public API
8+
9+
复用既有 `ConvertTo-ConfigHashtable`,补强其输入兼容性:
10+
11+
* `$null` -> 空 hashtable
12+
* `hashtable` -> 浅拷贝
13+
* `System.Collections.IDictionary` -> 遍历 keys 转成普通 hashtable
14+
* 其他对象 -> 遍历 `PSObject.Properties`
15+
16+
新增 `Get-ConfigValue`
17+
18+
* 入参:`Values``Name``DefaultValue`
19+
* `Values` 类型:`hashtable`
20+
* key 匹配:`OrdinalIgnoreCase`
21+
* 返回:命中值或默认值,命中时不改变 value 类型
22+
23+
## Data Flow
24+
25+
`Install-Skills.ps1` 已导入 `psutils/modules/process.psm1`。本任务保留现有 `Import-SkillsConfigModule`,让它导入 `psutils/modules/config.psm1`,并在脚本初始化阶段或首次读取配置前确保公共 helper 可用。
26+
27+
替换点:
28+
29+
* `ConvertTo-SkillsHashtable` -> `ConvertTo-ConfigHashtable`
30+
* `Get-SkillsConfigValue` -> `Get-ConfigValue`
31+
32+
## Compatibility
33+
34+
`Install-Skills.ps1` 当前本地 helper 支持 `System.Collections.IDictionary``psutils` 现有 `ConvertTo-ConfigHashtable` 只处理 hashtable 和普通对象。因此需要先补强公共 helper,再替换调用方。
35+
36+
`Get-ConfigValue` 的行为应与现有 skills helper 一致:仅 shallow lookup,不做 nested path,不做 key normalization,不修改 key 大小写。
37+
38+
## Rollback
39+
40+
若 downstream 行为异常,可恢复 `Install-Skills.ps1` 本地 helper,保留 `psutils` 新 helper;新 API 为向后兼容新增,不影响现有调用方。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# implement: config helper extraction
2+
3+
## Checklist
4+
5+
1. 更新 `psutils/src/config/convert.ps1`
6+
* 补强 `ConvertTo-ConfigHashtable``System.Collections.IDictionary` 的处理。
7+
* 新增 `Get-ConfigValue`
8+
* 为新增/更新公共函数保留中文 comment-based help。
9+
2. 更新 `psutils/modules/config.psm1`
10+
* 导出 `Get-ConfigValue`
11+
3. 更新 `psutils/psutils.psd1`
12+
*`FunctionsToExport` 中加入 `Get-ConfigValue`
13+
4. 更新 `psutils/tests/config.Tests.ps1`
14+
* 添加/补充 helper 用例。
15+
5. 更新 `ai/skills/Install-Skills.ps1`
16+
* 删除 `ConvertTo-SkillsHashtable``Get-SkillsConfigValue`
17+
* 确保在使用 helper 前导入 config 模块。
18+
* 将调用点替换为公共函数。
19+
6. 更新 `tests/SkillsInstaller.Tests.ps1`
20+
* 若导入时机改变导致测试需要调整,只做最小更新。
21+
7. 验证
22+
* `pnpm exec pwsh -NoProfile -File ./scripts/pwsh/devops/Invoke-PesterMode.ps1 -Mode serial -Path ./psutils/tests/config.Tests.ps1`
23+
* `pnpm exec pwsh -NoProfile -File ./scripts/pwsh/devops/Invoke-PesterMode.ps1 -Mode serial -Path ./tests/SkillsInstaller.Tests.ps1`
24+
* `pnpm qa`
25+
* `pnpm test:pwsh:all`
26+
27+
## Review Gate
28+
29+
确认本轮 diff 没有包含 path/env placeholder 实现,也没有把 skills 安装计划逻辑移入 `psutils`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# skills config helper extraction
2+
3+
## Goal
4+
5+
把多个 PowerShell 脚本重复实现的“配置对象转 hashtable”和“大小写不敏感读取配置值”收敛到 `psutils/modules/config.psm1`,先供 `ai/skills/Install-Skills.ps1` 使用。
6+
7+
## Requirements
8+
9+
* `psutils` 暴露稳定公共 helper,用于浅层配置对象转换与大小写不敏感键读取。
10+
* helper 必须保持通用配置语义,不包含 skills、ctx7、agent、GitHub release 等领域概念。
11+
* `ConvertTo-ConfigHashtable` 需要兼容 `hashtable``System.Collections.IDictionary``PSCustomObject``$null`
12+
* 新增读取函数应支持默认值,并在 key 命中时保留原始 value 类型。
13+
* `Install-Skills.ps1` 应移除本地 `ConvertTo-SkillsHashtable` / `Get-SkillsConfigValue`,改用 `psutils` 公共 helper。
14+
* 本轮不抽 `Resolve-SkillsPath` / `Resolve-SkillsEnvPlaceholder`;路径/env placeholder 留给 `skills-config-path-placeholder-extraction` 子任务。
15+
* 本轮不拆 `Install-Skills.ps1` 私有业务模块;模块拆分留给 `skills-installer-private-module-split` 子任务。
16+
17+
## Acceptance Criteria
18+
19+
* [ ] `psutils/modules/config.psm1` 导出通用 config helper,函数有中文 comment-based help、参数说明和返回值说明。
20+
* [ ] `psutils/tests/config.Tests.ps1` 覆盖 dictionary 转换、大小写不敏感读取、默认值、原始类型保留。
21+
* [ ] `Install-Skills.ps1` 改用公共 helper 后行为不变。
22+
* [ ] 不把 skills 安装器领域语义加入 `psutils`
23+
* [ ] 定向 config 测试、skills 安装器测试、`pnpm qa``pnpm test:pwsh:all` 通过。
24+
25+
## Out of Scope
26+
27+
* 配置路径解析、`~` 展开、`${VAR}` / `%VAR%` placeholder 展开。
28+
* GitHub CLI 安装器、rclone、start-container 的批量替换。
29+
* `Install-Skills.ps1` 业务模块拆分。
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"id": "05-20-skills-config-helper-extraction",
3+
"name": "05-20-skills-config-helper-extraction",
4+
"title": "skills config helper extraction",
5+
"description": "",
6+
"status": "in_progress",
7+
"dev_type": null,
8+
"scope": null,
9+
"package": null,
10+
"priority": "P2",
11+
"creator": "mudssky",
12+
"assignee": "mudssky",
13+
"createdAt": "2026-05-20",
14+
"completedAt": null,
15+
"branch": null,
16+
"base_branch": "master",
17+
"worktree_path": null,
18+
"commit": null,
19+
"pr_url": null,
20+
"subtasks": [],
21+
"children": [],
22+
"parent": "05-20-skills-installer-config",
23+
"relatedFiles": [],
24+
"notes": "",
25+
"meta": {}
26+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# skills config path placeholder extraction
2+
3+
## Goal
4+
5+
把多个脚本重复出现的配置路径解析和环境变量 placeholder 展开能力抽成通用基础设施,供后续 `Install-Skills.ps1`、GitHub CLI 安装器等脚本复用。
6+
7+
## Requirements
8+
9+
* 评估并设计通用 API,覆盖 `~`、相对 base path、`${VAR}``%VAR%` 这类配置路径展开场景。
10+
* API 必须只表达通用路径/env 解析语义,不包含 skills、GitHub release、rclone 等领域概念。
11+
* 缺失环境变量时必须有明确错误,避免路径静默落到错误目录。
12+
* 需要明确哪些脚本先接入,避免一次性批量改动过大。
13+
14+
## Acceptance Criteria
15+
16+
* [ ] 有独立 `design.md``implement.md` 描述 API、调用方迁移顺序和验证命令。
17+
* [ ] 通用 helper 有 Pester 测试覆盖 `~`、相对路径、`${VAR}`、缺失 env。
18+
* [ ] 首个调用方接入后行为不变。
19+
* [ ] 不和 config object helper 或 skills 私有模块拆分混在同一提交。
20+
21+
## Out of Scope
22+
23+
* 安装计划、agent 目录、ctx7 检测。
24+
* 大规模替换所有历史脚本。

0 commit comments

Comments
 (0)