get-shit-done 的 --sdk 安装旗标接线修复:forceSdk 机制与 GSD SDK 部署链路解析
2026/9/7 8:45:21 网站建设 项目流程

get-shit-done 的 --sdk 安装旗标接线修复:forceSdk 机制与 GSD 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

本文基于 changeset 3033-sdk-flag-wired.md 展开,讲解 get-shit-done(GSD)安装器中一个隐蔽的旗标失效问题:--sdk参数此前只在 bin/install.js 中被解析、却从未真正传入 SDK 部署函数,导致npx get-shit-done-cc@latest --sdk会静默跳过 SDK 部署并给出误导性成功提示。读完本文,你将理解 GSD SDK 的部署不变式(gsd-sdk必须可被 PATH 解析)、forceSdk选项如何打通“解析—部署”链路,以及 #2678 本地安装软跳过契约如何在修复中被完整保留,并能据此在本地排障时准确判断安装器输出的各类诊断信息。

背景:--sdk旗标与 GSD SDK 的部署模型

GSD 的 slash 命令、agent 提示词和 hook 脚本依赖一个外部命令gsd-sdk来执行查询类操作。自fix/2441-sdk-decouple之后,SDK 不再作为独立子包安装:sdk/dist/以预构建形式直接打进get-shit-done-ccnpm tarball,父包声明bin条目"gsd-sdk": "bin/gsd-sdk.js",由 npm 在打包安装时正确设置可执行权限(bin/gsd-sdk.js)。

这个 shim 本身极薄:它以自身__dirname为基准解析出sdk/dist/cli.js,再通过spawnSync用当前 node 解释器代为执行(bin/gsd-sdk.js#L30-L37)。因此安装器必须保证两件事:

  • sdk/dist/cli.js存在且可执行;
  • gsd-sdk命令在用户 shell 的 PATH 中可被解析(即command -v gsd-sdk能成功),这是工作流依赖的不变式,而不仅仅是“文件存在”。

安装器入口 bin/install.js 在启动阶段解析安装旗标,--sdk--no-sdk是互斥的一对开关(bin/install.js#L215-L226):

const hasSdk = args.includes('--sdk'); const hasNoSdk = args.includes('--no-sdk'); if (hasSdk && hasNoSdk) { console.error(` ${yellow}Cannot specify both --sdk and --no-sdk${reset}`); process.exit(1); }

两者的语义在installSdkIfNeeded的注释中被明确定义:--no-sdk完全跳过检查(向后兼容);--sdk则“强制检查,即使本应被跳过”(bin/install.js#L10218-L10219)。问题在于,#3033 修复之前,这个“强制”语义并没有真正生效。

缺陷:hasSdk被解析却从未接线

缺陷本身很典型:hasSdk变量在模块顶层被正确解析,但安装全部运行时之后的收尾阶段调用 SDK 部署函数时,参数对象里根本没有它。修复前的效果是——用户显式传入--sdk要求部署 SDK,安装器对本地安装(local install)却走了“软跳过”分支,静默返回,同时终端可能仍然显示误导性的 "✓ GSD SDK ready",用户无从察觉gsd-sdk其实并没有落到 PATH 上。

修复点在安装收尾函数finalize中,将解析结果透传给installSdkIfNeeded(bin/install.js#L11122-L11129):

// #3033: pass forceSdk so --sdk overrides the local-install skip. installSdkIfNeeded({ isLocal: !isGlobal, forceSdk: hasSdk, throwOnFailure: true });

三个参数的分工:

  • isLocal: !isGlobal:区分全局安装与本地安装(本地安装不拥有全局 node_modules,不能走全局安装的报错路径);
  • forceSdk: hasSdk:把--sdk的语义真正接入部署逻辑;
  • throwOnFailure: true:让缺失 SDK 产物时抛出可捕获的异常,而不是直接process.exit,以便与安装回滚机制(installer migrations rollback)协作。

修复核心:forceSdk如何改变早退判定

installSdkIfNeeded对本地安装的早期返回条件,在 #3033 中加入了forceSdk否定项(bin/install.js#L10376-L10404):

// #3033: --sdk (opts.forceSdk) overrides the local-install early-return — // the user explicitly requested SDK deployment, so treat the missing-dist // case like a global install (fail fast with an actionable diagnostic) // instead of silently skipping. if (opts.isLocal && !opts.forceSdk && !fs.existsSync(sdkCliPath)) { console.warn(`\n ${yellow}⚠${reset} Skipping SDK check for local install — sdk/dist/cli.js not found at ${sdkCliPath}.`); return; } if (!fs.existsSync(sdkCliPath)) { const ir = buildSdkFailFastReport(sdkDir, sdkCliPath); renderSdkFailFastReport(ir); if (opts.throwOnFailure) { const error = new Error(`GSD SDK prebuilt artifact missing: ${sdkCliPath}`); error.code = 'GSD_SDK_MISSING_DIST'; error.exitCode = 1; throw error; } process.exit(1); }

从源码结构看,修复后的行为可以用一张矩阵概括(sdkCliPathsdk/dist/cli.js):

安装模式是否传--sdksdk/dist/cli.js行为
本地安装缺失软跳过:打印黄色 "Skipping SDK check for local install" 警告后正常返回(保留 #2678 契约)
本地安装是(forceSdk: true缺失绕过软跳过,进入 fail-fast:渲染诊断报告,throwOnFailure为真时抛出GSD_SDK_MISSING_DIST异常,否则process.exit(1)
本地安装是(forceSdk: true存在执行完整 shim 链接路径,将gsd-sdk落到 PATH 并打印 "✓ GSD SDK ready"
全局安装任意缺失与本地+--sdk相同,fail-fast 退出

fail-fast 诊断并非一句笼统报错。buildSdkFailFastReport先通过classifySdkInstall判断安装形态,再给出对应的修复命令(bin/install.js#L10252-L10322):

  • npx-cache(路径含_npx段,npx 缓存目录被视为只读):提示升级全局安装或清空 npx 缓存重跑,明确声明“不会在 npx 缓存内尝试嵌套npm install”(该行为针对 #2649 的 Windows EACCES/EPERM 误报);
  • tarball(路径含node_modules段):提示发布产物本身缺失sdk/dist/,给出升级命令(对应 #2647);
  • dev-clone(附近存在.git目录):提示开发者自行执行cd sdk && npm install && npm run build,安装器自身绝不 shell out 调 npm。

此外,classifySdkInstall还会做一次副作用最小的写探针(创建临时文件再删除)来判断文件系统是否只读,探针失败一律按只读处理(bin/install.js#L10270-L10281)。

部署成功路径:shim 自链接与跨 shell PATH 校验

sdk/dist/cli.js存在时,installSdkIfNeeded还会完成一系列更严格的工作,这正是--sdk用户期望“完整 shim-link 路径”的具体含义(bin/install.js#L10406-L10522):

  1. 补齐可执行位tsc产物是 0o644、git clone 保留提交时的模式,若 execute bit 缺失则就地chmod修复;chmod 失败不致命,因为 shim 仍可通过node <cliPath>方式调用;
  2. 过滤 npx 临时 PATH 段后再解析filterNpxFromPath剔除 npx 注入的~/.npm/_npx/<hash>/node_modules/.bin——那是安装子进程的临时路径,用户在交互 shell 中不可达,在那里发现gsd-sdk不算“on PATH”(#3231,bin/install.js#L10665 一带的filterNpxFromPath/findGsdSdkOnPath);
  3. 自链接 shim:若 PATH 上找不到gsd-sdktrySelfLinkGsdSdk会挑选第一个“像用户自有 bin 目录”的 PATH 条目写入 shim,找不到则回退到~/.local/bin(即使它不在 PATH 上,随后打印后续建议)(bin/install.js#L10910);
  4. 跨 shell 复验(#3020):进一步探测用户登录 shell 的 PATH(Windows 下经 PowerShell 读用户级Path注册表键,Git Bash、PowerShell、cmd.exe 均继承它),要求 shim 在该持久 PATH 中也可达才允许打印 "✓ GSD SDK ready";
  5. 版本错配报告:若 PATH 上解析到的gsd-sdk与当前包版本不一致,打印版本错配诊断而非无脑打勾。

只有全部通过,终端才会输出绿色的✓ GSD SDK ready (sdk/dist/cli.js);否则输出带shimLocationLine和具体行动建议的 PATH 诊断(#3011)。

回归测试:四组断言锁住 #3033 契约

配套回归测试 tests/bug-3033-sdk-flag-wired.test.cjs 直接调用导出的installSdkIfNeeded,断言文件系统状态与控制台输出,不依赖源码文本匹配。测试在beforeEach中构造临时sdk/目录、独立的HOME与 PATH,四个用例分别覆盖(tests/bug-3033-sdk-flag-wired.test.cjs#L62-L171):

  1. forceSdk=true+isLocal=true+ dist 存在:断言~/.local/bin/gsd-sdkshim 被真实落盘,输出包含GSD SDK ready,且再出现 "Skipping SDK check for local install";
  2. forceSdk=true+isLocal=true+ dist 缺失:断言绕过软跳过、走 fail-fast,process.exit(1)被调用;
  3. throwOnFailure=true:断言缺失 dist 转化为可捕获异常,且error.code === 'GSD_SDK_MISSING_DIST'error.exitCode === 1
  4. 默认(无--sdk)+isLocal=true+ dist 缺失:断言触发process.exit,验证 #2678 的本地安装软跳过契约未被破坏。

该测试文件声明为 POSIX-only(Windows 上整体跳过),因为它强制把 shebang shim 写入~/.local/bin并断言 0o755 权限模式(tests/bug-3033-sdk-flag-wired.test.cjs#L33-L34)。

实战验证与适用前提

修复后,典型验证流程是:

# 全局安装并显式要求 SDK 部署 npx get-shit-done-cc@latest --sdk # 确认 shim 已落上 PATH command -v gsd-sdk gsd-sdk query --help

几点适用前提值得注意:

  • --sdk的完整语义依赖 tarball 内预构建的sdk/dist/fix/2441-sdk-decouple引入的形态);从 git clone 运行安装器时若未先构建 SDK,--sdk现在会明确 fail-fast 并提示cd sdk && npm install && npm run build,而不是静默跳过;
  • --no-sdk仍是完全跳过检查的向后兼容开关,与--sdk互斥,二者同传会直接报错退出;
  • 本地安装(非--global)不带--sdk时,行为与 #2678 之前一致:sdk/dist/cli.js缺失仅打印黄色警告,安装整体不受影响;
  • 由于收尾阶段使用throwOnFailure: true,SDK 部署失败会向上抛异常并触发 installer migrations 的回滚逻辑(见 docs/installer-migrations.md 所述集成方式),避免留下半成品安装。

小结

#3033 的修复面很小——一个布尔参数的接线——但它修正的是“用户显式意图 vs 安装器静默默认”之间的契约缺口。修复后,--sdk真正强制了 GSD SDK 部署不变式:缺失产物时 fail-fast 并给出按安装形态(npx 缓存 / 全局 tarball / git clone)分类的可执行诊断,产物存在时完整走完可执行位修复、npx 临时 PATH 过滤、shim 自链接与跨 shell 复验,最终才允许打出 "✓ GSD SDK ready"。相关证据链可沿 changeset 记录、bin/install.js、bin/gsd-sdk.js 与 tests/bug-3033-sdk-flag-wired.test.cjs 逐层核对。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询