【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载导读/gsd-surface是 gsd-core 中用于免重装切换运行时技能面surface的命令它读写~/.claude/.gsd-surface.json在不重新执行安装流程的前提下对已落地到~/.claude/skills/gsd-*/的技能目录进行原地重排。本文围绕 changeset 记录PR 322类型 Fixed中修复的缺陷展开surface 解析在 profile 闭包与 list/apply 操作前未对 manifest 输入做归一化导致调用方把已解析的gsd-file-manifest.json对象直接传入时manifest.get is not a function崩溃。本文将以源码级证据讲解该缺陷的根因、normalizeSkillManifest的修复机制、/gsd-surface的完整子命令协议与运行时状态模型并给出可供直接落地的配置与排错示例。一、问题背景manifest.get is not a function从何而来1.1 surface 解析对 manifest 的依赖/gsd-surface的核心逻辑位于 src/surface.cts其resolveSurface、applySurface、listSurface三个函数都需要一份技能依赖 manifest来计算 base profile 的传递闭包computeClosure依赖manifest.get(stem)将explicitAdds展开为带依赖的完整技能集合通过_calls_agents_stem元条目派生 Agent 集合在list/status中枚举全部技能 stem 并计算 token 成本。在 src/install-profiles.cts 中computeClosure直接调用manifest.get(stem)function computeClosure(base: Iterablestring, manifest: Mapstring, string[]): Setstring { const closed new Set(base); const queue [...closed]; while (queue.length 0) { const stem queue.pop()!; const deps manifest.get(stem) || []; // ← 要求 manifest 必须支持 .get() ... } return closed; }也就是说manifest参数在整个解析链路上被当作Mapstring, string[]使用。一旦传入的是普通对象plain objectmanifest.get便不存在随即抛出manifest.get is not a function。1.2 触发场景解析后的gsd-file-manifest.json安装期gsd-core 会在每个 runtime 的配置目录根部写入gsd-file-manifest.json源码中定义为INSTALL_MANIFEST_FILE_NAME见 src/surface.cts。该文件记录安装产物的文件清单典型形态包含files映射。例如测试中可见的合法形态{ version: 1.9.0, files: {} }以及安装测试夹具中的{ files: { agents/gsd-planner.md: abc123, skills/gsd-plan-phase/SKILL.md: a } }可分别参考 tests/update-custom-backup.test.cjs 与 tests/shadow-report.security.test.cjs。问题在于调用方可能先JSON.parse读出了这个{ files: {...} }对象然后把它当作 manifest 传给 surface 解析。此时它既不是Map也不是stem → requires[]形式的遗留对象映射manifest.get必然不存在——这正是 PR 322 修复的崩溃点。二、修复核心normalizeSkillManifest的三种输入归一化2.1 函数职责修复在 src/surface.cts 引入了normalizeSkillManifest它把 manifest 输入统一收敛为Mapstring, string[]并依据输入形态分三路处理function normalizeSkillManifest( runtimeConfigDir: string, manifest: Mapstring, string[] | object | null | undefined, ): Mapstring, string[] { // ① 规范形态本身就是 Map直接返回 if (manifest instanceof Map) { return manifest; } // ② null/undefined/非对象返回空 Map不再崩溃 if (!manifest || typeof manifest ! object) { return new Map(); } // ③ 遗留/临时对象映射{ stem: requires[] } const arrayEntries Object.entries(manifest) .filter(([, value]) Array.isArray(value)) as [string, string[]][]; if (arrayEntries.length 0) { return new Map(arrayEntries.map(([stem, deps]) [stem, deps])); } // ④ 已解析的 gsd-file-manifest.json{ files: {...} } // 回到安装源树重建依赖 manifest const manifestObj manifest as Recordstring, unknown; if (manifestObj[files] typeof manifestObj[files] object) { const srcCommandsDir findInstallSourceRoot(runtimeConfigDir); return loadSkillsManifest(srcCommandsDir); } // ⑤ 兜底无法识别则返回空 Map return new Map(); }2.2 每一条路径的语义① Map 直通这是 surface 模块内部的规范形态零开销、行为不变保证既有调用不受影响。② 空值安全null、undefined或非对象输入不再引发异常而是返回空 Map——配合 surface 对空 manifest的保守处理见下文pruneSkillDirs整体 fail-closed。③ 遗留对象映射兼容历史上手写的{ stem: string[] }形态。注意其判定条件是存在至少一个数组值条目这与 ④ 的{ files }形态互斥避免了歧义。④ 已解析 manifest 重建当对象带有files字段时说明调用方传入的是gsd-file-manifest.json的解析结果。此时normalizeSkillManifest通过findInstallSourceRootsrc/runtime-artifact-layout.cts 导出定位安装源根目录再调用loadSkillsManifestsrc/install-profiles.cts重新扫描源commands目录中的*.md重建stem → requires[]依赖表含_calls_agents_stem元条目。这就是surface resolution normalizes manifest inputs before profile closure and list/apply operations的代码落地profile 闭包、list、apply 在进入任何依赖计算之前manifest 都已被归一到可.get()的 Map。⑤ 兜底无法识别的形状返回空 Map由上层逻辑保守处理绝不抛异常。从源码结构看这一修复同时让list/statuslistSurface→resolveSurface、profile/disable/enableapplySurface→resolveSurface全部受益因为三条调用链的入口都先执行normalizeSkillManifest。三、/gsd-surface的运行时状态模型3.1 状态文件与布局状态文件${RUNTIME_CONFIG_DIR}/.gsd-surface.json例如~/.claude/.gsd-surface.json安装期 profile 标记~/.claude/.gsd-profile技能目录~/.claude/skills/gsd-*/引擎模块~/.claude/gsd-core/bin/lib/surface.cjs集群定义~/.claude/gsd-core/bin/lib/clusters.cjs。runtimeConfigDir必须是Claude 配置根目录~/.claude而非~/.claude/skills子目录——这与installRuntimeArtifacts/uninstallRuntimeArtifacts的约定一致技能目录只是destSubpath skills派生出的落点详见 commands/gsd/surface.md。3.2 SurfaceState 结构SurfaceState由四个字段组成src/surface.cts字段类型语义baseProfilestring基准 profile 名core/standard/full也支持逗号组合disabledClustersstring[]被禁用的集群名列表explicitAddsstring[]显式追加的技能 stemexplicitRemovesstring[]显式移除的技能 stem仅自身不级联readSurfacesrc/surface.cts会对这四类字段做结构校验baseProfile必须为 string其余三个必须为数组文件缺失或损坏一律返回nullfail-closed。3.3 有效技能集的计算规则resolveSurfacesrc/surface.cts按以下顺序计算最终集合基准按baseProfile缺失时回退到readActiveProfile或full调用resolveProfile全量展开当基准 profile 为full时把 manifest 中全部非_calls_agents_前缀的 stem 物化为集合并对 capability registry 贡献的第三方技能做幂等合并见#2045相关注释去除禁用集群clustersToSkills将disabledClusters展开为成员 stem 并删除src/surface.cts 中同时修复了非数组成员导致抛异常的问题追加显式技能explicitAdds沿 manifest 依赖边做传递闭包后加入移除显式技能explicitRemoves只删自身 stem不级联派生 Agent对每个技能 stem 读取_calls_agents_stem条目汇总为 Agent 集合。四、子命令协议与调用链/gsd-surface的第一 token 路由规则commands/gsd/surface.mdToken动作list展示启用的集群与技能statuslist别名追加 token 成本汇总与 base/install profile 对比profile name写baseProfile并重排支持逗号组合如profile core,standard无空格disable cluster把集群加入disabledClusters并重排enable cluster从disabledClusters移除集群并重排reset删除.gsd-surface.json回到安装期 profile(无参数)等价于list4.1 原子化的 mutation 协议/gsd-surface的所有变更操作都遵循内存中派生候选状态 → 交给applySurface发布的协议commands/gsd/surface.md先在内存中构造下一个SurfaceState通过opts.surfaceState传给applySurface绝不先调用writeSurfaceapplySurface先对所有 artifact kind 完成 stagingstaging 阶段任一失败则什么都不写全部成功后才原子发布候选状态传null表示重置到安装期 profile。这一设计在源码 src/surface.cts 与 src/surface.cts 中有对应实现candidateState仅在所有 kind 均 staging 成功、且pruneRetiredRuntimeArtifacts与_syncGsdDir全部完成后才写入candidateState null时删除状态文件。这也正是 changeset 中list/status/enable/disable 不再崩溃之外的工程要点崩溃修复与原子发布共同保证了 surface 变更不会留下半成品状态。profile子命令的典型调用链commands/gsd/surface.mdconst registry require(runtimeConfigDir /gsd-core/bin/lib/capability-registry.cjs); const layout resolveRuntimeArtifactLayout(runtime, runtimeConfigDir, scope); applySurface(runtimeConfigDir, layout, manifest, CLUSTERS, registry, { surfaceState });4.2 可用的集群名disable/enable接受以下集群与CLUSTERS定义一致见 commands/gsd/surface.mdcore_loop · audit_review · milestone · research_ideate · workspace_state docs · ui · ai_eval · ns_meta · utility4.3 token 成本估算listSurfacesrc/surface.cts对每个启用的技能 stem从安装源读取对应*.md的description:frontmatter按描述字符数 ÷ 4累计 token 成本与 audit 脚本口径一致并给出预算提示如 200k 上下文 1% 约为 500 token 上限。五、与 manifest 相关的保守化边界5.1 技能目录清理的所有权判定pruneSkillDirssrc/surface.cts是技能目录清理的单一事实源。它同样对 manifest 做了防御非 Map 的 manifest 一律视为缺失safeManifest缺失时不做任何删除——保守优先宁留勿删带前缀如gsd-的目录必须同时满足前缀匹配 manifest 成员或携带CAPABILITY_SKILL_MARKER自证文件才判定为 GSD 所有否则视为用户自有目录并保留同时向 stderr 输出警告Hermes空前缀路径下仅 manifest 中出现的规范化 stem 才可被清理。这与normalizeSkillManifest的空值兜底形成闭环无论 manifest 是 Map、遗留对象、已解析的gsd-file-manifest.json还是空值都不会触发manifest.get is not a function也不会误删用户文件。5.2 本修复不改变的其他边界applySurface校验runtimeConfigDir与layout.configDir必须一致src/surface.cts否则抛TypeError表面应用路径同样受real-home-guard的测试沙箱约束assertTestHomeSandboxed见 src/real-home-guard.cts防止通过kind.home逃逸到真实$HOME错误处理commands/gsd/surface.md未知集群名 → 列出合法集群并退出未知 profile → 列出core/standard/full并退出surface.cjs缺失 → 提示重新安装opengsd/gsd-core。六、验证与回归changeset 记录该修复对应 PR 322类型为Fixed直接影响list/status/enable/disable四类子命令仓库中与 surface 相关的回归测试覆盖了布局一致性tests/runtime-artifact-layout-surface.test.cjs、空 manifest 下的 Agent 派生tests/surface-empty-manifest-agents.test.cjs、surface 路径的 Markdown 相对路径改写tests/surface-md-paths.regression.test.cjs以及安装面遮蔽诊断src/health-diagnostic-rules/install-surface-shadowing.ctsgsd-file-manifest.json的写入与读取在安装、卸载、备份恢复等多个测试中被反复断言如 tests/codex-config-hooks.test.cjs 中安装失败后恢复先前 manifest的场景可作为理解该文件契约的补充证据。七、实操建议升级到包含 PR 322 的版本后直接执行/gsd-surface status即可验证修复即使此前调用链传入的是解析后的gsd-file-manifest.json对象现在也会正常输出 enabled/disabled 列表与 token 成本而不再抛出manifest.get is not a function。编写自动化脚本调用applySurface时请统一走内存候选状态 →{ surfaceState }发布协议不要绕过applySurface直接writeSurface以保证原子性。需要精确控制 surface 时profile core,standard的组合写法与disable ui等集群级操作可叠加使用reset是回到安装期状态的唯一权威手段状态文件仅在重排成功后删除。排查异常时优先检查~/.claude/.gsd-surface.json的四个字段类型是否满足baseProfile: string、其余三个为数组——readSurface对结构不合法的文件返回null此时命令会按安装期 profile 兜底。结语PR 322 用一次前置归一化normalizeSkillManifest修复了 surface 全家桶list/status/profile/disable/enable在解析后的 manifest 对象输入下的崩溃问题并把空值/畸形输入保守处理这一工程原则贯彻到了技能目录清理与集群展开的每一处。理解这一修复既能让你安全地把gsd-file-manifest.json的解析结果交给/gsd-surface也能帮你更精准地诊断运行时技能面的启停行为。赞分享【免费下载链接】gsd-coreGit. Ship. Done - Core项目地址https://gitcode.com/gh_mirrors/ge/gsd-core点击查看免费下载相关推荐gsd-core 运行时斜杠命令输出机制从 PR 3584 看 /gsd-cmd 与 $gsd-cmd 的单一格式化器gsd core 运行时斜杠命令输出机制从 PR 3584 看 /gsd cmd 与 $gsd cmd 的单一格式化器 导读 gsd core 会在多处运GSD Skill Surface 运行时管理全解析使用 /gsd:surface 按集群开关技能、切换 Profile 而不重装GSD Skill Surface 运行时管理全解析使用 /gsd:surface 按集群开关技能、切换 Profile 而不重装 GSDget shit人工智能AI 应用提示工程开发工具工作流自动化AI Agentgsd-core 运行时名称规范化基于共享别名清单统一 GSD_RUNTIME 与配置输入的运行时身份解析gsd core 运行时名称规范化基于共享别名清单统一 GSD_RUNTIME 与配置输入的运行时身份解析 本篇技术指南围绕 gsd core 的运行时名称策上一篇LLaDA2.0-Uni vs DALL-E 3多模态大模型生成能力深度对比评测下一篇Cromite浏览器常见问题技术解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
