ZCode 的工程纪律以 spec-first + 单一状态所有者 + 类型/引用边界 为核心,通过两层 AGENTS.md + architecture skill + pre-push 三段门禁落地。

版本锚点与工具链

工具版本来源
Node>=24.0.0,精确 24.14.0根 package.json、mise.toml
pnpm10.33.2package.json、mise.toml
TypeScript根 ^6.0.2,CLI 子库 ^5.9.0各自 package.json

mise.toml 是权威版本源(AGENTS.md 明确”Node 版本以 mise.toml 为准”),还定义环境变量与 6 个 task 包装器(经 scripts/mise-run.mjs 注入工具链环境)。.npmrc 使用 node-linker=hoisted(SEA 打包依赖)。

构建编排:分层(根 pnpm,CLI turbo)

  • 根没有 turbo.json。根编排靠 pnpm:build = pnpm -r build;build:bootstrap = 过滤所有 packages/* 排除 desktop,再单跑 @zcode/desktop build:no-runtime-assets。
  • 唯一 Turbo 配置在 apps/zcode-cli/turbo.json:定义 build(dependsOn:["^build"],带 cache)、build:desktop-agent、test/coverage(dependsOn:["build"])、typecheck、dev、clean,以及 @zcode/cli#build override。
  • scripts/build-desktop-agent-cli.mjs 默认不走 turbo,而按显式有序包清单逐个 pnpm --filter <pkg> build(原因:Linux 容器 demo 无仓库级 turbo 根,turbo --cwd apps/zcode-cli 会把子目录当根并拒绝指向 ../../packages/shared 的 inputs)。
  • TS 用 project references 全链路:tsconfig.base.json 的 composite:true、declaration+declarationMap+sourceMap、module/moduleResolution: nodenext、target/lib: es2024、verbatimModuleSyntax、noUncheckedIndexedAccess。根 typecheck 是一条显式列 15 个入口的复合 tsc -b。

关键构建脚本(scripts/,80+)

脚本作用
bootstrap.mjsgit submodule update --init(CLI 是 submodule)+ pnpm install + prepare:desktop-runtime(默认跳过远程资源)+ build:bootstrap
build-zcode.mjs统一 Node 分发包:构建 CLI 闭包 → server → web → 组装 → tar.gz + sha256 + latest.json + install.sh
build-desktop-agent-cli.mjs按有序清单构建 12 个 CLI 包 + 2 个必需插件 runtime + 暂存 bundled-agents/
dependency-graph.mjs / dep-refs.mjs生成 mermaid/dot/json 依赖图 / ts-morph 精确查 export 引用
count-lines.sh找 >400 行的 .ts
clean.mjs安全删 node_modules/dist(含路径断言)
assert-node-version.mjs强制 Node ≥ 24
native-search-tools-*.mjs(8 个)rg/bfs/ugrep sidecar 构建与打包

其余:build-sea、build-native-search、prepare-prebuilds、download-glm、third-party-notices、zcode-distribution/{assets,installer,runner}、dev-desktop-env、run-affected-unit-tests、release-it/*、architecture/*。详见 distribution。

架构治理

策略模型(architecture-policy.yaml,195 行)

可执行的组织级契约,version: 1,三类要素:

  • modules(35+ 条):每条含 id/roots/managed/requires/publicEntrypoints/layers/layerOrder/owner。存量模块多标 managed:false;已迁移的 managed:true 模块:storage、gen-ui-protocol/gen-ui-service/gen-ui、mcp-apps-protocol/mcp-ui/plugin-ui-bridge/plugin-sandbox/plugin-ui。
  • global 限额:maxFileLines: 400、maxContractLines: 300、maxPublicMethods: 12、forbidCycles: true、forbidDeepImports: true、managedOnly: true。
  • exceptions:仅两条,都针对 genUiTweakRuntime.js(放宽行数与 disable-count),各带 reason。

检查器(scripts/architecture/)

architecture-check.mjs(CLI:check/report/baseline:update/context,支持 --changed)+ index.mjs(规则引擎)实现:

  • missing-module-artifact:managed 模块须有 module.ts/contract.ts/contract.example.ts/contract.test.ts/CONTRACT.md 五件套
  • max-file-lines / max-contract-lines / max-public-methods
  • disable-count:禁止任何 oxlint-disable/eslint-disable
  • domain-io:domain 层不得 import node:/fs|path|http|https|net|child_process|timers,不得出现 fetch/setTimeout/setInterval
  • layer-direction:层序靠前的层不能依赖更靠后的层
  • ui-implementation-import:ui 模块不得直接依赖 repo/runtime/service 实现
  • module-dependency:跨模块 import 必须在 requires 中声明
  • deep-import:跨模块只能走 publicEntrypoints
  • cycle:DFS 环检测(仅 managed 模块间)

Ratchet baseline

.architecture-baseline.json 当前为空({"version":1,"violations":[]})。违规用 sha256(rule\0file\0detail)[:16] 指纹;命中 baseline 的是”存量”(不阻断),新指纹才 FAIL。--changed 从变更文件沿反向依赖图求影响闭包。baseline:update 只在显式调用时写盘,CI 从不自动刷新。

architecture-governance skill

.agents/skills/architecture-governance/SKILL.md:编码前先跑 architecture:check --changed 拿基线;跨模块/契约不明时跑 architecture:context <module-id>;强制五条设计决策(One owner / One path / Explicit boundaries / Explicit time / Bounded context)。

边界:managedOnly:true + 空 baseline 意味着零违规只保证已完成迁移的这批模块,不证明全部存量跨域依赖合规。

测试矩阵

层级入口运行器/隔离
单测pnpm test:unit / testVitest threads(unit)+ forks(fork-isolated)
覆盖率pnpm test:coverageVitest v8
affectedpnpm test:unit:affectedlint-staged + vitest run / vitest related
CLI 单测pnpm --dir apps/zcode-cli testTurbo + node:test + vitest
桌面 e2epnpm test:e2eWDIO Electron,Windows 分片
容器 e2epnpm test:e2e:container[:preset]Docker,replay-isolated 默认
native-search e2epnpm test:native-search:e2e独立 Bash toolcall
SEA runtime e2epnpm test:sea-runtime-tools:e2e单文件交付验证
架构测试pnpm test:architecturenode --test scripts/test/architecture-governance.test.mjs

规模(实测):根单测 1917 个、desktop WDIO e2e 417 个、managed contract test 7 个。单测与 e2e 通过 --exclude "packages/desktop/test/e2e/**/*.test.ts" 硬分层。

vitest.config.ts 定义两个 project:unit(threads,maxWorkers 4)与 fork-isolated(串行 forks)。forkIsolatedTests 手工白名单每个条目都对应一个真实故障(进程树/生命周期、electron-builder NSIS 下载、真 Git 子进程、pdfjs 原生崩溃等),带中文根因注释,是重点维护区。

vitest.setup.ts:Windows Git Bash PATH 修正、强制 core.autocrlf=false、固定 release target、删除 ZCODE_DATA_BASE_DIR 防误写真实目录、mock homedir。

Lint / Format / Hooks / Release

  • oxlint(.oxlintrc.json):核心规则只有一条 max-lines: ["error", {max:400, skipBlankLines:true, skipComments:true}];测试文件与 i18n locale 关闭;忽略 apps/zcode-cli、vendored UI、.agents/skills 等。不启用推荐规则集。
  • oxfmt(.oxfmtrc.json):fmt/fmt:check。
  • husky + lint-staged:.husky/pre-push 缓存 stdin(供 affected 取 remote sha)、unset $(git rev-parse --local-env-vars),然后 pnpm run verify:pre-push。
  • verify:pre-push = pnpm run lint && pnpm run architecture:check -- --changed && pnpm run test:unit:affected。
  • release-it:根 .release-it.mjs 提交 chore: release v${version} + tag + push,但关闭 github/gitlab/npm release;CLI 有独立 release 配置。

CI(GitLab,配置未随仓库导出)

重要事实:仓库没有 .github/,也没有 .gitlab-ci.yml。CI 是 GitLab,作业定义属闭源/未导出部分;scripts/ci/(如 ci-lint-pipeline.mjs)同样不在检出中。以下从文档还原:

  • 阶段(docs/desktop-ci-cd.md):test → build-app → build → notify → approve → validate → upload → preload → publish → release-notify。
  • 构建平台选择(docs/ci-build-platform-selection.md):变量 ZCODE_BUILD_PLATFORMS(六平台);MR 默认 macos-arm64,windows-x64;tag 与 ci/* 六平台全跑。
  • 缓存策略(docs/ci-cache-strategy.md):废弃 GitLab cache,改用 runner 工作区持久化(.pnpm-store/.npm-cache/.next/cache/mock-cdn 靠 GIT_CLEAN_FLAGS 排除项复用)。build:desktop:app 11m10s → ~25s,MR 流水线 ~34min → ~23min。
  • 飞书通知(docs/ci-feishu-card2-notification.md):notify:feishu:<platform>:<arch> 发 Feishu Card 2.0,经 zcode-internal 通用服务转发(CI 不持有飞书应用凭证)。

工程纪律(AGENTS.md)

根 AGENTS.md(82 行)核心:spec-first、以当前检出的源码/package.json/架构策略为准、先诊断后修改、保留无关本地改动、开工前跑 check-workspace-freshness.mjs、必跑 pnpm typecheck 和 pnpm lint 并报真实结果、避免重复状态和多条写入路径(不能用超时掩盖同步问题)、跨包导入用公开入口、平台操作走 IPlatformService、日志分层。

apps/zcode-cli/AGENTS.md(103 行):工具改动必须先读/更新 docs/design/v2/tool/00-tool-change-chain.md;单文件默认 ≤400 行;常量提取为命名变量;环境变量统一 ZCODE_ 前缀;外部 I/O 边界收敛(副作用必须可观察/审批/取消/重试/排队/审计/测试;业务模块不得直接调 fetch/http/fs/child_process/process.env);traceId 贯穿;错误是一等设计对象,底层不调 process.exit;每个功能级变更一个独立提交。

patches/

6 个补丁通过 pnpm.patchedDependencies 应用:vitest@4.1.7、wdio-electron-service@9.2.1、@arms/rum-electron@0.0.3、@ai-sdk/openai-compatible@2.0.60、@ai-sdk/anthropic@3.0.81、@open-pencil/core@0.14.0(磁盘存在但未登记)。pnpm.overrides 强制 react/react-dom = 19.2.7。

相关页面