
get-shit-done 工作流名称规范化与路径穿越防护CJS/SDK 双层校验一致性加固解析【免费下载链接】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-doneTÂCHES 出品的轻量级元提示词 / 上下文工程 / 规范驱动开发系统的一条Fixed变更集changeset关联 PR #3269展开深入剖析其中三项底层修复workstream工作流名称在 CJS 与 SDK 两层的统一校验与规范化、model_profile: inherit哨兵值的泄漏修复以及 SDK 侧writeActiveWorkstream对目标目录存在性的校验。读完本文你将掌握 workstream 名称命名的合法语法、路径穿越攻击的阻断机制、活动工作流指针的读写与自愈契约以及这些修复在源码中的真实落地位置。变更集定位一次包含三处修复的稳定性改动本仓库使用 changeset 管理发布说明.changeset目录下每个文件描述一次面向用户的变更。本文分析的.changeset/nimble-lynx-tumble.md内容如下--- type: Fixed pr: 3269 ---其正文共包含三个要点它们看似独立实则共同指向「多 workstream 并行的健壮性与安全性」这一主题Workstream 名称规范化CJS 与 SDK 两层现在对 workstream 名称做一致校验仅接受字母数字、连字符、下划线与点号例如v1.0并在两层同时阻断通过..序列进行的路径穿越。inherit哨兵修复model_profile: inherit哨兵不再作为字面模型 ID 泄漏到 session-runner 中。指针写入前校验SDK 的writeActiveWorkstream在写入指针前会确认目标 workstream 目录真实存在。背景知识workstream 与活动指针的目录模型要理解上述修复需先了解 GSD 的多 workstream 目录布局。从 workstream-utils.ts 可以看到不带 workstream 时规划目录为.planning带 workstream--ws name时规划目录被路由为.planning/workstreams/name/不同 workstream 拥有彼此隔离的计划、阶段状态与产物记录「当前活动 workstream」的指针文件位于.planning/active-workstream见 active-workstream-store.ts。由于 workstream 名称会被拼接到文件系统路径中posix.join(.planning, workstreams, workstream)名称本身是否合法就直接决定了路径是否安全——这正是本次修复把「校验」提升到路径构造之前的根本原因。仓库中的 ADR 0004 worktree/workstream seam 模块设计 对相关边界做了更完整的架构阐述。统一的命名语法^[a-zA-Z0-9][a-zA-Z0-9._-]*$修复的核心产物是一套被 CJS 与 SDK 两层共享引用的名称策略模块 workstream-name-policy.ts其中定义了规范正则const ACTIVE_WORKSTREAM_RE /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;据此可整理出明确的合法性与非法性对照维度规则示例首字符必须以字母或数字开头v1.0、feature-1、2026_alpha均合法后续字符允许字母数字、.、_、-release/1.0、my ws、v1.0/../x均非法空值 / 空白空串、纯空白、含空格、 非法路径穿越禁止..、/、\及裸./....、../x、a/../b非法实现层面分为两个互补的判定函数isValidActiveWorkstreamName(name)先剔除..、../前缀及任何内含..的值再对剩余字符串执行正则测试workstream-name-policy.tsvalidateWorkstreamName(name)作为isValidActiveWorkstreamName的别名专门面向 SDK 层调用方导出workstream-name-policy.tshasInvalidPathSegment(name)从「危险面」视角再补一刀——只要包含/、\、裸.、..或点号点序列即判不安全供 CJS 侧路径拼接逻辑复用workstream-name-policy.ts。这一设计使「点号作为合法字符」与「点号点序列作为非法穿越」能同时成立v1.0合法而..在任何位置都被拦截。路径穿越阻断fail-closed 的路径构造..序列一旦混入路径片段配合.planning/workstreams/name的拼接就会产生目录逃逸例如写出到.planning甚至仓库根目录之外。为此路径构造函数relPlanningPath在校验不通过时同步抛出异常而不是静默忽略或清洗后继续export function relPlanningPath(workstream?: string): string { if (!workstream) return .planning; if (!validateWorkstreamName(workstream)) { throw new Error( Invalid workstream name: ${JSON.stringify(workstream)}. Workstream names must match /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/ and may not contain ..., ); } return posix.join(.planning, workstreams, workstream); }见 workstream-utils.ts源码注释明确记载了两个关键决策均属于本修复要保证的一致性前提同一接缝上 fail closed直接调用 SDK、planningPaths、ContextEngine的所有调用方都会在路径构造前通过共享的validateWorkstreamName策略杜绝「SDK 层合法、CJS 层非法」或反向的路径分叉对应问题编号 #3589。不改变环境变量来源的既有契约来自环境变量的 workstream 仍由planningPaths预先过滤为null对应 #2791 的静默回退契约因此该校验不会对 env 来源行为造成破坏性变更——这说明本次修复是「在正确的位置加锁」而不是「改变取值优先级」。CJS 与 SDK 双层的同源校验机制变更集强调「CJS 与 SDK 两层一致校验」其背后是仓库的 shared-module 同步机制。名称策略的权威实现位于 SDK 侧 TypeScript而 CJS 运行时需要的同名策略由生成流程产出sdk/scripts/gen-workstream-name-policy.mjs落地为 workstream-name-policy.generated.cjs同时CJS 侧 active-workstream-store 也通过require(./workstream-name-policy.cjs)获得isValidActiveWorkstreamName。脚本/shared-module 的允许清单scripts/shared-module-handsync-allowlist.json与lint-shared-module-handsync等约束见 lint-shared-module-handsync.cjs确保两个副本不会漂移。这一点在「活动 workstream 解析」上体现得最直观。CJS 运行时按CLI --ws GSD_WORKSTREAM 环境变量 存储的活动指针三级优先级解析 workstream并在取到值后统一执行validateWorkstreamName非法即抛出统一文案的异常Invalid workstream name: must be alphanumeric, hyphens, underscores, or dots见 active-workstream-store.cjs指针读写写入前验证目录、读取时自愈SDK 侧的 active-workstream-store.ts 用对称的两段逻辑保证指针文件的正确性写入端writeActiveWorkstream(projectDir, name)第 35-49 行执行三道闸门name为空时删除指针文件清空当前活动状态name未通过validateWorkstreamName时直接抛错文案与 CJS 层保持一致本次变更集新增的关键闸门在writeFileSync之前先existsSync(workstreamDir(projectDir, name))若目标目录不存在则抛出Workstream directory does not exist: name从根上避免「指针指向不存在的 workstream」这一悬空状态。读取端readActiveWorkstream(projectDir)第 17-33 行则强调「自愈」指针内容非法空或未通过名称校验时主动删除指针文件并返回null指针指向的目录已不存在例如 workstream 被清理时同样删除指针文件并返回null。由此「写入前置校验」与「读取后置自愈」共同保证活动指针在任何时刻要么指向一个真实存在的、命名合法的 workstream要么不存在——不存在悬空引用也不存在可供后续拼接利用的脏路径。model_profile: inherit哨兵不再泄漏为字面模型 ID第三处修复位于会话执行器。在 session-runner.ts 的resolveModel中模型解析优先级为「显式options.model 配置model_profile SDK 默认」而当config.model_profile归一化为inherit时函数直接return undefinedif (config?.model_profile) { const profile String(config.model_profile).toLowerCase(); if (profile inherit) return undefined; const tier profile quality ? opus : (profile budget || profile speed) ? haiku : (profile balanced || profile adaptive) ? sonnet : null; if (!tier) return config.model_profile; return resolveRuntimeTierDefault(claude, tier)?.model; }见 session-runner.ts这确保了inherit作为「继承/交给运行时默认」的哨兵语义存在而不会被当成一个真实模型 ID 传给query()的options.model。同时需要留意其运行环境约束配置层的 profile→Claude 模型映射仅在运行时为 Claude 时生效对 Codex、Gemini、OpenCode 等非 Claude 运行时resolveModel一律返回undefined交由目标运行时回退到其默认模型源码注释对应 #2652、#2832。该哨兵在模型目录层也被显式保留见 model-catalog.ts 对profile inherit的透传分支说明修复目标是「在会话执行边界正确消费哨兵」而非抹掉哨兵这一配置语义。如何验证这三处修复仓库为上述行为提供了多层次回归测试与生成正确性测试可直接作为验证入口活动指针读写与解析tests/active-workstream-store.test.cjs、tests/bug-2524-sdk-query-ws-flag.test.cjs覆盖指针读取、--ws标志路由与回退行为名称策略生成一致性tests/workstream-name-policy-generator.test.cjs与 SDK 侧的sdk/src/bug-3589-planning-paths-validation.test.ts校验命名策略及路径构造的 fail-closed 语义会话执行器模型解析可结合 session-runner.ts 与sdk/src/query/config-query.ts中 profile 解析分支含resolve_model_ids: omit相关逻辑构造model_profile: inherit的用例进行回归。本地运行测试的常规方式仓库已配置 vitest见 vitest.config.ts为在sdk/目录执行对应测试文件或直接查阅根目录 package.json 中声明的测试脚本。小结.changeset/nimble-lynx-tumble.md表面是一条精简的 bug-fix 发布说明实际承载了三项互相咬合的正确性契约统一的 workstream 名称文法字母数字 /-/_/.首字符须为字母数字从源头定义了「什么是合法的工作流名」双层的..穿越阻断与目录存在性校验让路径从构造到指针落盘都 fail-closedinherit哨兵在会话边界的正确消费则消除了配置语义向运行时泄漏的最后一环。理解这些修复的最佳路径是从 workstream-name-policy.ts 出发顺藤摸瓜到 workstream-utils.ts、两套 active-workstream-store / SDK 版 与 session-runner.ts再以对应测试用例收官——这条链路本身就是 GSD「规范驱动、防御式路径处理」工程理念的浓缩样例。【免费下载链接】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),仅供参考