# Publishing 本仓库是普通 DSH bundle:`package.json` 声明 `dsh.bundle.patch`、入口、依赖、Node 范围和发布白名单。`cordis.patch.yml` 隔离原 `ptc-runtime` 的服务,并插入 `ptc-plus-execution`(`dsh-ptc-plus/execution-provider`)与 `ptc-plus`(`dsh-ptc-plus`)两项;安装时保留完整 bundle。插件自带的运行时依赖由 npm 包声明;必须与宿主共享实例的 DSH service 包声明为 peer dependencies,并由宿主按 `inject` 装配。 `npm run build` 生成 Client bundle,以及私有编译器使用的 `compiler-core.cjs`、`compiler-platform.cjs`、按需加载的 `compiler-amaro.cjs`、`compiler-typescript.cjs` 和对应 source maps。依赖中的大型字符串参数由构建提取为 `compiler-asset-*.txt`,`compiler-assets.json` 拥有精确加载清单,避免 WASM 等数据同时驻留于源码与字面量池。这些编译器产物由 `scripts/compiler-bundle.mjs` 从源码紧凑生成,并列入发布白名单;不能手工修改生成文件。构建同时核验编译器源码所导入的必需平台成员。`npm run build:check` 同时比较 Client、编译器和资源产物,`prepack` 通过该检查阻止陈旧产物进入 tarball。源码验证还须把私有 realm 的执行映射回原始编译器文件,不能只统计调用服务的外层代码。 ## 命名约定 项目在不同集成层使用不同名称: | 名称 | 用途 | | --- | --- | | `dsh-ptc-plus` | 仓库和 npm 包名;浏览器 bundle 的 module name 也从 `package.json` 取得它。 | | `ptc-plus` | DSH 插件 ID、运行时 loader name 和 settings namespace。 | | `PTC Plus` | 面向用户的产品名。 | 在 `cordis.patch.yml` 和解析后的 DSH 配置中,`id: ptc-plus` 标识插件配置项,`name: dsh-ptc-plus` 标识待加载的包。内部错误前缀、runtime context 名称和 worker 临时路径会按所属子系统使用 `ptc-plus` 或 `dsh-ptc-plus`;它们不是另外的公开产品名。 ## 发布权限与流水线 npm 发布遵循 [ADR 0022](adr/0022-stage-npm-releases-with-oidc.md),使用 `.github/workflows/release.yml` 声明的 Trusted Publisher,不向 GitHub 保存 npm write token。npm package settings 必须把 publisher 精确绑定到 `muyuanjin/dsh-ptc-plus`、workflow filename `release.yml` 和 environment `npm-release`,且只允许 `npm stage publish`。Publishing access 选择页面中最严格且标记为 recommended 的 2FA 选项;npm 文档称其为 `Require two-factor authentication and disallow tokens`,当前 npm 页面也可能显示 `Require two-factor authentication and disallow bypass 2fa tokens (recommended)`。不要从滚动变化的标签推断账户中已不存在传统 token。OIDC 只把经过验证的 tarball 放入 npm staging,维护者仍须在 npm CLI 或 npmjs.com 检查 staged package 并以 2FA approve,包才会进入公开 registry。 普通 `CI` 只在 `main` push 或 pull request 包含非纯文档变更时运行:只改动 `**.md`、`assets/**` 或 `LICENSE` 的提交不触发矩阵。发布 commit 因包含 `package.json` 与 `package-lock.json` 变更必然产生一次 `main` push run,Release workflow 仍要求该 commit 有成功的 run 才继续。发布前创建 annotated `v` tag,原子推送 release commit 与 tag,等待该 commit 的 `CI` 成功,然后以该 tag 作为 ref 显式运行 `Release` workflow。workflow 不接受另一个 tag input,并会重新证明 dispatch 的 `GITHUB_REF`、`GITHUB_SHA`、annotated tag target、checkout HEAD、manifest 版本和成功 CI 的 SHA 完全一致;release job 使用 GitHub-hosted Node `24.15.0`、npm `12.0.2`、无 package-manager cache 和最小 `id-token: write` 权限,构建一个 tarball、执行使用同一冻结宿主 peer 图的 clean-consumer smoke,再对同一文件执行 `npm stage publish`。`package.json#allowScripts` 显式拒绝当前不需要的 `esbuild` install script;`replace-registry-host=always` 让 release install 将 lockfile 中的 registry tarball 路由到显式 npm 官方 registry,而不放宽 npm 12 的 Git/remote dependency 默认拒绝。 ```powershell git tag -a "v$((Get-Content package.json | ConvertFrom-Json).version)" -m "v$((Get-Content package.json | ConvertFrom-Json).version)" git push --atomic origin main "v$((Get-Content package.json | ConvertFrom-Json).version)" gh workflow run release.yml --ref "v$((Get-Content package.json | ConvertFrom-Json).version)" ``` workflow 成功只表示 package 已 staged,并非已经公开发布。维护者从 workflow 日志或 npmjs.com 的 Staged Packages 页面取得 stage id,检查 metadata 和下载的 tarball 后执行: ```powershell npm.cmd stage view '' --json --registry=https://registry.npmjs.org/ npm.cmd stage download '' --registry=https://registry.npmjs.org/ npm.cmd stage approve '' --registry=https://registry.npmjs.org/ ``` `npm stage approve` 必须完成 npm 2FA。approve 后 npm 会进行 publish-time malware scan;公开可安装通常延迟约 5 分钟,高峰或需进一步检查时可能超过 15 分钟。发布自动化必须轮询明确版本并允许该延迟,不能把 approve 返回等同于 registry 已可安装。扫描确认版本可用后再发布对应 GitHub Release。staged 内容错误时使用 `npm stage reject ` 并完成 2FA,不能移动既有 tag 或用同一版本覆盖。 首次 OIDC staging 成功后,检查 npm 账户的 Access Tokens,并撤销所有仍可对本包执行 publish 或 stage 的 granular/automation token,尤其是 bypass-2FA token;在 Trusted Publisher 尚未实测成功前保留恢复路径,不能把未验证的凭据切换当成完成。后续 workflow 不保存或读取 npm token,定期清点用于发现账户侧重新引入的发布凭据。 ## Release checklist 1. 提交前在稳定工作树上运行完整 `npm run check`,执行无覆盖插桩的完整普通后端测试并生成 review proof。覆盖率只在准备发布新版本时运行;Release workflow 在打包与 npm staging 前对 release tag 执行 `npm run coverage`,要求行与函数覆盖率 100%、分支覆盖率至少 95%。发布准备期间可在本地运行同一命令,并用 `npm run coverage:focus` 诊断覆盖率缺口;日常开发、审查与提交不运行覆盖率专用套件、采集探针或插桩分支;这些测试由 `test/coverage/` 和发布入口的显式标记拥有。仓库 CI 在 Linux Node `22.19.0`、24.x、26.x,以及 Windows 与 macOS Node 24.x 的干净安装上运行 `npm run verify:ci`,检查构建、Client 与跨平台关键运行契约;Ubuntu Node 24.x 另运行打包后的 `latest` / `next` Host contracts。普通 CI 不收集 coverage 或执行穷尽式后端套件。 2. 运行 `npm audit --omit=dev`、`npx publint`、`git diff --check`、Markdown local-link check 和 `npm pack --silent --dry-run --json`。audit 检查随包安装的 production 依赖图;宿主 DSH 及其开发依赖不进入插件 tarball,由冻结宿主契约和 CI 单独验证。确认 tarball 只包含发布白名单内的运行时代码、文档和展示资产,不含凭据、本地路径、开发脚本或测试夹具,并执行 `npm run test:package:consumer -- `:入口先校验当前安装的宿主与其 lock 一致,再将宿主实际提供的 peer 版本与 tarball 放在同一次 npm 安装事务中,在空目录执行 ESM import、内置编译器栈与内核 worker 加载 smoke。不能让 npm 对各宿主 peer 分别选用 dist-tag;插件继续声明不限制版本的 required peers,不私装宿主服务副本。机器读取 `npm pack --json` 时保持 `--silent`,避免 lifecycle 输出混入 JSON stream。 3. 更新到最新可用 DSH release 并记录 `dsh --version`。分别从 npm 包、固定 Git commit、源码 checkout 和 tarball 安装到临时 profile,再执行 `dsh --profile --dump-config`,确认与 `cordis.patch.yml` 一致:新增 `ptc-plus-execution`、`ptc-plus` 两项,并将原 `ptc-runtime` 的 `ptcRuntime` 服务隔离到 `ptc-plus-original`。每个上游 release 都重新验证公共扩展面、CLI/Web 集成和 profile 装配,并核对 `engines.dsh` 的上下界;范围内的宿主升级保留现有边界,运行时不按版本号选择接口。 4. 在 Windows 与 Linux 运行无模型调用的 `npm run test:client:web -- --dsh-entry `,验证 tarball 安装后的真实 Web Client、设置与对话 surface;浏览器前置条件见 [安装指南](installation.md)。`build:check`、Host ESM import 和 factory smoke 均不能替代浏览器激活验收。macOS 由原生 runner 验证 CLI/Web;Windows 与 macOS Desktop 从托盘打开当前 profile 的 DSH Terminal 安装,重启 Desktop 后做一次 PTC 模式 smoke。Desktop 当前发布平台不包括 Linux。界面有变化时用同一前置条件刷新 README 截图:`npm run readme:screenshots -- --dsh-entry ` 从当前打包候选各写回一帧中英文 REPL 工作台与设置窗口;先用 `--out ` 落到别处检查,命令、前置条件与失败边界见 [安装指南](installation.md)。 5. 只有在明确授权模型消耗后才运行 `npm run test:expensive` 与 `npm run test:ab`;发布候选还要用 `DSH_PTC_ACCEPTANCE_SCENARIOS=managed-adaptive-surface,managed-session-resume,managed-surface-change,subagent-continuity` 追加托管能力面、会话恢复、宿主表面变化与子代理场景(运行方式、预算与版本差异判别见[评估](evaluation.md#managed-session-continuity-cohort))。发布结论以结构化测试结果为准,不把一次模型样本推广为普遍保证。 6. 确认 npm 包名可用、待发布版本高于 registry 版本、README 截图来自真实 DSH 会话,并核对 repository、homepage、bugs、license 与 `dsh-plugin` topic。 7. 最后检查 `npm pack --silent --json` 的名称、版本、大小与文件列表,创建 annotated release tag,并确认 tag commit 已通过 `CI`。运行 `Release` workflow 将同一源码产生的 tarball送入 npm staging;人工检查并以 2FA approve 后,等待 registry 扫描完成,再创建 GitHub Release。Release notes 的内容取舍与风格由 [release-notes.md](release-notes.md) 拥有。 远程仓库、registry、签名凭据、目标平台运行状态和模型额度都属于发布时事实,不能由本地 manifest 推断。 ## Permission disclosure PTC Plus 自身不配置外部 endpoint,也不读取 API key。它让模型代码使用当前 request 的 DSH native tools,并在插件自有 helper/worker 进程和操作系统实际允许时直接使用 Node.js filesystem、process、network 与 child process API。DSH 负责 native-tool policy;ambient Node/OS access 不经过该 policy。会话 worker 运行在插件自有 helper 进程内,但 worker/helper 边界是生命周期隔离,不是恶意代码安全沙箱。 DSH 当前公共 bundle surface 未定义供插件使用的机器可读 permission-disclosure contract,因此这些权限边界记录在人类可读文档中。 ## Client UI 发布包包含设置卡片和会话头部启用标识的 Client UI。发布截图必须来自 DSH Web 或 Desktop 中真实的 PTC 模式 surface;实现与构建边界见 [Client UI](client-ui.md)。