diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d259e5..ff731e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,8 @@ name: CI -# 每次 push 到主分支、以及任何 PR 包括来自 fork 的 PR 都自动跑完整检查。 -# 本插件采用 TypeScript 源码与 tsdown 构建,CI 会安装锁定依赖并重建发布产物。 +# 每次 push 到主分支、任何 PR 包括来自 fork 的 PR 都自动跑完整检查。 +# 本插件是构建型:src/ 是源码,lib/ 是产物且不入库,因此 CI 必须装依赖再构建。 +# PR 检查即门禁:typecheck / build / smoke / 产物校验全绿才允许合并。 on: push: branches: @@ -11,56 +12,51 @@ on: branches: - main -# 同一分支/PR 上排队的新提交会取消正在跑的旧任务,避免资源浪费。 +# 同一分支或 PR 上排队的新提交会取消正在跑的旧任务,避免资源浪费。 concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: check: - name: 类型检查 · 构建 · 产物校验 + name: typecheck · build · smoke runs-on: ubuntu-latest - strategy: - matrix: - # 本地与线上主推的运行时;两个版本都验证一次。 - node: - - 22 - - 26 steps: - name: Checkout uses: actions/checkout@v4 - - name: 配置 pnpm + - name: Setup pnpm uses: pnpm/action-setup@v4 with: + # 版本必须与 package.json 的 packageManager 完全一致,否则 action-setup 会报 Multiple versions of pnpm specified。 version: 9.15.9 - - name: 配置 Node.js + - name: Setup Node uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node }} + # 与本地 node -v 锁死同一版本,见工作区 AGENTS.md 的 Node 版本约定。 + node-version: 26.3.1 cache: pnpm - - name: 安装依赖 + - name: Install dependencies run: pnpm install --frozen-lockfile - - name: 类型检查 + - name: Typecheck run: pnpm typecheck - - name: 构建 + - name: Build run: pnpm build - # 冒烟测试消费构建产物,验证 host RPC 与 client 注册的行为契约。 - - name: 冒烟测试 + # 编辑器面板与文件树的加载路径走冒烟脚本,单独跑一遍。 + - name: Smoke run: pnpm smoke - # 出厂文件齐全性校验,缺失会在此失败,让 PR 作者一眼看到问题。 - - name: 产物齐全性校验 + # 本插件是双半身且带 sourcemap,产物缺失会在此失败。 + - name: Verify build outputs run: | test -f lib/index.js test -f lib/index.d.ts test -f lib/client.js test -f lib/client.js.map test -f cordis.patch.yml - test -f package.json - echo "发布产物齐全" + echo "构建产物齐全:lib/index.js · lib/index.d.ts · lib/client.js · lib/client.js.map · cordis.patch.yml" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1245f1a..8882ad1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,8 @@ name: Release -# 推送形如 vX.Y.Z,如 v0.2.0,的 tag 时自动发版: -# 凭 tag 号更新 package.json 版本并提交回 main → 安装依赖 → 类型检查 → 构建 → 产物校验 -# → 发布 npm → 生成 GitHub Release draft。人只需打一个 tag,其余自动衔接。 -# 注意:npm 发布依赖 npmjs 侧开启的 Trusted Publishing -# npmjs.com → 本包 → Enable trusted publishing → 绑本仓库 GitHub Actions, -# 无需配置 NPM_TOKEN;未开启时发布步骤会失败。 +# 推送形如 vX.Y.Z 如 v0.1.0 的 tag 时自动发版:先把 package.json 版本兜底对齐到 tag 号,不一致才提交回 main → 类型检查 → 构建 → 发布 npm → 生成 GitHub Release draft。 +# 人只需打一个 tag,其余自动衔接。 +# 注意:npm 发布走 Trusted Publishing,无需 NPM_TOKEN;未在 npm 侧绑定信任关系时发布会失败。 on: push: tags: @@ -26,8 +23,7 @@ jobs: id-token: write # fork 永不触发 tag 发布,仅作为兜底防护。 if: startsWith(github.ref, 'refs/tags/v') - # 绑定 GitHub Actions environment「release」,使 OIDC subject 稳定为 - # environment:release,npm 侧 Trusted Publisher 需填相同 Environment 名。 + # 绑定 GitHub Actions environment「release」,使 OIDC subject 稳定为 environment:release,npm 侧 Trusted Publisher 需填相同 Environment 名。 environment: release steps: - name: Checkout @@ -38,11 +34,30 @@ jobs: # 默认 GITHUB_TOKEN 在分支保护下会被拒,此处显式传 token。 token: ${{ secrets.GITHUB_TOKEN }} - # 版本号仅凭 tag 号决定,写入 package.json 并提交回 main。 + # 前置守卫:仅当该 tag 版本尚未发布到 npm 时才继续发版。 + # 补历史 tag 时对应版本早已在 npm 上,重复 publish 会报错,且版本回写会把 main 改回旧号,故已发布则跳过后续所有步骤。 + # npm view 只读 registry,无需凭证。 + - name: Skip when tag version already published + id: published + run: | + set -euo pipefail + PKG="dsh-classic-coding" + TAG="${GITHUB_REF_NAME#v}" + if npm view "$PKG@$TAG" version >/dev/null 2>&1; then + echo "已存在 $PKG@$TAG,跳过发布" + echo "published=true" >> "$GITHUB_OUTPUT" + else + echo "未发布 $PKG@$TAG,继续" + echo "published=false" >> "$GITHUB_OUTPUT" + fi + + # 版本号以源码里的 package.json 为准,正常随改动一起提交,发版前与将要打的 tag 对齐。 + # 这一步只是兜底:忘改或写错时在此对齐 tag 号,再提交回 main。 - name: Sync version to main + if: steps.published.outputs.published != 'true' run: | set -euo pipefail - TAG="${GITHUB_REF_NAME#v}" # 去 v 前缀得版本号,如 0.2.0 + TAG="${GITHUB_REF_NAME#v}" # 去 v 前缀得版本号,如 0.1.0 echo "target version = $TAG" # 切到 main 分支再改版本,避免在 detached tag 上提交。 @@ -58,53 +73,64 @@ jobs: fs.writeFileSync('./package.json', JSON.stringify(p, null, 2) + '\n'); " "$TAG" - # 已是最新版本则无改动,跳过提交;否则提交并推回 main。 + # 兜底对齐后与 package.json 已一致则无改动,跳过提交;否则提交并推回 main。 git diff --quiet package.json || { git add package.json git commit -m "chore: release $TAG 同步 package.json 版本 [skip ci]" git push origin main } - - name: 配置 pnpm + - name: Setup pnpm + if: steps.published.outputs.published != 'true' uses: pnpm/action-setup@v4 with: version: 9.15.9 - - name: 配置 Node.js + # setup-node 的 registry-url 告知 npm 向哪个 registry 换 Trusted Publishing 临时凭证。 + # node-version 与本地 node -v 锁死同一版本。它同时满足 npm 官方 Trusted Publishing 的下限:捆绑 npm 需大于等于 11.5.1,否则 npm CLI 无法做 OIDC 自动换权,会回退用失效 token 导致 PUT 404 is not in registry。 + - name: Setup Node + if: steps.published.outputs.published != 'true' uses: actions/setup-node@v4 with: - # node-version 24 保证捆绑 npm>=11.5.1,npm CLI 才能做 Trusted Publishing 的 OIDC 自动换权; - # registry-url 告知 npm 向哪个 registry 换临时凭证,二者缺一不可。 - node-version: 24 + node-version: 26.3.1 cache: pnpm registry-url: https://registry.npmjs.org - - name: 安装依赖 + - name: Install dependencies + if: steps.published.outputs.published != 'true' run: pnpm install --frozen-lockfile - - name: 类型检查 + - name: Typecheck + if: steps.published.outputs.published != 'true' run: pnpm typecheck - - name: 构建 + # 编辑器面板与文件树的加载路径走冒烟脚本,单独跑一遍。 + - name: Smoke + if: steps.published.outputs.published != 'true' + run: pnpm smoke + + - name: Build + if: steps.published.outputs.published != 'true' run: pnpm build - - name: 产物齐全性校验 + # 本插件是双半身且带 sourcemap,产物缺失会在此失败。 + - name: Verify build outputs + if: steps.published.outputs.published != 'true' run: | test -f lib/index.js test -f lib/index.d.ts test -f lib/client.js test -f lib/client.js.map test -f cordis.patch.yml - test -f package.json - echo "发布产物齐全" + echo "构建产物齐全:lib/index.js · lib/index.d.ts · lib/client.js · lib/client.js.map · cordis.patch.yml" - # Trusted Publishing:npm 凭 workflow 的 OIDC 身份直接授权, - # 无需 NPM_TOKEN;--provenance 会在 npm 上附构建来源证明。 - # node-version 24 保证捆绑 npm>=11.5.1,npm CLI 才能做 OIDC 自动换权发布。 + # Trusted Publishing:npm 凭 workflow 的 OIDC 身份直接授权,无需 NPM_TOKEN;--provenance 会在 npm 上附构建来源证明。 - name: Publish to npm - run: pnpm publish --no-git-checks --provenance --access public + if: steps.published.outputs.published != 'true' + run: npm publish --provenance --access public - name: Create GitHub Release draft + if: steps.published.outputs.published != 'true' uses: softprops/action-gh-release@v2 with: draft: true diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..f301fed --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers=false diff --git a/cordis.patch.yml b/cordis.patch.yml index 5b28b9a..46f6239 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -1,8 +1,7 @@ -# dsh-classic-coding bundle patch: mount the classic-coding plugin. -# -# Applied when this bundle appears in a profile's dsh.profile.bundles list. -# The node half (package root) registers RPC endpoints for file system operations; -# the browser half (dsh.client) provides the Monaco editor + file tree overlay panel. +# dsh-classic-coding bundle patch:把 classic-coding 插件插进 profile 的 layer stack。 +# 当本 bundle 出现在 profile 的 dsh.profile.bundles 列表里时应用。 +# 主机端半身注册文件系统操作的 RPC 端点。 +# 浏览器半身提供 Monaco 编辑器与文件树浮层面板。 - insert: - id: dsh-classic-coding diff --git a/package.json b/package.json index 27b62ff..7130445 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "dsh-classic-coding", - "version": "0.2.1", - "description": "古法编程:在 DSH Web UI 中提供 Monaco 编辑器 + 文件树覆盖层面板", + "version": "0.2.2", + "description": "「DSH·古法编程」:在 DSH Web UI 中提供 Monaco 编辑器 + 文件树覆盖层面板", "keywords": [ "deepseek-harness", "dsh", @@ -11,6 +11,9 @@ "monaco" ], "packageManager": "pnpm@9.15.9", + "engines": { + "node": ">=26.3.1" + }, "type": "module", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -50,6 +53,9 @@ "typecheck": "tsc --noEmit", "smoke": "node smoke/verify.mjs" }, + "peerDependencies": { + "@deepseek-ai/dsh": "^0.1.7-rc.2" + }, "devDependencies": { "@types/node": "^22.0.0", "@types/react": "~18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94638f1..01725d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,7 +1,7 @@ lockfileVersion: '9.0' settings: - autoInstallPeers: true + autoInstallPeers: false excludeLinksFromLockfile: false importers: @@ -70,42 +70,36 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-arm64-musl@1.2.7': resolution: {integrity: sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - libc: [musl] '@rolldown/binding-linux-ppc64-gnu@1.2.7': resolution: {integrity: sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-s390x-gnu@1.2.7': resolution: {integrity: sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-gnu@1.2.7': resolution: {integrity: sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [glibc] '@rolldown/binding-linux-x64-musl@1.2.7': resolution: {integrity: sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - libc: [musl] '@rolldown/binding-openharmony-arm64@1.2.7': resolution: {integrity: sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==} @@ -161,37 +155,31 @@ packages: resolution: {integrity: sha512-QJXwIW6Ms3QIawbcBIedmrmXnfdpuAOjZJ/eAABq5XTzWvSxZ7lutu9W5yIHahlaTaFnBo7ikrVMD1szLTpPUw==} cpu: [arm] os: [linux] - libc: [glibc] '@yuku-codegen/binding-linux-arm-musl@0.9.5': resolution: {integrity: sha512-eHbFy3IHGb+IYarrYwAo0yWSEQV3eAmEn6VrsKA6I1Wy1YPJxWqSJlV69JhqsHtJuJlljUIF3ex0y46yaKIu9w==} cpu: [arm] os: [linux] - libc: [musl] '@yuku-codegen/binding-linux-arm64-gnu@0.9.5': resolution: {integrity: sha512-ByoJMbySTaDhjAXSu8q6Lh7HKg3YoesXpcT72aYk0Aiw4PCznmY4ybpLTq0RCvp0RIPhFm/6yECFiGBwyCC1nw==} cpu: [arm64] os: [linux] - libc: [glibc] '@yuku-codegen/binding-linux-arm64-musl@0.9.5': resolution: {integrity: sha512-gD9vfXIoBw1toSxhO9rgmSu/FEfy3PMznJAxVjIuH8DrWEiDKXmJO0pJKfj1Ltbe/TmtWVZR+TjISqeSIGQzMg==} cpu: [arm64] os: [linux] - libc: [musl] '@yuku-codegen/binding-linux-x64-gnu@0.9.5': resolution: {integrity: sha512-BARvdnvqMGjOr5Iel2JH+9H5vAIE0R6H0Z2fsT02xrvmI/1ZXNB8lkuX+ZGevPhZb3zJ9WeC/R8JZstrsUOK5g==} cpu: [x64] os: [linux] - libc: [glibc] '@yuku-codegen/binding-linux-x64-musl@0.9.5': resolution: {integrity: sha512-x8flcevS1fbb7ESrmpOY/pON4eInSaE/7Ktjqx2udOE2W33BNSZmJuwpyUgo54AoHNqrcaM7szqydyJn5fNvew==} cpu: [x64] os: [linux] - libc: [musl] '@yuku-codegen/binding-win32-arm64@0.9.5': resolution: {integrity: sha512-KOL/rBatWqH4ZpCNoF8ZtSNdOJbAxBJLmk/VeRciepGROPTbPum1A9t67GpFgOU7qrkUWlPJdJ+KHKbvbmOt+w==} @@ -227,37 +215,31 @@ packages: resolution: {integrity: sha512-b0afYK5gHeV8RdmOcqAlgM8ONsye4cax4DMnIBaoJyPMd1UTGvTbpkqQcPVdhmHlcfcGVGMV1laeVovlr/dscw==} cpu: [arm] os: [linux] - libc: [glibc] '@yuku-parser/binding-linux-arm-musl@0.9.5': resolution: {integrity: sha512-fD3lKzl+r6j6n8DwiMY53qnh5DLqD8KJjCp+NbVud54Nnh3Q9Wprqss3YzyMHP3NSJk663Wlg1E1X5qOuFVFig==} cpu: [arm] os: [linux] - libc: [musl] '@yuku-parser/binding-linux-arm64-gnu@0.9.5': resolution: {integrity: sha512-aRU/aCphV1MWCl/lvI6NX8LgucHQ68Fx+vz7NBb/5MEr2EuzCxiPOQqeFcMdWh+2AED/p0AvAREch0c+cSnlhA==} cpu: [arm64] os: [linux] - libc: [glibc] '@yuku-parser/binding-linux-arm64-musl@0.9.5': resolution: {integrity: sha512-5+Guro0l8H473YXlEjVNBRLN/IbPbJdnQh1zo0OLt49xxnON+XMJRRaEyTOTfkn9QSRg0+BhEKGR4W9Gu2uZJQ==} cpu: [arm64] os: [linux] - libc: [musl] '@yuku-parser/binding-linux-x64-gnu@0.9.5': resolution: {integrity: sha512-pwwSyV9q+GlvzSXlsMZBMlgk22L5bud714/vqZCdeUTivzeUVltQzUaf3IQXOGXdpc59JYTeuMCtbGquaAUoCA==} cpu: [x64] os: [linux] - libc: [glibc] '@yuku-parser/binding-linux-x64-musl@0.9.5': resolution: {integrity: sha512-z18j6JN3lBHH8vzN7gG1M8fI0nlgItSfnC9PfbmUbt97iHViKfw2iA2G9fGwRMe5LyPRZBrejIlapbygPbpdaw==} cpu: [x64] os: [linux] - libc: [musl] '@yuku-parser/binding-win32-arm64@0.9.5': resolution: {integrity: sha512-s6Gwttb1dQvtPX6Bgkw+UPC9IO3UBDXc6Zezog8MMgvu3UfJBBB9TQqKBX/2quu0Eyh+lLSAyNlIyyecaagUPg==}