ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

get-shit-done 中 /gsd:resume-work 的 zsh NOMATCH 检查点丢失修复:从裸 glob 链到 find 的健壮化实践

get-shit-done 中 /gsd:resume-work 的 zsh NOMATCH 检查点丢失修复:从裸 glob 链到 find 的健壮化实践 get-shit-done 中 /gsd:resume-work 的 zsh NOMATCH 检查点丢失修复:从裸 glob 链到 find 的健壮化实践【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done这篇文章基于 get-shit-done 仓库的 changeset 记录 .changeset/3689-resume-glob-nomatch-fix.md(对应 issue #3689 / PR #3693)展开:它会解释为什么/gsd:resume-work在 macOS 默认的 zsh 环境下会静默丢失.planning/.continue-here*.md续接检查点,根因是 zsh 默认NOMATCH选项对裸 glob 链式ls的词展开期中断行为,以及项目如何改用find命令并配套真实 shell 行为回归测试来彻底消除这一隐患。读完后,你将掌握 shell 元字符展开时机差异(bash vs zsh)这一类隐蔽 bug 的诊断方法,以及为由 Agent 执行的嵌入式 bash 工作流编写可移植、可验证命令片段的最佳实践。背景:.continue-here检查点是什么,谁在写、谁在读get-shit-done(GSD)是一套面向 Claude Code 的元提示与规格驱动开发系统,其会话续接能力围绕.planning/目录下的工件构建。其中.continue-here*.md文件是计划执行到一半时写下的续接检查点,用于让下一次会话知道我们停在哪里。写入方是/gsd:pause-work工作流。从 pause-work 工作流 的路径探测规则看,检查点的落盘位置取决于暂停时的上下文类型:阶段(phase)工作 →.planning/phases/XX-name/.continue-here.mdSpike 工作 →.planning/spikes/SPIKE-NNN/.continue-here.md(目录不存在时创建)Sketch 工作 →.planning/sketches/.continue-here.md讨论(deliberation)工作 →.planning/deliberations/.continue-here.md研究工作或无上下文 →.planning/.continue-here.md检查点的格式由 continue-here 模板 定义,包含 YAML frontmatter(phase、task、total_tasks、status、last_updated)和current_state、completed_work、remaining_work、decisions_made、blockers、context、next_action等语义区块,模板明确要求具体到足以让一个全新的 Claude 实例立即理解,并在恢复后被删除(一次性工件)。读取方则是/gsd:resume-work命令——它的前置声明见 命令定义,该命令路由到 resume-project 工作流,其中check_incomplete_work步骤负责探测四类未完成工作:结构化交接文件HANDOFF.json、.continue-here检查点、没有 SUMMARY 的 PLAN(执行未完成的计划)、以及被中断的 agent。3689 修的就是最后这条探测链:在 zsh 默认配置下,它会把顶层检查点吞掉。Bug 剖析:zsh 的 NOMATCH 如何在词展开期中断整条命令问题场景很具体:一个新项目布局下,.planning/目录已经存在,里面有一个带后缀的检查点文件(例如.planning/.continue-here-AT-1234.md),但spikes、sketches、deliberations等子目录尚未创建。这正是刚开工、还没有 spike/sketch的常见状态。修复前的check_incomplete_work步骤使用了一条链式ls,串联约六个裸 glob 参数来一次性探测所有可能的检查点位置。从回归测试的文本不变量断言可以确认,旧模式中包含.planning/spikes/*/.continue-here*.md这样的裸 glob(测试用正则ls\s\.planning\/spikes\/\*\/\.continue-here来检测残留)。可以将其还原为如下形态(按测试断言与 changeset 描述重建):# 旧实现(重建示意):一条 ls 串联多个裸 glob ls .planning/spikes/*/.continue-here*.md \ .planning/sketches/.continue-here*.md \ .planning/deliberations/.continue-here*.md \ .planning/.continue-here*.md 2/dev/null || true在bash 默认行为下,不匹配的 glob 保持字面量,ls报 No such file or directory(被2/dev/null吞掉),匹配到的路径仍会正常输出,整条命令可用。但在zsh 的默认NOMATCH选项下(macOS 的默认 shell 正是 zsh),行为完全不同:zsh 在执行命令之前进行 glob 词展开;第一个无法匹配的 glob 直接触发NOMATCH错误,整条命令在词展开阶段就被中止,连ls都来不及执行;关键点在于中止发生在第一个未匹配模式处——排在它后面的所有模式(包括真正持有有效检查点的.planning/.continue-here*.md)都从未被求值;命令末尾的2/dev/null || true只抑制ls自身的 stderr 和退出码,对 shell 在执行前的中止完全无效。结果就是:在新项目布局下,/gsd:resume-work探测不到任何检查点,且没有任何报错——续接上下文被静默丢弃,用户回来了却被告知项目没有未完成工作。这是一个典型的只在默认 shell 是 zsh 的机器上复现的环境相关 bug。修复:用两条 find 取代裸 glob 链changeset 给出的修复方案是:放弃依赖 shell 做 glob 展开,改为两条find调用。当前 resume-project 工作流 的check_incomplete_work步骤中的实际实现如下(完整继承原文,含注释):# Check for structured handoff (preferred — machine-readable) cat .planning/HANDOFF.json 2/dev/null || true # Check for continue-here files (phase non-phase legacy fallback). # Use find rather than a chained ls of bare globs: under zshs default # NOMATCH option (macOS default shell), a single non-matching glob aborts # the entire command during word-expansion — silently dropping every # pattern after the first miss, including .planning/.continue-here*.md. # find does not use shell glob expansion and tolerates absent # directories on both bash and zsh. find .planning -maxdepth 3 -name .continue-here*.md -print 2/dev/null || true find . . -maxdepth 1 -name .continue-here*.md -print 2/dev/null || true(注:第二行按仓库原文为find . -maxdepth 1 -name .continue-here*.md -print 2/dev/null || true,此处照录原文。)这个方案的安全性来自find的两个特性,恰好针对 zshNOMATCH的两个失败点:不做 shell glob 展开:-name .continue-here*.md中的通配符由find自行匹配,shell 从不参与通配展开,因此不存在第一个未匹配模式中止整条命令的问题;容忍不存在的目录:find missing-dir -maxdepth N -name PATTERN -print 2/dev/null在目录缺失时(如新项目的.planning/spikes不存在)只是不产出结果,两条find均以|| true收尾,在 bash 和 zsh 下都能干净地以退出码 0 结束。两条命令的分工也值得注意:命令作用范围覆盖的检查点位置find .planning -maxdepth 3 -name .continue-here*.md.planning/内深度 3phase 目录、spikes/SPIKE-NNN/、sketches/、deliberations/下的检查点find . -maxdepth 1 -name .continue-here*.md仓库顶层深度 1遗留布局中放在项目根目录的顶层 handoff 文件(changeset 特别指出旧链式ls因第一个未匹配模式中止而吞掉的正是这个模式)工作流对探测结果的消费逻辑不变:.continue-here文件命中即判定Found mid-plan checkpoint,读取文件恢复具体上下文,且其优先级低于HANDOFF.json(结构化交接)和被中断 agent、高于PLAN 无 SUMMARY的兜底。完整的路由规则见 resume-project.md 的determine_next_action步骤。回归测试:用真实 shell 做行为验证,而不是源码字符串断言这次修复配套了一个设计很有代表性的回归测试 tests/bug-3689-resume-glob-nomatch.test.cjs。它的文件头注释开宗明义:Workflow.md文件是被 Claude Code 作为嵌入式 bash 执行的运行时契约。断言 resume-project.md 的文本、以及嵌入式片段在真实 shell 下的行为,是对工作流本身的行为测试,不是源码 grep 表演。测试覆盖四组场景:zsh-o nomatch下列出.planning/.continue-here-AT-1234.md:构造新项目布局(.planning/存在、有带后缀检查点、无spikes/sketches/deliberations子目录),在工作流嵌入的find片段原文下用spawnSync(zsh, [-o, nomatch, -c, FIND_SNIPPET])实际执行,断言退出码 0 且 stdout 匹配.planning/.continue-here-AT-1234.md;bash 默认行为:同一布局、同一命令,断言检查点同样被列出;空工作区:.planning/完全不存在、无任何检查点时,zsh-o nomatch下命令退出码 0、stdout 为空、无报错(纯 greenfield 场景不会误报);工作流文本不变量:直接读取 resume-project.md 的全文,断言其不再包含ls .planning/spikes/*/.continue-here的脆弱模式,且包含find .planning -maxdepth 3 -name .continue-here*.md的新模式——防止未来有人在编辑工作流文档时把裸 glob 链改回去。测试中FIND_SNIPPET常量被显式标注与 resume-project.md 的check_incomplete_work步骤保持同步,即测试与工作流文档形成双向约束:行为测试守护运行时语义,文本不变量守护文档不漂移。这种对 Agent 执行的 markdown 工作流做回归的思路,是 GSD 仓库测试体系的特色之一(该测试文件位于 tests/ 目录,与 300 余个bug-*.test.cjs回归测试并列)。可移植性经验:给嵌入式 shell 片段的三条实践准则这个 fix 体量很小,但它暴露的问题在Agent 驱动的工作流里嵌入 shell 命令这一类系统中具有普遍性。结合本仓库的实现,可以提炼出三条可复用的准则:避免依赖 shell 的裸 glob 展开来枚举可能缺失的路径。ls a/*.md b/*.md c/*.md这种写法在 bash 下碰巧可用(未匹配项变字面量、靠 stderr 抑制和退出码兜底),在 zsh 默认NOMATCH下则第一个未匹配项即中止整条命令。需要跨 shell 枚举可能存在也可能不存在的路径时,优先find root -maxdepth N -name PATTERN -print 2/dev/null || true——模式匹配交给find,存在性交给退出码兜底;区分抑制命令输出与抑制 shell 展开期错误。2/dev/null || true只能兜住命令执行阶段的 stderr 和非零退出;对发生在命令执行之前(词展开阶段)的 shell 级中止无效。写跨 shell 片段时,应假定读者机器上的默认 shell 可能是 zsh 的默认配置,而不是 bash 的宽松默认;用真实 shell 的行为测试守护文档型工作流。GSD 的工作流是.md文件,其内嵌 bash 由 Agent 实际执行,传统的单元分层在这里不适用。bug-3689 测试 的做法——spawnSync真实zsh/bash执行片段原文 对工作流文档做文本不变量断言——提供了一个可直接借鉴的模板:前者锁住语义,后者锁住没人把坏模式改回来。小结/gsd:resume-work在 zsh 默认NOMATCH下丢失.continue-here检查点的根因,是链式裸 globls在词展开期被首个未匹配模式中止,且该中止发生在ls执行前、不受2/dev/null || true约束;修复方案是用两条find命令(深度分别为 3 与 1,-name .continue-here*.md)取代裸 glob 链,使检查点探测在 bash 与 zsh 下、目录存在与缺失的场景中行为一致;回归测试 tests/bug-3689-resume-glob-nomatch.test.cjs 通过真实 shell 执行片段原文加文档文本不变量双重守护了这一修复。相关实现分布在 resume-project 工作流、continue-here 模板、pause-work 工作流 与 gsd:resume-work 命令 中,changeset 原文见 .changeset/3689-resume-glob-nomatch-fix.md。【免费下载链接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by TÂCHES.项目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表