news 2026/10/9 18:45:10

gsd-core 现有代码接入指南:/gsd:onboard 如何基于仓库状态投影确定接入路由

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gsd-core 现有代码接入指南:/gsd:onboard 如何基于仓库状态投影确定接入路由

【免费下载链接】gsd-core

Git. Ship. Done - Core

项目地址:https://gitcode.com/gh_mirrors/ge/gsd-core
点击查看免费下载

本文介绍 gsd-core 的Existing Code Onboarding Module(现有代码接入模块):它通过一个纯函数式、只读的投影(projection)模块,确定性检测 brownfield(既有代码)仓库的文件系统状态,并据此选择下一步该运行的接入原语(/gsd:map-codebase、/gsd:ingest-docs、/gsd:new-project)。读完本文,你将理解/gsd:onboard的路由判定逻辑、状态检测规则、安全不变量,以及它如何被 Init Command Module 和工作流渲染层消费。

该模块的架构决策记录在 docs/adr/1990-existing-code-onboarding.md(ADR-1990,Issue #1990,实现 PR #1994),核心实现位于 src/onboard-projection.cts。

背景:为什么需要一个接入编排入口

GSD 早已具备若干处理既有代码库的独立原语:

  • /gsd:map-codebase—— 并行代码库分析,产出.planning/codebase/地图;
  • /gsd:ingest-docs—— 分类并整合仓库中已有的 ADR/PRD/SPEC/RFC 文档;
  • /gsd:new-project—— 规划初始化,建立PROJECT.md/REQUIREMENTS.md/ROADMAP.md/STATE.md。

问题在于:缺少一个统一的引导入口,告诉用户在某个 brownfield 仓库中哪一个原语应该先执行。如果只靠自然语言描述,执行顺序是模糊且不安全的——用户可能在代码库地图尚未生成前就初始化规划、跳过相关设计文档、或者覆盖/重复.planning/上下文而不是复用它。

ADR-1990 的核心判断是:这个顺序问题不是口味偏好,而是一个依赖图——地图应在规划之前存在;已有设计文档应在全新/gsd:new-project之前被 ingest;任何操作都不应破坏进行中的.planning/。而"从文件系统状态决定下一步安全动作"的依赖图,本质上是一个投影(projection)——它无法被工作流中的自然语言指令可靠地求值或测试。

三层架构:投影、处理器与渲染

该模块遵循 GSD 已有的两个投影模块先例——Planning Path Projection Module(ADR-0006,负责.planning路径解析)与Shell Command Projection Module(ADR-0009,负责运行时感知的命令投影)。如果/gsd:onboard以自由形式的工作流正文去内联扫描目录树,就会把不可测试、不确定的文件系统逻辑塞进 markdown——这正是那些投影模块要防止的反模式。

因此,模块被切分为三个明确层次:

  1. 投影(投影模块本身):src/onboard-projection.cts 编译为gsd-core/bin/lib/onboard-projection.cjs。它是纯函数、无副作用的投影:只读仓库状态,计算next_action,从不写入任何文件。
  2. 处理器(Init Command Module):src/init.cts 是init.*查询处理家族的所有者,其 cmdInitOnboard 处理器(L1865-L1881) 调用buildOnboardProjection,并合并getInitGitState的 Git 状态字段,最终以与兄弟处理器相同的{ data: <flat JSON> }契约输出。命令路由在 src/init-command-router.cts 的 onboard: 分支(L182-L185) 中接线:解析--fast/--text布尔标志后调用cmdInitOnboard。
  3. 渲染(工作流层):gsd-core/workflows/onboard.md 只负责菜单/门禁呈现;commands/gsd/onboard.md 及其技能镜像 skills/gsd-onboard/SKILL.md 负责委托。模块本身只拥有它们消费的"状态 → 路由"决策。

在 CLI 层面,你可以直接查看投影结果:

# 默认模式(完整地图门槛) gsd_run --cwd "$PWD" init onboard --raw # 快速模式(接受 fast map 用于轻量接入) gsd_run --cwd "$PWD" init onboard --fast --raw # 文本模式(无交互选择器的运行时) gsd_run --cwd "$PWD" init onboard --text --raw

--raw输出为扁平 JSON 结构(如next_action.kind、is_brownfield、map_readiness、handoff_commands等字段),供工作流解析渲染。

状态检测:投影的输入信号

投影从仓库文件系统读取五类信号。下面的信号表来自 ADR-1990,括号内为源码中的实际实现细节。

信号规则 / 不变量
Brownfield 代码存在深度受限的递归代码文件扫描(hasCodeFilesInternal)或识别到包清单(hasPackageFileInternal)
生成 / vendor 目录排除扫描跳过CODE_SCAN_SKIP_DIRS,避免 vendored 树产生错误的 brownfield 判定
代码库地图完整性.planning/codebase/是否持有规范地图产物
既有设计文档是否存在 ADR/PRD/SPEC/RFC 风格的候选(根级、嵌套目录、以及路径段匹配)
部分规划状态PROJECT.md/REQUIREMENTS.md/ROADMAP.md/STATE.md是否只存在一部分

深度受限的代码扫描与包清单

hasCodeFilesInternal(src/onboard-projection.cts L116-L133)以深度上限 3递归扫描,匹配 31 种源码扩展名:.ts.tsx.js.jsx.mjs.cjs.py.go.rs.swift.java.kt.kts.c.cpp.cc.h.hpp.cs.rb.php.dart.m.mm.scala.groovy.lua.r.R.zig.ex.exs.clj。深度上限保证扫描成本可控,不会遍历整个仓库。

hasPackageFileInternal(L135-L137)检查 18 种常见包清单文件:package.json、requirements.txt、pyproject.toml、Cargo.toml、go.mod、Package.swift、build.gradle、build.gradle.kts、pom.xml、Gemfile、composer.json、pubspec.yaml、CMakeLists.txt、Makefile、build.zig、mix.exs、project.clj。即使没有任何源码文件,只要存在包清单也被视为 brownfield——这是测试中明确覆盖的语义(见下文"测试与回归")。

最终isBrownfield = hasCode || hasPackageFile(L345),同时投影输出has_existing_code与has_package_file两个细分字段。

生成 / vendor 目录排除

ADR 中记录的CODE_SCAN_SKIP_DIRS为node_modules、dist、build、.next、.nuxt、.svelte-kit、coverage、vendor、.venv、venv;源码中的实际集合(L19-L22)更完整,还包含.git、.planning、.claude、.codex、__pycache__、target。这些目录在代码扫描与文档候选扫描中都会被跳过,确保一个只有node_modules/dist的"空"仓库不会被误判为 brownfield——对应测试ignores generated and vendor directories when detecting existing code。

代码库地图完整性

完整地图与快速地图各有一套规范文件清单(L31-L38):

模式必需文件
完整地图(REQUIRED_CODEBASE_MAP_FILES,7 个)STACK.md、ARCHITECTURE.md、STRUCTURE.md、CONVENTIONS.md、TESTING.md、INTEGRATIONS.md、CONCERNS.md
快速地图(FAST_CODEBASE_MAP_FILES,4 个)STACK.md、INTEGRATIONS.md、ARCHITECTURE.md、STRUCTURE.md

listCodebaseMapFiles(L202-L212)只读取项目作用域下的.planning/codebase/(注释标注了 Issue #3964:扁平根读取会让GSD_PROJECT下的has_codebase_map/needs_codebase_map答错项目)。由此得到三态map_readiness: 'none' | 'fast' | 'complete'(L214-L218)。投影还会输出missing_codebase_map_files、missing_fast_codebase_map_files、codebase_map_summary_status、codebase_map_final_status等诊断字段。

设计文档候选

listPlanningDocCandidates(L139-L200)在深度 ≤ 3 内识别设计文档,命中规则为(满足其一即算候选,且仅限.md文件):

  • 文件名匹配/(^|[-_ ])(ADR|PRD|SPEC|RFC)([-_ ]|\.)/i(如ADR-001.md、0001-PRD.md);
  • 文件名匹配/^\d{4}[-_].+\.md$/i(如0001-decision.md);
  • 相对路径的某个路径段属于PLANNING_DOC_SEGMENTS:adr/adrs/prd/prds/spec/specs/rfc/rfcs(如docs/adr/0001-runtime.md);
  • 文件名恰为REQUIREMENTS.md。

扫描覆盖根级文件以及docs、adr、adrs、prd、prds、spec、specs、rfc、rfcs根目录(L140),同样跳过CODE_SCAN_SKIP_DIRS。

规划状态

投影逐一探测四个规划文档的存在性(L352-L361):PROJECT.md(同时检查根级与项目作用域两个候选路径)、REQUIREMENTS.md、ROADMAP.md、STATE.md,并生成planningMissing缺失清单(L232-L244)。hasPlanningArtifacts为四者任一存在。同时探测.planning/config.json、.planning/onboarding/SUMMARY.md等辅助状态。

路由选择:依赖序优先于便利序

ADR-1990 给出的路由选择(输出)按依赖序排列:

  1. Brownfield 代码且.planning/codebase/地图不完整 → 交给/gsd:map-codebase(fast 模式为/gsd:map-codebase --fast);
  2. 存在设计文档候选且尚无项目 → 在/gsd:new-project之前提供/gsd:ingest-docs;
  3. 否则 →/gsd:new-project。

并且 ADR 强调:partial-planning 与 fast-map-completeness 必须在 docs-ingest 分支之前求值,这样半地图或半初始化的仓库永远不会被路由越过它尚欠的步骤。

源码中nextAction(src/onboard-projection.cts L246-L319)实现了更细粒度的 8 分支判定,顺序即优先级:

优先级条件next_action.kind含义
1isBrownfield && needsOnboardCodebaseMapmap-codebase检测到既有代码但缺必需地图;fast 模式用map_codebase_fast
2hasPlanningArtifacts && missingPlanningFiles.length > 0partial-planning规划存在但不完整,列出missing
3fastMode && mapReadiness === 'fast' && !projectExistscomplete-map-before-new-projectfast map 只够轻量接入,项目初始化前仍需完整地图
4hasDocsCandidates && !projectExistsingest-docs项目建立前应先 ingest 已有设计文档
5!isBrownfield && !projectExists && !hasDocsCandidatesnew-project未检测到代码或规划文档(greenfield)
6!projectExistsnew-project代码库上下文已就绪,可初始化项目
7!onboardingSummaryExistswrite-summary缺少接入摘要
8兜底ready接入摘要已存在

fast 模式通过needsOnboardCodebaseMap = options.fast ? needsFastCodebaseMap : needsCodebaseMap(L351)切换门槛:fast 模式只要求 4 个快速地图文件齐全,而非 7 个完整地图文件。但注意第 3 分支:在项目建立前,fast map 仍不足以放行new-project——只有当项目设置已完整时(分支 7),fast map 才足够推进到摘要阶段。这正是回归测试#1990中"fast map gate misroute"修正后的行为。

每个分支都携带人类可读的reason,例如Existing code was detected, but the required .planning/codebase/ map is missing.,工作流直接将其呈现给用户。

安全不变量:为什么这是一个模块而非辅助函数

ADR-1990 明确列出四条安全不变量,全部由投影的只读设计保证:

  1. 幂等 / 无静默覆盖。接入过程绝不修改既有被跟踪的.planning/产物;重复运行保持字节不变。测试reports complete codebase map and onboarding summary in existing planning在运行前后对PROJECT.md、ROADMAP.md、STATE.md、SUMMARY.md做字节级比对断言(tests/onboard-command.test.cjs L114-L153)。
  2. SUMMARY.md是尾随产物。.planning/onboarding/SUMMARY.md只在项目设置已存在且文件缺失时才写入;工作流明确"不覆盖已有摘要"。
  3. "完成"是合取而非析取。只有PROJECT.md、REQUIREMENTS.md、ROADMAP.md、STATE.md全部存在才报告完成——不存在单文件短路。
  4. 文本模式等价。--text渲染与交互式选择器完全相同的门禁决策为编号纯文本提示,使没有交互选择器的运行时(OpenAI Codex、Antigravity 等)获得一致路由。

运行时感知的 handoff 命令

投影输出的handoff_commands(buildHandoffCommands,L321-L331)不是硬编码的/gsd:xxx字符串,而是通过 src/runtime-slash.cts 的 formatGsdSlash(L31-L74) 按运行时解析格式:resolveRuntime读取运行时身份,formatGsdSlash依据能力注册表中的commandStyle决定输出——Claude 风格输出/gsd-<cmd>,Codex 等 shell-var 运行时输出$gsd-<cmd>(命令 token 小写)。这样投影出的"下一步命令"对当前安装的运行时的斜杠语法总是正确的。

{ "handoff_commands": { "map_codebase": "/gsd-map-codebase", "map_codebase_fast": "/gsd-map-codebase --fast", "ingest_docs": "/gsd-ingest-docs", "new_project": "/gsd-new-project", "manager": "/gsd-manager", "onboard": "/gsd-onboard" } }

在GSD_RUNTIME=codex环境下,同样的命令会渲染为$gsd-map-codebase等(对应测试formats onboard handoff commands for the resolved runtime)。另外,onboarding_summary_path使用锚定在 cwd/project_root 的绝对路径(源码注释标注 Issue #2376),避免派生子代理的 cwd 与编排者不一致导致路径错位。

工作流渲染:菜单、门禁与文本模式

gsd-core/workflows/onboard.md 是围绕投影的"薄渲染器":它通过gsd_run自举解析器(来自共享的references/gsd-run-resolver.md,而非内联)运行init onboard --raw/init onboard --fast --raw,解析 JSON 字段后按next_action.kind分派:

  • map-codebase:询问用户"先映射代码库?"(推荐)或"跳过映射"。跳过路径仍有守卫:若规划存在但不完整,改走 partial-planning 守卫;若存在文档候选且无项目,改走 docs ingest;否则提示跳过会削弱new-project的上下文。
  • ingest-docs:询问是否先 ingest 检测到的 N 个文档候选;跳过则警告会遗漏既有文档上下文。
  • complete-map-before-new-project/new-project/partial-planning:直接打印下一步命令并要求在ONBOARDING_ROOT({git_worktree_root || _GSD_RUNTIME_ROOT})下运行后重跑/gsd:onboard。
  • write-summary:创建.planning/onboarding/SUMMARY.md(不覆盖),模板记录项目状态、代码库上下文、文档上下文与推荐下一步;若commit_docs为真,仅提交摘要路径(query commit "docs: create onboarding summary" --files .planning/onboarding/SUMMARY.md)。
  • ready:打印最终状态并结束。

工作流同时处理response_language(用户可见输出翻译为指定语言,技术术语与路径保持英文)、嵌套 Git worktree 警告(has_git && in_nested_subdir时提示产物归属外层 worktree 且不执行git init),以及 Copilot 的vscode_askquestions等价适配。接入流程绝不执行实现阶段或 ship 工作——这也是命令契约测试断言!content.includes('execute-phase')与!content.includes('gsd:ship')的原因。

模块边界:什么留在模块之外

ADR-1990 明确划定了边界,防止模块膨胀:

  • 原语本身:/gsd:map-codebase、/gsd:ingest-docs、/gsd:new-project保持各自行为不变;模块只选择并排序它们,投影路由而不重实现目的地。
  • 写入规划产物:所有.planning/写入仍归目的地命令与 Installer/规划模块所有;投影是只读的。
  • 工作流的渲染:菜单/门禁呈现归 gsd-core/workflows/onboard.md,命令委托归 commands/gsd/onboard.md 及其技能镜像 skills/gsd-onboard/SKILL.md;模块只拥有它们消费的状态→路由决策。

测试与回归

投影的负载行为全部由 tests/onboard-command.test.cjs(约 25 KB)覆盖,主要用例包括:

  • brownfield 代码 / 文档 / 缺失规划状态的整体报告;
  • 顶层ADR/PRD/RFC目录与根级设计文档的候选检测;
  • --text标志透传为text_mode: true;
  • 完整地图与既有摘要下的幂等性(无突变断言);
  • fast 地图就绪但缺完整地图时,路由到complete-map-before-new-project(next_action.command为/gsd-map-codebase);
  • partial-planning 在 docs-ingest 与 complete-map 门禁之前求值——即回归测试#1990:fast mode routes incomplete planning to partial-planning before the complete-map gate;
  • 对全部状态(code / docs / greenfield / partial planning / summary / ready)的next_action精确断言;
  • vendor 目录排除与包清单 brownfield 判定;
  • 运行时格式化(GSD_RUNTIME=codex→$gsd-*);
  • 点号查询query init.onboard与直接init onboard的输出一致性;
  • 命令契约测试:工作流必须引用共享 resolver、渲染全部 7 种next_action.kind、跳过路径必须显式 handoff 且保持 partial-planning 先于 docs-ingest 的守卫顺序。

后果与维护耦合

ADR-1990 记录的后果包括:

  • Brownfield 接入从"散文中的操作顺序民俗"变为单一、可测试、确定性路由的入口。
  • Init Command Module 新增一个重量级处理器initOnboard,沿用与兄弟处理器相同的{ data: <flat JSON> }契约,没有新的分发形态。
  • 新增的维护耦合已被显式记录:模块的完整性检查必须跟随规范.planning/codebase/产物清单及路由目标的身份变化;若三个目的地命令更改其入口契约,投影必须跟进。ADR 将这一耦合记录为集中化路由决策的已知成本——与之相对的替代方案(在每个原语内复制该决策)更糟。
  • 无新增运行时依赖,不改变既有命令语义(纯增量)。

开放问题

ADR-1990 留有两个开放问题,供后续演进观察:

  1. 代码库地图完整性是否应改为从地图模块持有的单一共享谓词获取,而非在本模块中重新编码,以避免两处漂移?
  2. /gsd:onboard工作流从共享的references/gsd-run-resolver.md片段获取gsd_run自举而非内联;如果该委托模式被其他工作流采用,可能值得单独成文一份简短 ADR——此处记录该先例使其可见,而非悄然确立。

快速上手

对刚克隆的既有仓库,接入流程是:

# 1. 从仓库根运行 onboard,查看投影出的下一步 gsd_run --cwd "$PWD" init onboard --raw # 2. 按 next_action 指示执行: # - map-codebase → gsd_run --cwd "$PWD" init map-codebase --raw(或带 --fast) # - ingest-docs → gsd_run --cwd "$PWD" init ingest-docs --raw # - new-project → gsd_run --cwd "$PWD" init new-project --raw # - partial-planning → 补齐缺失的 PROJECT.md / REQUIREMENTS.md / ROADMAP.md / STATE.md # - write-summary/ready → 接入完成,接下来运行 /gsd-manager # 3. 每个目的地命令执行完毕后,重新运行 onboard,直到 next_action.kind 变为 ready

接入的终点是ready:四份规划文档齐全、代码库地图完整(fast 模式除外,见上文第 3 分支约束)、接入摘要已写入.planning/onboarding/SUMMARY.md,系统推荐的下一步是/gsd-manager。整个过程不执行任何实现阶段,不 ship 任何工作——/gsd:onboard只负责把你安全地领到正确的起点。

【免费下载链接】gsd-core

Git. Ship. Done - Core

项目地址:https://gitcode.com/gh_mirrors/ge/gsd-core
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 18:41:04

凸分析工具链:示性函数、共轭函数与对偶范数实战指南

1. 从示性函数到共轭函数&#xff1a;一套被低估的凸分析工具链示性函数、共轭函数、对偶范数、共轭——这四个词放在一起&#xff0c;很多人第一反应是“凸优化课本里的东西&#xff0c;考试完就还给老师了”。但我自己做过几个涉及稀疏建模和正则化求解的项目之后&#xff0c…

作者头像 李华
网站建设 2026/10/9 18:40:40

HTML练手全攻略:从骨架到天气卡片,避开新手五个坑

1. HTML 练手第一步&#xff1a;把文档骨架写进肌肉记忆 HTML 这个东西&#xff0c;跟我刚开始学的时候一样&#xff0c;很多人第一反应就是"这有什么好练的&#xff1f;不就是几个标签吗&#xff1f;"但真正的问题是&#xff1a;标签认得&#xff0c;页面写不好。我…

作者头像 李华
网站建设 2026/10/9 18:36:57

Cursor 扩展工具 Context7 MCP 接入 TaoToken 的配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/9 18:35:09

Fluent Meshing水密工作流中Add Local Sizing实战指南

如果你和我一样&#xff0c;每天要和 Fluent Meshing 打交道&#xff0c;那你一定遇到过这种场景&#xff1a;全局尺寸给到0.5mm&#xff0c;算下来网格量五百多万&#xff0c;看起来数值也没问题&#xff0c;但一到弯管处&#xff0c;边界层一拉&#xff0c;圆弧面网格完全看不…

作者头像 李华
网站建设 2026/10/9 18:29:30

DeepView MCP 接入 TRAE:把 MCP endpoint 改到 TaoToken 的配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华