首页
/ WinUtil 编码代理作业规范深度解析:AGENTS.md 如何约束构建、测试与文档工作流

WinUtil 编码代理作业规范深度解析:AGENTS.md 如何约束构建、测试与文档工作流

2026-09-03 16:08:01作者:咎竹峻Karen

AGENTS.md 是 WinUtil 仓库为编码代理(Coding Agent)编写的"可插入式"作业指令:它以 13 个章节规定了哪些文件是生成产物不可手改、哪些命令是构建与验证的唯一入口、npm 工具为何必须在 Docker 中运行,以及改动前后必须完成的验证闭环。读完本篇,你将掌握这套"规则即文档"的仓库治理方式:它如何与 SPEC.md 项目契约分工、如何用 Compile.ps1 生成的单脚本产物替代模块式开发,以及 Pester 5.8.0、PowerShell Script Analyzer、Astro 文档站三条验证链路的具体执行方法。

文档定位:AGENTS.md 与 SPEC.md 的契约分工

AGENTS.md 开篇明确了自己的角色与边界:

Drop-in operating instructions for coding agents. Read this file before every task. Working code only. Finish the job. Plausibility is not correctness.

它声明 SPEC.md 是"项目契约"(描述 WinUtil 是什么、如何构建、如何运行),而 AGENTS.md 本身只覆盖"如何在这个仓库上工作"。这一分工在仓库中有直接的物证:

  • CLAUDE.md 全文只有一行 @AGENTS.md,即 Claude 系工具进入仓库后自动加载本文件;
  • GEMINI.md 同样只指示"先读仓库根目录的 AGENTS.md";
  • SPEC.md 第 5 行明确写着"AGENTS.md 指向这里获取事实,并单独覆盖代理在仓库中的行为"。

这种"单入口 + 契约分置"的结构意味着:所有行为规则只维护在 AGENTS.md 一处,各 AI 工具的配置入口文件只是指针,避免多处规则漂移。

八条不可协商规则(Non-Negotiables)

AGENTS.md 第 0 章列出 8 条在冲突时压倒其他一切规则的硬性条款,每条都能在仓库中找到对应证据:

  1. 不要直接编辑 winutil.ps1。它是生成产物——Compile.ps1 按固定顺序拼接 scripts/start.ps1functions/ 下全部函数文件、config/*.json 转换出的 $sync.configs 内嵌配置、xaml/inputXML.xamltools/autounattend.xmlscripts/main.ps1,最终写出根目录的 winutil.ps1。改源码、跑编译才是正确路径。
  2. 不要提交 winutil.ps1。仓库根 .gitignore 中显式列出了 winutil.ps1binary/,发布产物由 GitHub Actions 统一生成。
  3. 绝不触碰 docs/src/content/docs/code-reference/tweaks/docs/src/content/docs/code-reference/features/。这两个目录由 tools/devdocs-generator.ps1config/tweaks.jsonconfig/feature.json 及对应 PowerShell 函数文件自动生成;要改内容就改 JSON 或函数文件。而 code-reference/ 下的手写页面(如 architecture.mdx)不在生成范围内,可以直接编辑。
  4. 绝不虚构。不凭空捏造文件路径、函数名、命令输出、测试结果、commit 哈希或 API 行为——先读文件或跑命令。
  5. 前提错误时先指出再行动
  6. 真正有歧义时停下:如果两种理解会产生实质性不同的 diff,先问再改。
  7. 只碰任务要求的部分:不顺手重构、不做大面积格式化、不做无关清理。
  8. 说"完成"之前先验证:看起来合理的 diff 不等于证明。

前 3 条本质上是在保护"单一脚本构建模型":由于最终产物是拼接结果,代码不能依赖运行时模块导入或源码相对路径的 dot-sourcing,任何手改生成物都会在下次编译时被静默覆盖。

关键命令:编译、测试、静态检查与文档站

AGENTS.md 第 1 章给出了项目全部关键命令,并附带了非显而易处的操作细节:

编译与运行

.\Compile.ps1            # 仅编译,生成根目录 winutil.ps1
.\Compile.ps1 -Run       # 编译并直接启动 GUI

对应 Compile.ps1-Run 开关:第 44-46 行在 Set-Content 写出生成脚本后,若带 -Run 则直接 .\Winutil.ps1 执行,用于手动 GUI 验证。

安装受支持的 Pester 版本(一次性)

Install-Module -Name Pester -RequiredVersion 5.8.0 -Repository PSGallery -Scope CurrentUser -Force -SkipPublisherCheck

文档特别解释了 -SkipPublisherCheck 的必要性:Windows 自带(inbox)Pester 3.4.0 是 catalog-signed,而 PowerShell Gallery 上的 Pester 5.8.0 是 Authenticode-signed,Install-Module 默认拒绝这种"降级签名类型"的升级,因此必须显式跳过发布者检查。同时强调该参数不会跳过下载完整性校验(仍是 HTTPS + NuGet 包哈希校验);-Repository PSGallery 则是显式锁定受信来源,而不是依赖机器上恰好注册了哪些仓库。

运行测试

Import-Module Pester -RequiredVersion 5.8.0 -Force
Invoke-Pester -Path 'pester/*.Tests.ps1' -Output Detailed -CI

-CI 参数会生成 testResults.xml 并在失败时返回非零退出码(对应 SPEC.md 中 GitHub Actions unittests.yaml 的行为)。第 13 章的项目经验再次强调:必须先导入 Pester 5.8.0 再运行测试,否则 Invoke-Pester 会解析到 Windows 自带的 3.4.0。测试套件本体位于 pester/ 目录,覆盖 appx、config、tweaks、runspace 生命周期等 30 余个测试文件。

静态分析

Invoke-ScriptAnalyzer -Path . -Settings .\lint\PSScriptAnalyser.ps1 -Recurse

项目设置文件 lint/PSScriptAnalyser.ps1 仅排除一条规则 PSAvoidUsingWriteHost。AGENTS.md 在此命令前埋了一个容易踩的坑:该设置文件"只排除规则,不排除文件",所以如果本地存在已编译的 winutil.ps1-Recurse 会把它一并 lint,产生一堆映射不到任何源码文件的行号噪音——运行前先删除本地生成的 winutil.ps1。第 13 章还补充了治理原则:优先修复可操作的源码警告,不要全局压制被接受的惯例性警告(复数命名、UI 辅助函数上的 ShouldProcess$global:sync、编译期跨文件误报等)。

文档站开发服务器与生产构建(必须走 Docker)

# 在 docs/ 目录下执行
docker compose up winutil-astro                                   # 开发服务器
docker compose run --rm winutil-astro npm run build               # 生产构建

迭代时优先使用"最窄但有用的验证",收尾前再跑完整的相关检查。

依赖安装与构建环境:npm 一律进容器

AGENTS.md 第 2 章是全文最具安全针对性的一节。鉴于 npm/pnpm/yarn 供应链投毒(恶意 postinstall/preinstall 脚本、窃密包)的持续风险,规则写得非常绝对:永不在宿主机上直接运行 npm/pnpm/yarn/npx

仓库中唯一的 npm 项目是 docs/(Astro + Starlight 文档站)。它的容器化配置在仓库中可以完整验证:

  • docs/Dockerfile:基于 node:22-bookworm-slimcorepack enable 后先拷贝 package*.jsonnpm install(利用层缓存),再以非 root 的 node 用户运行,暴露 4321 端口,默认命令 npm run dev -- --host 0.0.0.0
  • docs/docker-compose.yml:服务名 winutil-astro,端口绑定 127.0.0.1:4321:4321(仅本地可达),卷挂载 .: /app(宿主机编辑即时反映到容器,常规代码改动无需重建镜像),并声明了命名卷 astro_node_modules 映射到 /app/node_modulestmpfs 挂载 /app/.astro,环境变量 CHOKIDAR_USEPOLLING=true(轮询文件监听,规避 overlayfs inotify 问题)与 ASTRO_TELEMETRY_DISABLED=1

这一节还固化了几个容易出错的运维细节:

  1. 新增文档依赖:直接改 docs/package.json,然后 docker compose build winutil-astro 重建镜像并 docker compose down -v 丢弃 node_modules 卷——因为 Docker 只在命名卷首次创建时从镜像播种,普通 rebuild 会静默保留旧 node_modules
  2. Docker 不可用时的行为:给出当前操作系统的安装命令并等待确认,而不是"退而求其次"在宿主机上跑 npm;若只是守护进程没启动,告知用户而不是自行启动。
  3. 生命周期脚本审查:新依赖中的 postinstall/preinstall 脚本在安装前向用户摘要其作用。
  4. 秘密管理陷阱docs/.dockerignore 只影响 docker build 拷贝进镜像的内容,不影响 docker compose 的 bind mount——整个 docs/ 目录(包括任何 .env)对每个 dev/build/preview 命令都在容器内可见,所以"不要把真实密钥放在 docs/ 下任何位置"。
  5. 边界:这条 Docker 要求只针对 docs/;仓库其余部分是 PowerShell(Compile.ps1、Pester、Script Analyzer),直接在宿主机上运行。

真实源与编辑前检查清单

第 3 章规定:凡是影响编译后脚本行为的改动,只能落在 SPEC.md "Repository Layout" 描述的源文件上(functions/config/scripts/xaml/ 等),绝不落在 winutil.ps1;若行为变化需要编译产物变化,更新源文件后运行 .\Compile.ps1 仅用于验证生成

这一作用域只覆盖"编译脚本行为"。仓库元数据——AGENTS.mdSPEC.mdCLAUDE.md/GEMINI.md/.github/copilot-instructions.md.github/workflows/、根 .gitignore——在任务需要时直接编辑。

第 4 章的"编辑前"清单要求:

  • 动手前用一两句话陈述计划,非平凡工作要附带拟运行的验证方式;
  • 读要改的文件和调用它的文件;
  • 匹配既有模式,即使另一种"绿地设计"更干净;
  • 影响行为、兼容性或用户数据的假设要显式说出;
  • 两种方案存在实质权衡时,先命名权衡再选择。

这些规则与第 5 章编码指南中的命名契约呼应:按钮/动作接线遵循 SPEC.md 的 UI And Event Contract——XAML 元素命名为 WPFThingButton 就映射到 Invoke-WPFThingButton 函数,这与 functions/public/Invoke-WPFInstallInvoke-WPFOOSU 等文件的实际命名一致。

编码指南与运行时安全规则

第 5 章编码指南的核心条目(均指向 SPEC.md 的对应契约章节):

  • 优先"解决所述问题的最少代码",除非任务当下需要,不添加抽象、可配置性、钩子或"未来扩展性";
  • PowerShell 函数尽量保持在单个函数文件内,文件名与主函数名一致(functions/private/functions/public/ 的结构即如此);
  • 使用批准的 PowerShell 动词-名词命名,遵循既有的 WPF/WinUtil 命名约定;
  • 共享状态与 UI 引用统一使用 $sync——编译产物里 scripts/main.ps1 正是把 $sync.configs.applications 展开为 $sync.configs.applicationsHashtable 等哈希表供跨 runspace 共享;
  • 在后台 runspace 中工作时,通过 UI dispatcher 更新 WPF 控件(对应第 13 章中 Invoke-WPFUIThread 必须可无窗调用的经验);
  • 符合既有 schema 的配置驱动功能放在 JSON 中(config/*.json),而不是在 PowerShell 里硬编码列表;重命名配置键必须同步更新所有 preset、UI 引用、文档与代码路径;
  • 保留 tweak 的 undo/原始状态数据,让用户可以逆转变更;
  • 清理自己改动产生的孤儿代码;避免大面积纯格式化改动,尤其是 JSON、XAML、文档与生成产物。

第 6 章运行时安全规则将 WinUtil 定位为执行系统级 Windows 变更的工具:注册表、服务、AppX 移除、包管理器、Windows Update、ISO 与无人值守安装变更一律视为高危。具体守则包括:优先复用 WinGet/Chocolatey/注册表/服务/进度/UI 更新等既有辅助函数;tweak 在 schema 支持时保持可逆(记录原始值或原始状态);永不就地修改用户的原始 ISO,遵循既有的拷贝/挂载/导出模式;不在仓库文件中存储凭据、秘密或机器特定路径;长时/破坏性操作保留日志与用户反馈模式。

外科式改动与验证闭环

第 7 章"Surgical Changes"把最小 diff 原则展开为可检查的行为约束:不顺手改进相邻代码、注释、格式、import 或文档;不因"人已经在文件里了"而重构能跑的代码;不删除既有死代码(相关时在总结中提及即可);每一行改动都应可追溯到用户请求;改动开始向无关区域蔓延时,暂停并重新评估计划。

第 8 章验证矩阵按改动类型给出可检查的成功标准:

改动类型 必做验证
编译/构建相关 运行 .\Compile.ps1
GUI 行为 可行时运行 .\Compile.ps1 -Run 并手动验证受影响路径
配置变更 编译检查 + 相关 Pester 测试
函数变更 相关 Pester 测试,可行时新增/更新聚焦测试
纯文档 校对改动文件;除非涉及文档生成,跳过运行时测试

两条硬性纪律:读了命令输出才能说测试通过;验证失败时修复原因,而不是削弱测试。如果某项检查跑不了,必须精确说明为什么、剩余风险是什么。

生成文件与 Git 卫生

第 9 章规定:本地 winutil.ps1 的改动按"可丢弃的编译输出"对待;绝不暂存或提交 winutil.ps1binary/ 或任何被根 .gitignoredocs/.gitignore 忽略的内容——且要求"读那些文件而不是凭假设"(根 .gitignore 实际列出的还包括 testResults.xmlwinutil.exe.config 与系统文件)。docs/public/ 是被跟踪的静态资源源(favicon 等),不是生成产物。收尾前运行 git status --short,把自己的改动与用户既有改动分开;未被明确要求时不回滚用户改动。提交信息要求:短标题(72 字符内)+ 必要时解释"为什么"的正文;把改动拆成小而逻辑内聚的多个 commit,使每个 commit 的 diff 可作为一组相关变更被审阅。

文档预期与沟通风格

第 10 章文档预期把"行为变化"与"文档落点"绑定:

  • 用户可见行为变化 → 更新 docs/src/content/docs/guides/
  • 架构、构建流程、配置 schema 或贡献工作流变化 → 更新手写的 docs/src/content/docs/code-reference/architecture.mdx 等开发者文档,但绝不手改自动生成的 code-reference/tweaks/code-reference/features/ 子目录;
  • docs/astro.config.mjs 中的侧边栏条目必须与 docs/src/content/docs/ 下的实际页面 slug 保持同步;
  • README 的改动保持简短、高层级,详细用户与开发者文档一律放 docs/
  • SPEC.md 跟随项目/架构变化更新,AGENTS.md 跟随流程变化更新——两者各自单一职责。

第 11 章沟通风格要求:直接、简洁,答案/动作先行;不奉承、不客套、不假装确定;报告"改了什么、如何验证、什么没做";被要求 review 时以发现和文件/行号引用开头。第 12 章给出"何时问、何时直接做"的双向清单:两种合理解释且选择实质影响行为或触碰文件时、影响发布生成/迁移/高危 Windows 行为而用户未指定时、需要无权限的凭据或生产资源时、用户陈述目标与字面请求冲突时——先问;而任务平凡可逆、歧义可通过读代码或跑本地命令消解、或用户本会话已回答过时——直接做。

项目经验沉淀(Project Learnings)

第 13 章是这套规范最"活"的部分:每当用户纠正代理的做法,会话结束前就在这一节新增或收紧一条具体规则,并持续删减不再重要的条目。当前的经验列表浓缩了该项目大量实战踩坑:

  • 日志:WinUtil 运行时日志保持在带时间戳的 %LocalAppData%\winutil\logs\winutil_*.log 会话文件中,不另建根目录 winutil.log;当活动日志文件正被 Start-Transcript 持有时,不要对该文件调用 Add-Content(会记录终止错误诊断),改为写到宿主输出,让 transcript 把该行收进同一日志文件。
  • UI 生命周期Invoke-WPFUIThreadSet-WinUtilTweaksProgressIndicator 等 UI 辅助函数必须可在无窗口时安全调用——-Preset-Config 路径在表单创建之前、PresentationCore 加载之前就执行工作流。
  • 包管理日志:入队后台 runspace 工作之前记录包名与包管理器 ID,不依赖 runspace 宿主输出获取包标识;winget/Chocolatey 的进程启动保持简单,除非明确要求,不新增独立的 stdout/stderr 进程日志辅助。
  • Win11 Creator(ISO 工作流):每次新的 ISO 修改都从全新的 WinUtil_Win11ISO_* 临时目录开始,"已有工作检测"仅用于恢复/导出已修改介质;驱动注入的离线 WIM 维护保持"一次挂载、一次 /Add-Driver、一次提交",不做版本导出或无关 WIM 清理,导出 ISO 前拒绝损坏的元数据。
  • DNS:DHCP 重置时保留 cmdlet 重置,并显式把 IPv4 与 IPv6 的 DNS 来源都设为 DHCP。

小结:一套可审计的代理作业规范

AGENTS.md 的设计要点可以归纳为三层闭环:

  1. 事实层:SPEC.md 作为唯一项目契约,AGENTS.md 只引用不重复,CLAUDE.md/GEMINI.md/.github/copilot-instructions.md 全部收敛到同一入口;
  2. 执行层:每条规则都绑定一个可运行的命令或一个可读的文件(Compile.ps1 的拼接顺序、lint/PSScriptAnalyser.ps1 的规则排除、docs/Dockerfiledocs/docker-compose.yml 的卷布局、根 .gitignore 的忽略清单),规则因此可被机器和人同时审计;
  3. 演化层:第 13 章的 Project Learnings 把每次纠正固化为一条可删除的短期规则,使规范随项目经验滚动更新而不膨胀。

对贡献者而言,这份文件同时也是一份"仓库地图":读懂它,就理解了 WinUtil 为什么是"模块化源码 + 单脚本产物"的形态、验证链如何分三段(编译、Pester、静态分析)、以及文档站为何被隔离在 Docker 内独立构建。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384