Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"access": "public",
"baseBranch": "main",
"fixed": [["@ykdz/cli-contract", "@ykdz/cli-contract-testing"]]
}
5 changes: 5 additions & 0 deletions .changeset/next-round-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ykdz/cli-contract": minor
---

为命令提供独立的输出方式、契约发现与可验证的调用示例,并将契约清单升级到 5、结构化线协议升级到 3。最低运行环境升至 Node 26。
37 changes: 25 additions & 12 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,35 @@ ARG NODE_VERSION
FROM node:${NODE_VERSION}-bookworm-slim

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ARG PACKAGE_MANAGER_PIN
ENV COREPACK_HOME="/corepack"
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME/bin:$PNPM_HOME:$PATH"
# 覆盖镜像支持的两个用户,非交互命令也能直接执行全局工具。
ENV PATH="/root/.local/share/pnpm/bin:/home/node/.local/share/pnpm/bin:$PATH"
# @template-mirror pnpm-bootstrap
COPY --from=ghcr.io/pnpm/pnpm:12.9.1 /opt/pnpm /opt/pnpm
# @end-template-mirror
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& apt-get install -y --no-install-recommends \
bubblewrap \
ca-certificates \
curl \
file \
git \
iproute2 \
jq \
openssh-client \
procps \
python-is-python3 \
python3 \
ripgrep \
unzip \
&& rm -rf /var/lib/apt/lists/* \
&& git config --system init.defaultBranch main \
&& install -d -m 0755 "$COREPACK_HOME" "$PNPM_HOME" "$PNPM_HOME/bin" \
&& corepack enable --install-directory "$PNPM_HOME" \
&& corepack prepare "${PACKAGE_MANAGER_PIN}" --activate \
&& chmod -R a+rX "$COREPACK_HOME" "$PNPM_HOME"
&& for bin in pnpm pn pnpx pnx; do ln -s "/opt/pnpm/pnpm" "/usr/local/bin/$bin"; done \
&& install -d /pnpm/store/root /root/.local/share/pnpm \
&& install -d -o node -g node /pnpm/store/node /home/node/.local/share/pnpm \
&& pnpm config set store-dir /pnpm/store/root --global \
&& su -s /bin/sh node -c 'pnpm config set store-dir /pnpm/store/node --global'

RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& install -m 0755 -d /etc/apt/keyrings \
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \
Expand Down
5 changes: 1 addition & 4 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
{
"build": {
"args": {
"NODE_VERSION": "24",
"PACKAGE_MANAGER_PIN": "pnpm@12.1.0"
},
"args": { "NODE_VERSION": "26.13.0" },
"dockerfile": "Dockerfile"
},
"customizations": {
Expand Down
20 changes: 11 additions & 9 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ jobs:
with:
persist-credentials: false
fetch-depth: 1
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: package.json
package-manager-cache: false
- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- name: 读取 Node 版本
id: node-runtime
run: echo "runtime=node@$(jq -er '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
- name: 安装 pnpm 与 Node.js
uses: pnpm/setup@fa36a5ef7dcdefc3a7cb25655c122e00cf6e636e # v3.1.2
with:
runtime: ${{ steps.node-runtime.outputs.runtime }}
install: false
cache: true
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Root Check
run: pnpm run check
- name: Run Light Check
run: node --conditions=source scripts/task-gates.ts check
- name: Run Heavy Check
run: node --conditions=source scripts/task-gates.ts check:heavy
124 changes: 70 additions & 54 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,70 +1,86 @@
name: Release
name: 发布 npm 包

on:
workflow_dispatch:

permissions:
contents: write
id-token: write
permissions: {}

concurrency:
group: release
group: npm-publication-${{ github.repository }}
cancel-in-progress: false
queue: max

jobs:
publish:
name: Publish verified release candidate
pack:
name: 验收并打包
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
runs-on: ubuntu-latest
timeout-minutes: 45
timeout-minutes: 120
permissions:
contents: read
outputs:
pack-dir-artifact-id: ${{ steps.pack.outputs.pack-dir-artifact-id }}
steps:
- name: Checkout event commit
- name: 检出源码
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.sha }}
- name: Set up pnpm
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
- name: 读取 Node 版本
id: node-runtime
run: echo "runtime=node@$(jq -er '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
- name: 安装 pnpm 与 Node.js
uses: pnpm/setup@fa36a5ef7dcdefc3a7cb25655c122e00cf6e636e # v3.1.2
with:
cache: pnpm
node-version: 24
- name: Install dependencies
runtime: ${{ steps.node-runtime.outputs.runtime }}
install: false
cache: true
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: Verify release tag and package versions
env:
EVENT_SHA: ${{ github.sha }}
RELEASE_REF: ${{ github.ref }}
run: node --conditions=source scripts/validate-release-tag.ts "$RELEASE_REF" "$EVENT_SHA"
- name: Install supported npm
run: npm install --global npm@11.5.1
- name: Show npm version
run: npm --version
- name: Verify release candidate
id: candidate
shell: bash
run: |
candidate_directory="$(mktemp -d)"
candidate_result="$(pnpm --silent candidate:verify -- --output-dir "$candidate_directory")"
core_tarball="$(jq --raw-output '.coreTarball' <<<"$candidate_result")"
testing_tarball="$(jq --raw-output '.testingTarball' <<<"$candidate_result")"
test -f "$core_tarball"
test -f "$testing_tarball"
printf 'core_tarball=%s\n' "$core_tarball" >> "$GITHUB_OUTPUT"
printf 'testing_tarball=%s\n' "$testing_tarball" >> "$GITHUB_OUTPUT"
- name: Publish core package
env:
CORE_TARBALL: ${{ steps.candidate.outputs.core_tarball }}
run: npm publish "$CORE_TARBALL" --access public --tag latest --registry https://registry.npmjs.org
- name: Publish testing package
env:
TESTING_TARBALL: ${{ steps.candidate.outputs.testing_tarball }}
run: npm publish "$TESTING_TARBALL" --access public --tag latest --registry https://registry.npmjs.org
- name: Create GitHub Release
env:
CORE_TARBALL: ${{ steps.candidate.outputs.core_tarball }}
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ github.ref_name }}
TESTING_TARBALL: ${{ steps.candidate.outputs.testing_tarball }}
run: gh release create "$RELEASE_TAG" "$CORE_TARBALL" "$TESTING_TARBALL" --verify-tag
- name: 检查源码
run: pnpm run check
- name: 按依赖顺序构建
run: pnpm exec turbo run build
- name: 打包未发布版本
id: pack
uses: changesets/action/pack@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2
- name: 下载同批制品进行消费验收
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
artifact-ids: ${{ steps.pack.outputs.pack-dir-artifact-id }}
path: ${{ runner.temp }}/changesets-pack
- name: 验收 Changesets 原生制品
run: pnpm product:verify -- --pack-dir "$RUNNER_TEMP/changesets-pack"

publish:
name: 发布 npm 包和 GitHub Release
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
needs: pack
runs-on: ubuntu-latest
timeout-minutes: 60
environment: npm
permissions:
contents: write
id-token: write
steps:
- name: 检出源码
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: 读取 Node 版本
id: node-runtime
run: echo "runtime=node@$(jq -er '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
- name: 安装 pnpm 与 Node.js
uses: pnpm/setup@fa36a5ef7dcdefc3a7cb25655c122e00cf6e636e # v3.1.2
with:
runtime: ${{ steps.node-runtime.outputs.runtime }}
install: false
cache: false
- name: 安装依赖
run: pnpm install --frozen-lockfile --ignore-scripts
- name: 发布已验收制品
uses: changesets/action/publish@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
pack-dir-artifact-id: ${{ needs.pack.outputs.pack-dir-artifact-id }}
create-github-releases: true
push-git-tags: true
43 changes: 43 additions & 0 deletions .github/workflows/version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Changesets 版本 PR

on:
push:
branches:
- main

permissions:
contents: write
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
version:
name: 生成版本 PR
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: 检出主分支
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: 读取 Node 版本
id: node-runtime
run: echo "runtime=node@$(jq -er '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
- name: 安装 pnpm 与 Node.js
uses: pnpm/setup@fa36a5ef7dcdefc3a7cb25655c122e00cf6e636e # v3.1.2
with:
runtime: ${{ steps.node-runtime.outputs.runtime }}
install: false
cache: true
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 计算版本并生成版本 PR
uses: changesets/action/version@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: pnpm exec changeset version
pr-base-branch: main
4 changes: 1 addition & 3 deletions oxfmt.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
import { defineConfig } from "oxfmt";

export default defineConfig({ printWidth: 80, sortImports: true });
export { default } from "@cli-contract/tooling-config/oxfmt";
8 changes: 2 additions & 6 deletions oxlint.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import lintConfiguration from "@cli-contract/tooling-config/oxlint";
import { defineConfig } from "oxlint";

// OXC's current erasing-op rule does not reject enum, runtime namespace, or
// parameter properties. TypeScript 7 erasableSyntaxOnly is authoritative.
export default defineConfig({
options: { typeAware: true },
categories: { correctness: "error", suspicious: "warn" },
});
export default defineConfig({ extends: [lintConfiguration] });
31 changes: 17 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@
"private": true,
"type": "module",
"scripts": {
"boundaries": "node --conditions=source scripts/check-boundaries.ts",
"candidate:pack": "node --conditions=source scripts/create-pack-candidate.ts",
"candidate:verify": "node --conditions=source scripts/verify-release-candidate.ts",
"consumer:types": "node --conditions=source scripts/verify-typescript-consumer-matrix.ts",
"check": "node --conditions=source scripts/verify-release-candidate.ts --check",
"boundaries": "turbo boundaries",
"check": "node --conditions=source scripts/task-gates.ts check",
"check:full": "node --conditions=source scripts/task-gates.ts check:full",
"check:heavy": "node --conditions=source scripts/task-gates.ts check:heavy",
"check:workspace": "turbo run boundaries format:check lint typecheck build test test:e2e --continue=dependencies-successful --output-logs=errors-only --log-order=grouped --log-prefix=task",
"example:published": "node scripts/verify-example.ts --published",
"fix": "turbo run lint:fix format:write --continue=dependencies-successful --output-logs=full --log-order=grouped --log-prefix=task",
"format:check": "node --conditions=source scripts/run-root-owned-task.ts format:check",
"format:write": "node --conditions=source scripts/run-root-owned-task.ts format:write",
"lint": "node --conditions=source scripts/run-root-owned-task.ts lint",
"lint:fix": "node --conditions=source scripts/run-root-owned-task.ts lint:fix",
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
"consumer:types": "node --conditions=source scripts/verify-typescript-consumer-matrix.ts",
"example:published": "pnpm --filter @cli-contract/example run verify:published",
"fix": "node --conditions=source scripts/task-gates.ts fix",
"format:check": "oxfmt --list-different package.json README.md pnpm-workspace.yaml pnpm-lock.yaml turbo.json tsconfig*.json *.config.ts .gitignore .vscode .github .changeset/config.json .devcontainer scripts",
"format:write": "oxfmt --write package.json README.md pnpm-workspace.yaml pnpm-lock.yaml turbo.json tsconfig*.json *.config.ts .gitignore .vscode .github .changeset/config.json .devcontainer scripts",
"lint": "oxlint --quiet --format=unix *.config.ts scripts",
"lint:fix": "oxlint --format=unix *.config.ts scripts --fix",
"product:verify": "node --conditions=source scripts/verify-packed-release.ts",
"typecheck": "tsc --build --noEmit --pretty false"
},
"devDependencies": {
"@changesets/cli": "3.0.3",
"@cli-contract/tooling-config": "workspace:*",
"@types/node": "catalog:",
"oxfmt": "catalog:",
"oxlint": "catalog:",
Expand All @@ -26,7 +29,7 @@
"typescript-7": "catalog:"
},
"engines": {
"node": "24"
"node": "26.13.0"
},
"packageManager": "pnpm@12.1.0"
"packageManager": "pnpm@12.9.1"
}
17 changes: 10 additions & 7 deletions packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,25 @@
}
},
"scripts": {
"authoring:fixture:example": "cat src/index.ts",
"build": "tsc -p tsconfig.build.json --pretty false",
"format:check": "oxfmt --list-different --config ../../oxfmt.config.ts .",
"format:write": "oxfmt --write --config ../../oxfmt.config.ts .",
"lint": "oxlint --quiet --format=unix --config ../../oxlint.config.ts --ignore-pattern node_modules .",
"lint:fix": "oxlint --format=unix --config ../../oxlint.config.ts . --fix",
"format:check": "oxfmt --list-different .",
"format:write": "oxfmt --write .",
"lint": "oxlint --quiet --format=unix --ignore-pattern node_modules .",
"lint:fix": "oxlint --format=unix . --fix",
"release:verify": "node --conditions=source scripts/verify-consumer.ts",
"start": "node src/main.ts",
"test": "node --test test/*.test.ts",
"test:e2e": "node --test test/*.e2e.ts",
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false",
"verify:published": "node --conditions=source scripts/verify-consumer.ts --published"
},
"dependencies": {
"@ykdz/cli-contract": "workspace:*",
"zod": "catalog:"
},
"devDependencies": {
"@cli-contract/typescript-config": "workspace:*",
"@cli-contract/tooling-config": "workspace:*",
"@types/node": "catalog:",
"@ykdz/cli-contract-testing": "workspace:*",
"oxfmt": "catalog:",
Expand All @@ -39,6 +42,6 @@
"typescript-7": "catalog:"
},
"engines": {
"node": "24"
"node": "^26.13.0"
}
}
Loading
Loading