news 2026/9/14 17:38:35

text-to-cad 仓库工程实战:Agent Skill 开发的分支布局、发布管线与 CAD Viewer 调试全解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
text-to-cad 仓库工程实战:Agent Skill 开发的分支布局、发布管线与 CAD Viewer 调试全解

text-to-cad 仓库工程实战:Agent Skill 开发的分支布局、发布管线与 CAD Viewer 调试全解

【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cad

text-to-cad 是一个面向 CAD、CAE、CAM 的 Agent Skill 库(当前规范版本见 VERSION),仓库根目录本身即 Agent 插件包。本文以仓库工程约定文件 AGENTS.md(由 CLAUDE.md 以@AGENTS.md指令引入)为骨架,系统拆解其分支与目录布局、以 GitHub Actions 为中心的单次发布工作流、Skill 自包含的边界规则、检查体系,以及 CAD Viewer 的本地调试方法;所有结论均以仓库内脚本、配置与测试为证据,读者可据此直接开展分支开发、跑通发布流水线并在本地把 CAD Viewer 跑起来。

仓库定位:一个“以 Skill 为产品”的 Workbench

仓库把skills/视为产品本体(每个目录是一份可独立安装的 Agent Skill),把models/视为共享的 fixture/artifact 区域(STEP、STL、GLB、DXF、URDF、SRDF、SDF 等样本与生成产物统一落在这里)。围绕这两块核心,仓库还维护了:

  • viewer/:可编辑的 CAD Viewer 应用源码,作为本地文件系统应用被逐字镜像到独立的 cad-viewer 仓库;
  • packages/cadjs:与 UI 框架无关的共享 JS CAD / 渲染 / 运行时代码;
  • packages/implicitjs:独立的自包含 implicit CAD 模型、着色器渲染、快照、网格采样与导出运行时;
  • packages/cadgen:共享的 Python STEP/GLB/topology 工件生成代码;
  • docs/tests/scripts/:文档站、根级测试套件与长期有效的仓库命令。

从文件组织可以看出两条硬约束:共享运行时一律放packages/作为唯一事实源,再由打包流程 vendor 进各 Skill 的运行时目录models/是唯一允许写 CAD/机器人描述产物的地方,禁止在仓库其他位置随手创建产物目录。

分支与布局策略:develop 用 symlink 开发,main 只做发布

分支纪律

  • 所有开发从develop分支切出,PR 一律打回develop禁止从main起步开发
  • main纯发布分支:只接受Release工作流的发布提交,禁止向其开 PR 或直接 push;
  • develop分支刻意使用 symlink 布局(跨生成的运行时路径与 viewer 本地包路径),遇到 symlink 时要沿链接追踪并编辑真正的源目标。

两种布局的本质区别

  • develop(开发布局):把生产打包产物路径以 symlink 指回规范源码,贡献者只需编辑skills/viewer/packages/下的一份源码。建立与校验布局使用 scripts/dev/setup-symlinks.sh:
scripts/dev/setup-symlinks.sh # 建立开发 symlink 布局 scripts/dev/setup-symlinks.sh --check # 校验布局无损,不改动文件

该脚本内部委托 scripts/dev/setup-skill-symlink.sh 与各 Skill 的setup-*-skill-symlink.sh逐个建立链接。

  • main(发布布局):必须能被“裸 checkout”直接安装,因此里面是真实的生成产物副本,而非 symlink。把 symlink 替换成真实副本在main上是正确性要求而非惯例。

为什么 symlink 不能进入发布树

不同 Agent 安装器对 symlink 的处理方式互不相同,且其中一种会静默丢文件。这一点在 scripts/github-workflows/check-builds.sh 中有明确注释佐证:

  • Skills CLI(npx skills):把 symlink 解引用为真实文件;
  • Claude Code 插件安装:原样保留 symlink;
  • Codexplugin add静默丢弃 symlink 且无任何报错——其copy_dir_recursive只按is_dir()/is_file()分支判断,symlink 条目两个分支都不命中,于是该文件直接缺失,Skill 装上后运行时缺文件。

因此发布树中一旦出现 symlink,check-builds.sh会直接失败(Production bundle paths must not contain symlinks),这是 CI 红线,不可放宽。

main 的“裁剪”语义

仓库根即插件包,main上任何源码路径都会被复制进每次安装,所以发布任务在打包、全部检查通过之后会裁剪发布树:移除models/viewer/tests/docs/packages/requirements-dev.txt,让main尽量只保留插件包本身。这些内容并不丢失,因为各自都有“读源码而非读发布树”的消费方:

  • viewer/的运行时是解引用后的skills/cad-viewer/scripts/viewer副本,镜像仓库同步自发布源提交;
  • docs/packages/Deploy Docs工作流从发布源提交构建部署;
  • models/tests/requirements-dev.txt只在源码检出时使用。

单次发布的完整管线:Release / Deploy Docs / Sync CAD Viewer

规范版本号的唯一事实源:VERSION

VERSION(当前为0.4.10)是规范发布版本号,普通开发 PR 一律不碰它。所有衍生版本元数据(各package.json/package-lock.jsonversion字段、.claude-plugin/.codex-plugin/插件清单版本、packages/cadgen/pyproject.toml等 TOML 的version行)由 scripts/release/sync-version.mjs 从VERSION统一盖章。

值得注意的工程细节:由于 develop 布局下镜像路径与规范路径是 symlink,多个目标可能指向同一个真实文件sync-version.mjsmergeTargetsByRealPathrealpath合并目标后再统一写回,避免“后写的镜像目标覆盖掉规范目标独有字段”这类问题——这正是 0.4.10 发布门禁曾因packages/cadjs/package-lock.json被 symlink 覆盖而自锁的教训修复。因此永远不要手工编辑这些重复的版本字段,scripts/release/bump-version.sh与 scripts/bundle/bundle.sh 会负责盖章。

Release 工作流:一次运行完成整个发布

发布只通过单一的ReleaseGitHub Actions 工作流完成,默认参数即真实发布配置:

gh workflow run release.yml --ref develop -f bump=patch

一次运行依次完成:在release/<version>分支上 bumpVERSION与衍生元数据 → 打开发布 PR 并立即合入develop→ 执行发布(生产打包、校验、写main)→ 部署文档 → 打 semver tag 与 GitHub Release。关键约束:

  • 不要自行选择 semver:请求未指明 patch / minor / major 或精确版本时必须先确认再派发;
  • 发布 PR 不等自身 CI;发布任务会对“最终要发布的东西”重新跑完整打包与测试门禁;
  • 只有源版本新于main与最新 semver tag、且源包含上一次发布源提交时才允许发布;写main时以“生成的生产合并提交”叠加在上一发布目标之上、以发布源为第二父提交,既保证main可 fast-forward,又保留源码提交用于 release notes 与贡献者归属;
  • GitHub Release 默认立即发布;publish=false可先以草稿审阅。

PyPI 发布 cadgen

发布任务同时把packages/cadgen上传到 PyPI:先校验生产 bundle,再 pushmain之前上传——发布树用 scripts/release/pin-cadgen-requirements.sh 把 editable 依赖行改写为固定的cadgen==<version>(来自 PyPI),因此 PyPI 上传失败必须阻塞发布,否则会发布一个依赖无法解析的main。PyPI 版本恒等于VERSION,上传使用skip-existing,失败重跑幂等可续。首次发布需在 PyPI 为cadgen配置 trusted publisher(GitHub OIDC),无需存储 API token。

bump=none:不是发布设置

bump=none表示“把base_branch原样发布”:不改版本、不开发布 PR、直接进入发布任务。它用于续跑失败发布build-test做管线彩排set_version只用于指定新版本,不是“保持版本不动”的说法。即使bump=nonesync-version.mjs仍会运行,若衍生元数据与VERSION漂移会被拦截走发布 PR 流程。

彩排与续跑

  • CI/CD 或构建变更测试:只有用户明确要求测试时才用target_branch=build-test,并必须搭配bump=none,避免彩排消耗版本号:
gh workflow run release.yml --ref <branch> \ -f bump=none -f base_branch=<branch> -f target_branch=build-test

dry_run=true只预览版本变化;auto_merge=false停在“准备发布 PR”这一步。

  • 续跑失败发布:任何环节失败(包括main已前进但 tag 未打)后,用bump=none重跑即可——版本已到base_branch,无需再 bump,直接进发布任务,发布门禁同时处理“main 未动”与“main 已动但缺 tag”两种形态。

Deploy Docs:独立重部署文档站

独立的Deploy Docs工作流不触发发布,只把文档站重新部署到 Vercel 生产:

gh workflow run deploy-docs.yml -f ref=develop

它只能部署源码 ref(默认develop),不能部署main——发布树已删掉docs/packages/,而 docs 应用是依赖根目录packages/构建的(docs/tsconfig.jsoncadjs/*映射到../packages/cadjs/src/*)。工作流前置检查这两者并给出明确报错。要重放某次历史发布的站点,用该发布源提交:每次发布提交的第二父提交即发布源,例如git rev-parse <tag>^2

镜像 CAD Viewer 仓库

viewer/会被发布为独立的 cad-viewer 仓库:Release在发布main之后调用Sync CAD Viewer Repo,从发布源提交(而非不含viewer/main)镜像。可单独派发:

gh workflow run sync-cad-viewer.yml -f ref=develop gh workflow run sync-cad-viewer.yml -f ref=develop -f dry_run=true

该镜像是一次直拷贝:不重写任何路径/命令/文本,唯一结构性变化是把viewer/packages/*解引用为真实目录,脚本拒绝发布仍含 symlink 的树。推送前会在镜像内跑npm cinpm run testnpm run buildpip install -r requirements.txtserver_py测试,镜像站不住脚则发布失败。它需要CAD_VIEWER_SYNC_TOKEN(对镜像仓库有contents:write)。本地同步/查漂移可用 scripts/viewer/sync-cad-viewer-repo.sh。

本地手动兜底

与工作流同款脚本的本地发布准备:

git fetch origin develop git fetch --tags origin scripts/release/bump-version.sh patch --no-commit node scripts/release/sync-version.mjs scripts/release/check-version.sh --incremented-from origin/main node scripts/release/sync-version.mjs --check

scripts/release/publish-github-release.sh 是 tag 与 GitHub Release 步骤的手动兜底,与工作流不同,它默认创建草稿,除非传--publish。同时建议配置仓库规则集:main拒绝 PR 与直接 push(只留Release发布任务这个唯一写入口)、为[0-9]*.[0-9]*.[0-9]*开启 tag 规则集。

仓库硬规则:Skill 自包含、包边界与产物纪律

Skill 运行时自包含

每条 Skill 在运行时必须自包含且独立:不得引用、导入或依赖另一条 Skill、skills/根目录或仓库根模块的代码。禁止把skills/、仓库根或兄弟 Skill 目录加入sys.pathPYTHONPATHNODE_PATH等运行时查找路径。共享运行时助手必须放在packages/作为唯一事实源,再通过打包/生成流程 vendor 进各消费 Skill 的运行时;packages/cadgen这类共享 Python 工件也应走捆绑包路径,而非兄弟 Skill 导入。开发 symlink 只是 checkout 布局便利,不改变这条运行时约束。

包间依赖方向

  • packages/cadjs必须保持可复用、非 React;App 的 UI 与工作流状态属于viewer/
  • packages/implicitjs必须保持可复用、非 React,且绝不 importcadjs。依赖单向流动:cadjs依赖implicitjs并在cadjs/implicit/*下再导出其共享渲染/导出 API,因此消费方(CAD Viewer、快照工具)只装cadjs即可;
  • viewer/必须完全自包含:其下任何内容不得引用上层路径/命令/文档,因为它是被逐字镜像进独立 cad-viewer 仓库的,无重写步骤。viewer/scripts/selfContained.test.mjs 在每次测试运行中强制这一点。

产物与脚本纪律

  • 所有测试、样本、永久与生成的 CAD/机器人描述产物(STEP/STP、STL、GLB、DXF、URDF、SRDF、SDF)一律写入models/,禁止另建临时产物目录;
  • scripts/只放长期有效的仓库命令,临时一次性脚本放tmp//tmp
  • 源码变更影响生成运行时后,用主打包包装器 scripts/bundle/bundle.sh 刷新或校验:
scripts/bundle/bundle.sh # 同步版本元数据并打包所有生产输出 scripts/bundle/bundle.sh --check # 打包到 tmp/,若已提交输出过期则失败 scripts/bundle/bundle.sh --clean # 先清理临时打包目录

bundle.sh先调用sync-version.mjs同步版本元数据,再委托 scripts/bundle/bundle-skill.sh 按scripts/bundle/skills/bundle-<skill-id>.sh逐个 Skill 打包(--all遍历全部、--print-outputs输出生成路径供检查脚本使用)。低层 bundle 脚本只在调试包装器本身时使用。

  • Git 卫生:不提交.venv/node_modules/、缓存、tmp/、本地凭据与打印机配置;生成运行时的变更应来自生产输出流程而非手工编辑生成目录。

开发环境与轻量 worktree

  • CAD Python 工作优先使用./.venv/bin/python(CONTRIBUTING.md 建议python3.12 -m venv .venv后安装requirements-dev.txt);
  • 默认保持新分支 checkout 与 git worktree 轻量化:不通过.worktreeinclude复制.venv/models/;仅当工作流需要 Python 依赖时才在 worktree 内重建.venv/
  • worktree 中若明确需要开发 symlink 布局,先scripts/dev/setup-symlinks.sh --check再有意执行scripts/dev/setup-symlinks.sh;不要在 Codex / Claude Code 的启动 hook 里自动修复布局;
  • models/只在用户要求或任务明确针对其下文件时才水合:优先用本地 Git LFS 缓存git lfs checkout <path>git lfs checkout models,仅在明确需要且本地缓存缺失时下载 LFS 对象;
  • 只为正在改动的工作流安装依赖。

检查体系:先小范围,后全量

原则是“跑覆盖本次改动的最小路径定向检查”,触碰共享面或交接前再跑全量包装器:

scripts/test/test.sh # 代码测试总入口 scripts/test/test-js.sh # 聚焦 JS 测试 scripts/test/test-docs.sh # 聚焦文档测试 scripts/test/test-python.sh # 聚焦 Python 测试 scripts/test/test-global.sh # 聚焦全局测试 scripts/dev/setup-symlinks.sh --check # 开发 symlink 布局 scripts/release/check-version.sh # 规范版本号 scripts/bundle/bundle.sh --check # 生成运行时新鲜度

包级与站点检查:npm --prefix packages/cadjs testnpm --prefix packages/implicitjs testnpm --prefix viewer run testnpm --prefix viewer run buildnpm --prefix docs run check;定向 Python 测试用./.venv/bin/python -m unittest <changed test paths>(测试按tests/python/skills/<skill>packages/<package>viewer/<service>global分组)。CI 中test.yml在独立 job 校验规范版本号(版本元数据错了代码测试仍能跑),并在测试 job 里校验 develop symlink 布局、对比生成输出与源码、临时打包生产输出、再对产物跑文档与代码测试。

CAD Viewer 调试实战

URL 语义:PATH 即绝对目录

Viewer 的 URL PATH 就是它打开的绝对目录,与file://URL 一致;?file=在该目录内选择一个工件:

http://127.0.0.1:3245/absolute/model/root?file=path/relative/to/that/root

Windows 下盘符是路径的一部分(前导斜杠之后、使用正斜杠):D:\project\models对应.../3245/D:/project/models。Viewer不是针对某个目录启动的——它打开 URL 命名的任何内容,因此一个实例可服务其服务根下的任意文件夹。worktree 场景下这很关键:从另一个 checkout 启动的实例按它自己的根解析路径,指向别的 clone 的绝对路径会直接“not found”,面板报告该文件在此 viewer 根之外。如果其他 checkout 的 Viewer 已占用默认端口,请为本工作区另起一个空闲端口实例(--port <n>),而不是把运行中的实例指向你的路径。

查看仓库 fixture 时,一律用models/目录作为路径并保持永久/生成文件放此处,且必须用绝对路径——Viewer 从任意工作目录启动,相对路径会解析错位置。除非用户要求,不要停掉别人的 Viewer。

改了源码不生效?先怀疑 Vite 缓存

编辑viewer/packages/cadjs源码却看不到变化,很可能是 Vite 的服务端 transform 缓存比 HMR 和硬刷新都“长寿”——磁盘文件已正确,浏览器却一直服务旧模块。重启 dev server 并删除viewer/node_modules/.vite即可。

Dev 默认、Prod 只用于 e2e

迭代用devserver——Vite 从源码直接服务客户端并带 HMR,viewer/packages/cadjspackages/implicitjs的改动即时可见:

npm --prefix viewer run dev -- --host 127.0.0.1 --port <n> # 然后打开 http://127.0.0.1:<port><repo>/models?file=<path>

prod路径只用于对发布 bundle 的端到端测试,或用户明确要求测 prod。它由 Python 后端(cad-viewer Skill 的start命令)服务构建好的dist/,所以先构建:

npm --prefix viewer run build npm --prefix viewer run start -- --host 127.0.0.1 --port <n>

端口行为

devstart都监听--port,默认3245;两者都不会滚动到其他端口——端口被占则直接报错退出,所以 Viewer 总在你要求的端口上。传--port <n>可同时跑多个实例。打包版 Viewer 的运行时与交接细节见 skills/cad-viewer/SKILL.md,其检查属于生成输出检查,走主打包包装器。

轻量 worktree 里启动 Viewer 的四个坑

cad-viewer Skill 文档描述的是 PRODUCTION 运行时,假设是已水合的 checkout;而轻量 worktree 刻意不带node_modules和构建产物,其“一行命令”会连续失败四次,且每次报错都不指向真正原因:

  1. npm --prefix skills/cad-viewer/scripts/viewer run startCannot find package 'cadjs'——skills/cad-viewer/scripts/viewer是指向viewer/的 symlink,打包运行时仍需要 worktree 自己的模块;
  2. 链接好模块后服务能起、CAD API 有响应,但/返回 404——start服务的是预构建 bundle,而 worktree 还没有viewer/dist。活着的后端配缺失的前端,看起来像坏链接而非缺构建;
  3. npm --prefix viewer run build再逐个裸 specifier 失败——implicitjsthreemeshoptimizer,都来自packages/cadjs/src/...
  4. meshoptimizerpackages/cadjs/node_modules下任何位置都不存在,仓库里唯一副本在docs/node_modules/meshoptimizer

从 worktree 根目录(<main>为主 checkout)正确补救:

ln -s <main>/viewer/node_modules viewer/node_modules mkdir -p packages/cadjs/node_modules ln -s ../../implicitjs packages/cadjs/node_modules/implicitjs ln -s <main>/packages/cadjs/node_modules/three packages/cadjs/node_modules/three ln -s <main>/docs/node_modules/meshoptimizer packages/cadjs/node_modules/meshoptimizer npm --prefix viewer run build npm --prefix skills/cad-viewer/scripts/viewer run start -- --host 127.0.0.1 --port <n>

务必用显式的空闲--port:从别的 checkout 启动的 Viewer 会按它自己的根解析路径,永远找不到这个 worktree 里的模型。

两个容易误判“模型坏了”的行为

  • 目录扫描跳过点目录.review/或其他点开头路径下的可构建条目,用直接?dir=查询能解析,但永远不会出现在项目根扫描结果里,Viewer 会报告“文件不存在”。可构建条目不要放进点目录;
  • 验证 Viewer 链接要“开页面”,不要 curl/__cad/asset:该路由只服务原始文件;生成条目的渲染包由另一条路由服务,所以探测它无论有无问题都返回 404。

Git 与 LFS 纪律

CAD 交换文件、生成渲染/topology 资源与assets/**可能由 Git LFS 跟踪。绝不git add、提交或其他写对象操作禁用 LFS 过滤器。本地 hooks 位于.githooks,通过 scripts/git-hooks/pre-commit 委托构建检查。assets/**存放重型演示 GIF,被排除在默认 LFS 拉取之外,仅在本地需要演示素材时执行git lfs pull --include="assets/**"水合。

上手路径小结

  • 开发环境:从develop切分支 → 建.venvscripts/dev/setup-symlinks.sh建立 symlink 布局 → 编辑skills/<skill>/packages/源码;
  • 本地联调 Skill:用 scripts/install/install-skills.sh(--agent codex|claude|gemini|universal|project--all全装)把 checkout 的 Skill symlink 进 Agent,改完立即生效;卸载用 scripts/install/uninstall-skills.sh,只移除指向本 checkout 的链接;
  • 验证:先跑最小定向检查,再scripts/test/test.shscripts/bundle/bundle.sh --check
  • 发布:只通过Release工作流,由develop构建、main发布,VERSION是唯一版本事实源,绝不手工改衍生版本。

生产用户从main克隆安装,贡献者则把developRelease工作流当作通往main的唯一路径——这条“分支开发、symlink 迭代、单管线发布、检查前置”的工程闭环,正是 text-to-cad 能同时服务多种 Agent 安装器而又不丢文件的关键所在。

【免费下载链接】text-to-cadA library of agent skills for CAD, CAE and CAM项目地址: https://gitcode.com/GitHub_Trending/tex/text-to-cad

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

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

沈阳高精度绿地数据处理:解压、投影拼接与拓扑质检全攻略

简介&#xff1a;沈阳高精度绿地数据是一套基于WGS1984坐标系、以栅格图像为核心的GIS地理信息资料&#xff0c;适用于城市规划、环境监测、生态研究和GIS教学等需要精细分析绿地覆盖的从业者与学生。压缩包共7个文件&#xff0c;涵盖tif栅格主数据、tfw世界文件、xml元数据与辅…

作者头像 李华
网站建设 2026/9/14 17:36:09

LangGraph与AutoGen多智能体框架选型指南

1. 多智能体框架的技术选型困境在构建基于大语言模型&#xff08;LLM&#xff09;的复杂应用时&#xff0c;开发团队常常面临一个关键决策&#xff1a;如何在LangGraph和AutoGen这两个主流多智能体框架之间做出选择&#xff1f;这个问题看似简单&#xff0c;实则涉及技术架构、…

作者头像 李华
网站建设 2026/9/14 17:36:09

Buzz 离线语音转文字:10 分钟跑通本地 Whisper 部署与字幕制作

Buzz 离线语音转文字&#xff1a;10 分钟跑通本地 Whisper 部署与字幕制作 【免费下载链接】buzz Buzz transcribes and translates audio offline on your personal computer. Powered by OpenAIs Whisper. 项目地址: https://gitcode.com/GitHub_Trending/buz/buzz Bu…

作者头像 李华
网站建设 2026/9/14 17:35:59

Flutter鸿蒙应用负载与功耗问题定位实战指南

做鸿蒙上的Flutter性能问题&#xff0c;最头疼的不是代码本身&#xff0c;而是“不知道去哪看数据”。同样一个App&#xff0c;在Android上跑得好好的&#xff0c;换到鸿蒙上就出现发热、掉帧、后台耗电异常&#xff0c;而且排查工具链跟以前完全不一样&#xff0c;adb那套指令…

作者头像 李华
网站建设 2026/9/14 17:35:40

Unity生态模拟系统设计:状态机+Job System+UI Toolkit实战

简介&#xff1a;这是一套基于Unity引擎开发的环保主题挂机类游戏完整源码项目&#xff0c;面向C#游戏开发初学者与Unity休闲游戏实践者&#xff0c;提供从点击交互、资源循环到离线收益的典型Idle Tycoon架构实现。资源共2000个文件&#xff0c;包含187个C#脚本&#xff08;核…

作者头像 李华
网站建设 2026/9/14 17:35:34

Java开发者就业方向与技术趋势全解析

1. Java开发者的主流就业方向解析Java作为一门拥有28年历史的编程语言&#xff0c;其就业市场已经形成了非常成熟的细分领域。根据我过去五年对招聘市场的持续观察和技术社区的数据分析&#xff0c;当前Java开发者最主要的就业方向可以归纳为以下六大类&#xff1a;1.1 企业级应…

作者头像 李华