SuperAPI AI 工具集

batch-script-progress

编程与开发

查看项目

更新于 10-16 12:04

技能介绍

Batch Script Progress

让生成的批处理脚本在运行时可被观测,同时不改变其处理契约。将启动、周期性进度、逐项失败和最终汇总输出与结果流、退出状态一起设计。仅靠一个进度条库并不能建立这一契约。

  1. 固定现有契约

编辑前先阅读脚本、调用方和附近的测试。识别:

输入单位、总数已知或未知,以及枚举是否惰性。

现有 stdout 格式及其消费者、运行时版本,以及交互式与重定向执行的区别。

出错继续或快速失败策略、重试规则、跳过规则、事务边界和取消行为。

现有退出码以及调用方视为成功的情况。

保留这些决定。不要仅为添加进度输出而添加重试、并行、依赖或新的失败策略。如果部分失败当前返回零,就如实报告部分结果,同时保持该退出契约。如果契约缺失或自相矛盾,就询问会改变行为的决策;不要默默替它做决定。

  1. 在实现前定义输出契约

选择一套小而稳定的词汇和字段,在合适处复用仓库已有的 logger:

启动:操作名、总数或明确未知、初始计数器。在昂贵的枚举之前发出;发现过程本身可能也需要进度。

进度:已处理、成功、失败、跳过、总数或未知,以及已用时间。仅在有用时添加经过脱敏的当前项标识符。

逐项失败:安全标识符、失败类别或脱敏原因,以及是否继续处理。在观察到时立即发出,独立于正常进度间隔。

汇总:已完成、部分完成、失败或已取消;最终计数器;已用时间;若可得则给出已知未处理数量;以及现有契约要求的退出状态。

对于到达终止结果的项,定义已处理 = 成功 + 失败 + 跳过。将进行中和未开始的项分开。每项只计一次;重试尝试不是额外的已处理项。不要在必需的提交、写入或确认之前把某项标记为成功。如果事务回滚,应报告已回滚的工作,而不是声称持久成功。

当总数未知时,报告计数,而不捏造百分比、ETA 或剩余数量。不要仅为计数而物化一个流。对于零项,发出启动和汇总,计数为零;绝不要除以零。

  1. 选择输出流与节奏

将 stdout 保留给既定的机器可读结果、管道对象或协议。把进度和诊断放在单独的通道上;对独立 CLI 脚本而言,stderr 是可移植的默认选择。仅 stderr 输出并不意味着失败:调用方必须使用约定的退出码和结果契约。在改变输出之前,先核实那些把任何 stderr 都当作失败的调用方。如果 stdout 已保留且 stderr 不兼容,仅在调用方已支持时使用现有的兼容 logger 或 sink。不要把进度移到 stdout 或语义已改变的其他流。如果不存在兼容通道,就停下来询问输出契约是否可改,或报告无法安全添加进度。

使用有界的节奏,例如每配置数量的项或每经过一个时间间隔,而不是无条件记录每一项。无论该节奏如何,都要发出启动、失败和汇总。单独保留必需的逐项审计记录。避免无界的内存失败列表和重复的堆栈跟踪。格式化前对凭据、查询参数、个人数据和敏感路径进行脱敏;默认不要转储原始异常或整条输入记录。

对间隔和时长使用单调时间。确保输出被刷新或排空,以便通知在退出前到达。在重定向下使用纯换行分隔的记录;仅对合适的 TTY 启用终端重写或颜色。保持各语言间日志字段含义一致,而不必强求确切格式或库相同。

循环末尾的时间检查无法在某项阻塞时发出。对于长耗时项,使用现有的进度回调、阶段通知,或在运行时允许时安全集成的心跳。Node.js 定时器无法穿过同步事件循环阻塞运行;PowerShell 进度显示不是持久日志。如果无法在不改变执行语义的情况下添加项内进度,就在当前阶段开始前发出它,并披露通知缺口。不要承诺实现无法兑现的周期性心跳。

  1. 实施最小兼容改动

阅读所选运行时的语言说明和安全示例。这些示例是可执行的输出契约探针,不是生产处理器;应让它们的发射器和记账适配现有代码,而不是照抄其失败策略。

将报告与处理决策分开。在并发代码中,通过协调器串行化报告,并统计已完成的结果,而非提交数。在已处理的失败或取消时,尝试一次最终汇总并保留原始结果;汇总写入错误不得替换原始处理异常。不要把取消吞作普通的逐项失败。对于宿主管理的取消(包括 PowerShell 宿主停止),保留现有宿主行为;不要把停止异常转换为逐项失败,也不要在宿主终止后承诺最终汇总。在适用处使用 finally 做清理,但当优雅取消属于契约时,要验证受支持宿主中的实际取消路径。

不要强行让成功终止来交付缓冲输出。在 Node.js 中,优先设置 process.exitCode 并排空写入,而不是立即 process.exit()。在 PowerShell 中尊重现有宿主/库语义:可复用函数不应退出其调用方。强制终止、进程崩溃和输出管道破裂可能阻止最终报告;不要声称相反。

  1. 在报告完成前验证

阅读验证用例,然后用无害的测试夹具对改动后的脚本运行聚焦测试。分别捕获 stdout 和 stderr,并检查真实退出状态。验证启动/进度顺序、单调计数器、脱敏失败、受支持路径上恰好一次汇总,以及结果内容和处理策略不变。

通过在子进程仍在运行时读取其输出来证明活性,而不是检查退出后收集的输出。当两者都被支持时,检查终端和重定向行为。在进度事件后受控暂停是有用的确定性探针:接收事件,确认子进程尚未退出,然后释放它。将此类门控保留在无害的测试夹具或测试框架中;不要仅为让测试通过而在正常生产处理中添加 stdin 等待、sleep 或取消钩子。优先使用现有回调或可注入的处理边界。如果不存在安全的确定性接缝,仅用无害输入测试真实路径,或将活性报告为未验证。看门狗可以使测试失败;它不得制造成功结果。

捆绑的跨语言验证器会运行 Python、PowerShell 和 Node.js 探针,覆盖正常、部分失败、保留部分失败且退出为零、空、总数未知、快速失败、模拟取消和实时输出等用例。它只检查探针;它不证明任意生成的脚本或自动技能选择可行。

从该技能文件夹使用 Node.js 20 或更高版本运行:

node tests/verify-examples.mjs

它还需要 Python 3.9 或更高版本以及 PowerShell 5.1 或更高版本。见语言说明中的可执行覆盖项。缺少运行时会算作失败,而不是被静默跳过的覆盖。

交付物

返回改动后的脚本、其输出/退出契约,以及聚焦的验证结果。区分已执行的测试与仅检查及未执行的用例。不要仅因脚本打印了进度条或技能元数据通过验证,就称该脚本已验证。

坑点

记录前先计数可能使发现过程静默消耗整个流。

用 PowerShell Write-Output 写状态会向成功管道添加字符串。

仅在退出后测量缓冲输出无法证明进度可见性。

一条“已完成”的最终消息会掩盖部分失败,除非结果和计数器解释了它。

finally 并不保证强制终止后仍能报告。