mirror of
https://github.com/cline/cline.git
synced 2026-09-17 17:45:33 +08:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
14f7801844 | ||
|
|
d201395f6d | ||
|
|
32d4750532 | ||
|
|
3e66a49c53 |
@@ -21,7 +21,11 @@ git checkout main && git pull origin main
|
||||
Get the latest release tag:
|
||||
|
||||
```bash
|
||||
git tag --sort=-v:refname | head -1
|
||||
LAST_TAG=$(git tag --list 'v*-vscode' --sort=-v:refname | head -1)
|
||||
if [ -z "$LAST_TAG" ]; then
|
||||
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
fi
|
||||
echo "$LAST_TAG"
|
||||
```
|
||||
|
||||
## Step 2: Present Commits Since Last Release
|
||||
@@ -29,15 +33,22 @@ git tag --sort=-v:refname | head -1
|
||||
Show all commits on main since the last release tag:
|
||||
|
||||
```bash
|
||||
LAST_TAG=$(git tag --sort=-v:refname | head -1)
|
||||
LAST_TAG=$(git tag --list 'v*-vscode' --sort=-v:refname | head -1)
|
||||
if [ -z "$LAST_TAG" ]; then
|
||||
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
fi
|
||||
git log ${LAST_TAG}..HEAD --oneline --format="%h %s (%an)"
|
||||
```
|
||||
|
||||
Also get the commit messages already on the tag (to identify previously cherry-picked commits). Note: Run these as separate commands to avoid shell parsing issues with parentheses in author names:
|
||||
|
||||
```bash
|
||||
LAST_TAG=$(git tag --sort=-v:refname | head -1)
|
||||
PREV_TAG=$(git tag --sort=-v:refname | head -2 | tail -1)
|
||||
get_vscode_release_tags() {
|
||||
git tag --list 'v*-vscode' --sort=-v:refname
|
||||
git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$'
|
||||
}
|
||||
LAST_TAG=$(get_vscode_release_tags | head -1)
|
||||
PREV_TAG=$(get_vscode_release_tags | head -2 | tail -1)
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -64,7 +75,10 @@ Build a mental model of what these changes do for the changelog.
|
||||
Parse the current version from package.json and the last tag:
|
||||
|
||||
```bash
|
||||
LAST_TAG=$(git tag --sort=-v:refname | head -1)
|
||||
LAST_TAG=$(git tag --list 'v*-vscode' --sort=-v:refname | head -1)
|
||||
if [ -z "$LAST_TAG" ]; then
|
||||
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
fi
|
||||
echo "Last release: $LAST_TAG"
|
||||
cat package.json | grep '"version"'
|
||||
```
|
||||
@@ -120,7 +134,10 @@ git push origin main
|
||||
Checkout the last release tag (detached HEAD):
|
||||
|
||||
```bash
|
||||
LAST_TAG=$(git tag --sort=-v:refname | head -1)
|
||||
LAST_TAG=$(git tag --list 'v*-vscode' --sort=-v:refname | head -1)
|
||||
if [ -z "$LAST_TAG" ]; then
|
||||
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
fi
|
||||
git checkout $LAST_TAG
|
||||
```
|
||||
|
||||
@@ -146,10 +163,10 @@ After all cherry-picks are applied successfully:
|
||||
|
||||
```bash
|
||||
# Tag the new release
|
||||
git tag v{VERSION}
|
||||
git tag -a v{VERSION}-vscode -m "VS Code v{VERSION}"
|
||||
|
||||
# Push the tag to remote
|
||||
git push origin v{VERSION}
|
||||
git push origin refs/tags/v{VERSION}-vscode
|
||||
```
|
||||
|
||||
## Step 8: Return to Main and Summary
|
||||
@@ -171,12 +188,12 @@ VS Code Hotfix v{VERSION} Published
|
||||
|
||||
Present a final summary:
|
||||
- New version: v{VERSION}
|
||||
- Tag pushed: yes
|
||||
- Tag pushed: v{VERSION}-vscode
|
||||
- Commits included: (list them)
|
||||
- Slack message copied to clipboard: yes
|
||||
|
||||
Remind the user to:
|
||||
1. Manually trigger the publish release GitHub Action at: https://github.com/cline/cline/actions/workflows/ext-vscode-publish-stable.yml (paste `v{VERSION}` as the tag)
|
||||
1. Manually trigger the publish release GitHub Action at: https://github.com/cline/cline/actions/workflows/ext-vscode-publish-stable.yml (paste `v{VERSION}-vscode` as the tag)
|
||||
2. Post the Slack message to announce the hotfix
|
||||
|
||||
## Important Notes
|
||||
|
||||
@@ -36,8 +36,8 @@ Confirm the release version with the maintainer (patch/minor/major).
|
||||
git add CHANGELOG.md package.json package-lock.json
|
||||
git commit -m "v<version> Release Notes"
|
||||
git push origin main
|
||||
git tag v<version>
|
||||
git push origin v<version>
|
||||
git tag -a v<version>-vscode -m "VS Code v<version>"
|
||||
git push origin refs/tags/v<version>-vscode
|
||||
```
|
||||
|
||||
### 4) Trigger publish workflow
|
||||
@@ -45,15 +45,15 @@ git push origin v<version>
|
||||
Tell the maintainer to run:
|
||||
https://github.com/cline/cline/actions/workflows/ext-vscode-publish-stable.yml
|
||||
|
||||
Use `v<version>` as the release tag.
|
||||
Use `v<version>-vscode` as the release tag.
|
||||
|
||||
### 5) Update GitHub release notes
|
||||
|
||||
After publish completes:
|
||||
|
||||
```bash
|
||||
gh release view v<version> --json body --jq '.body'
|
||||
gh release edit v<version> --notes "<final curated release notes>"
|
||||
gh release view v<version>-vscode --json body --jq '.body'
|
||||
gh release edit v<version>-vscode --notes "<final curated release notes>"
|
||||
```
|
||||
|
||||
### 6) Final summary
|
||||
|
||||
@@ -14,7 +14,7 @@ on:
|
||||
- main
|
||||
- nightly
|
||||
git_tag:
|
||||
description: "Existing release tag to publish when publish_target=main, for example cli-v0.1.0"
|
||||
description: "Existing release tag to publish when publish_target=main, for example v0.1.0-cli"
|
||||
required: false
|
||||
type: string
|
||||
confirm_publish:
|
||||
@@ -96,12 +96,13 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! printf "%s\n" "$TAG" | grep -Eq '^cli-v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
|
||||
echo "git_tag must look like cli-vX.Y.Z, got: ${TAG}"
|
||||
if ! printf "%s\n" "$TAG" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+-cli$'; then
|
||||
echo "git_tag must look like vX.Y.Z-cli, got: ${TAG}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="${TAG#cli-v}"
|
||||
VERSION="${TAG#v}"
|
||||
VERSION="${VERSION%-cli}"
|
||||
PACKAGE_VERSION=$(node -p "require('./apps/cli/package.json').version")
|
||||
|
||||
if [ "$PACKAGE_VERSION" != "$VERSION" ]; then
|
||||
@@ -181,7 +182,18 @@ jobs:
|
||||
id: prev_tag
|
||||
run: |
|
||||
CURRENT_TAG="${{ steps.version.outputs.tag }}"
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 --match 'cli-v*' "$CURRENT_TAG^" 2>/dev/null || echo "")
|
||||
NEW_STYLE_PREV=$(git describe --tags --abbrev=0 --match 'v*-cli' "$CURRENT_TAG^" 2>/dev/null || true)
|
||||
LEGACY_PREV=$(git describe --tags --abbrev=0 --match 'cli-v*' "$CURRENT_TAG^" 2>/dev/null || true)
|
||||
|
||||
PREV_TAG="$NEW_STYLE_PREV"
|
||||
if [ -n "$NEW_STYLE_PREV" ] && [ -n "$LEGACY_PREV" ]; then
|
||||
if git merge-base --is-ancestor "${NEW_STYLE_PREV}^{commit}" "${LEGACY_PREV}^{commit}"; then
|
||||
PREV_TAG="$LEGACY_PREV"
|
||||
fi
|
||||
elif [ -z "$PREV_TAG" ]; then
|
||||
PREV_TAG="$LEGACY_PREV"
|
||||
fi
|
||||
|
||||
echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get Changelog Entry
|
||||
@@ -235,7 +247,7 @@ jobs:
|
||||
publish-nightly:
|
||||
name: Publish cline nightly
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write
|
||||
id-token: write
|
||||
if: |
|
||||
github.repository == 'cline/cline' &&
|
||||
@@ -386,6 +398,21 @@ jobs:
|
||||
run: bun script/publish-npm.ts --tag nightly
|
||||
working-directory: sdk/apps/cli
|
||||
|
||||
- name: Create nightly git tag
|
||||
if: steps.check_commits.outputs.skip != 'true'
|
||||
run: |
|
||||
BASE_VERSION="${{ steps.version.outputs.base_version }}"
|
||||
NIGHTLY_VERSION="${{ steps.version.outputs.version }}"
|
||||
TIMESTAMP=$(date -u +"%Y%m%d%H%M%S")
|
||||
TAG="v${BASE_VERSION}-cli-nightly.${TIMESTAMP}"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "CLI nightly ${NIGHTLY_VERSION} from ${GITHUB_REF_NAME} at ${GITHUB_SHA}"
|
||||
git push origin "refs/tags/${TAG}"
|
||||
|
||||
echo "Tagged published commit: $TAG"
|
||||
|
||||
- name: Summary
|
||||
if: steps.check_commits.outputs.skip != 'true'
|
||||
run: |
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
contents: write
|
||||
packages: write
|
||||
checks: write
|
||||
pull-requests: write
|
||||
@@ -49,6 +49,12 @@ jobs:
|
||||
- name: Install Publishing Tools
|
||||
run: npm install -g @vscode/vsce ovsx
|
||||
|
||||
- name: Capture base version
|
||||
id: base_version
|
||||
run: |
|
||||
BASE_VERSION=$(node -p "require('./package.json').version")
|
||||
echo "base_version=${BASE_VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Verify LFS media assets are resolved
|
||||
run: |
|
||||
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
|
||||
@@ -73,3 +79,19 @@ jobs:
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
|
||||
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
|
||||
run: npm run publish:marketplace:nightly
|
||||
|
||||
- name: Tag published commit
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
BASE_VERSION="${{ steps.base_version.outputs.base_version }}"
|
||||
SOURCE_SHA=$(git rev-parse HEAD)
|
||||
TIMESTAMP=$(date -u +"%Y%m%d%H%M%S")
|
||||
TAG="v${BASE_VERSION}-vscode-nightly.${TIMESTAMP}"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "VS Code nightly from ${SDK_NIGHTLY_REF} at ${SOURCE_SHA}"
|
||||
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "refs/tags/${TAG}"
|
||||
|
||||
echo "Tagged published commit: $TAG"
|
||||
|
||||
@@ -61,6 +61,12 @@ jobs:
|
||||
- name: Install Publishing Tools
|
||||
run: npm install -g @vscode/vsce ovsx
|
||||
|
||||
- name: Capture base version
|
||||
id: base_version
|
||||
run: |
|
||||
BASE_VERSION=$(node -p "require('./package.json').version")
|
||||
echo "base_version=${BASE_VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Verify LFS media assets are resolved
|
||||
run: |
|
||||
for FILE in webview-ui/src/assets/cline_kanban_demo.mp4 webview-ui/src/assets/cline_kanban_demo.webm; do
|
||||
@@ -90,14 +96,13 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
SAFE_REF=$(echo "$GITHUB_REF_NAME" | tr '/[:upper:]' '-[:lower:]' | tr -cd 'a-z0-9._-')
|
||||
SHORT_SHA=$(git rev-parse --short=12 HEAD)
|
||||
BASE_VERSION="${{ steps.base_version.outputs.base_version }}"
|
||||
TIMESTAMP=$(date -u +"%Y%m%d%H%M%S")
|
||||
TAG="nightly-${SAFE_REF}-${TIMESTAMP}-${SHORT_SHA}"
|
||||
TAG="v${BASE_VERSION}-vscode-nightly.${TIMESTAMP}"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "Cline Nightly published from ${GITHUB_REF_NAME} at ${GITHUB_SHA}"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "VS Code nightly from ${GITHUB_REF_NAME} at ${GITHUB_SHA}"
|
||||
# Use an explicit HTTPS remote with GH_TOKEN because checkout was run with
|
||||
# persist-credentials: false, so actions/checkout did not persist a git credential helper.
|
||||
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "refs/tags/${TAG}"
|
||||
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
default: true
|
||||
type: boolean
|
||||
tag:
|
||||
description: "Tag to publish (required in both modes, e.g., v3.1.2)"
|
||||
description: "Tag to publish (required in both modes, e.g., v3.1.2-vscode)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
@@ -59,8 +59,8 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.]+)?$ ]]; then
|
||||
echo "Error: tag must match vX.Y.Z (optionally with -suffix or .suffix)"
|
||||
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-vscode$ ]]; then
|
||||
echo "Error: tag must match vX.Y.Z-vscode"
|
||||
exit 1
|
||||
fi
|
||||
TAG_REF="refs/tags/$TAG"
|
||||
@@ -88,8 +88,8 @@ jobs:
|
||||
echo "Tag '$TAG' already exists at tested SHA. Continuing."
|
||||
else
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag "$TAG" "$TESTED_SHA"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "VS Code ${TAG}" "$TESTED_SHA"
|
||||
git push origin "$TAG_REF"
|
||||
echo "Created and pushed tag '$TAG' from tested SHA $TESTED_SHA."
|
||||
fi
|
||||
@@ -128,8 +128,10 @@ jobs:
|
||||
- name: Verify Tag Matches Package Version
|
||||
run: |
|
||||
TAG="${{ steps.resolve_tag.outputs.tag }}"
|
||||
VERSION="v${{ steps.get_version.outputs.version }}"
|
||||
if [[ "$TAG" != "$VERSION" ]]; then
|
||||
TAG_VERSION="${TAG#v}"
|
||||
TAG_VERSION="${TAG_VERSION%-vscode}"
|
||||
VERSION="${{ steps.get_version.outputs.version }}"
|
||||
if [[ "$TAG_VERSION" != "$VERSION" ]]; then
|
||||
echo "Error: tag '$TAG' does not match package version '$VERSION'"
|
||||
exit 1
|
||||
fi
|
||||
@@ -182,7 +184,13 @@ jobs:
|
||||
id: prev_tag
|
||||
run: |
|
||||
CURRENT_TAG="${{ steps.resolve_tag.outputs.tag }}"
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 "$CURRENT_TAG^" 2>/dev/null || echo "")
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 --match 'v*-vscode' "$CURRENT_TAG^" 2>/dev/null || true)
|
||||
if [[ -z "$PREV_TAG" ]]; then
|
||||
# Migration fallback for old VS Code releases, which used plain vX.Y.Z tags.
|
||||
# Exclude all hyphenated tags so CLI, SDK package, and nightly tags cannot
|
||||
# become the changelog baseline.
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' --exclude 'v*-*' "$CURRENT_TAG^" 2>/dev/null || echo "")
|
||||
fi
|
||||
echo "prev_tag=$PREV_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get Changelog Entry
|
||||
|
||||
@@ -56,6 +56,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Determine publish channel
|
||||
id: channel
|
||||
@@ -155,6 +158,7 @@ jobs:
|
||||
echo "Base version: $BASE_VERSION"
|
||||
echo "Channel: $CHANNEL"
|
||||
echo "Publish version: $VERSION"
|
||||
echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update all package versions and lockfile
|
||||
@@ -236,7 +240,7 @@ jobs:
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
for PKG in shared llms agents core sdk; do
|
||||
TAG="sdk/${PKG}/v${VERSION}"
|
||||
TAG="v${VERSION}-sdk-${PKG}"
|
||||
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
|
||||
echo "Tag already exists locally: ${TAG}"
|
||||
else
|
||||
@@ -244,10 +248,24 @@ jobs:
|
||||
echo "Created tag: ${TAG}"
|
||||
fi
|
||||
|
||||
# Ensure remote has the tag; this is idempotent if tag already exists remotely.
|
||||
git push origin "refs/tags/${TAG}"
|
||||
done
|
||||
|
||||
- name: Create nightly git tag
|
||||
if: steps.check_commits.outputs.skip != 'true' && steps.channel.outputs.channel == 'nightly'
|
||||
run: |
|
||||
BASE_VERSION="${{ steps.version.outputs.base_version }}"
|
||||
NIGHTLY_VERSION="${{ steps.version.outputs.version }}"
|
||||
TIMESTAMP=$(date -u +"%Y%m%d%H%M%S")
|
||||
TAG="v${BASE_VERSION}-sdk-nightly.${TIMESTAMP}"
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "$TAG" -m "SDK nightly ${NIGHTLY_VERSION} from ${GITHUB_REF_NAME} at ${GITHUB_SHA}"
|
||||
git push origin "refs/tags/${TAG}"
|
||||
|
||||
echo "Tagged published commit: $TAG"
|
||||
|
||||
- name: Summary
|
||||
if: steps.check_commits.outputs.skip != 'true'
|
||||
run: |
|
||||
@@ -261,9 +279,9 @@ jobs:
|
||||
echo " - @cline/sdk@${VERSION}"
|
||||
if [ "$CHANNEL" = "latest" ]; then
|
||||
echo "Created git tags:"
|
||||
echo " - sdk/shared/v${VERSION}"
|
||||
echo " - sdk/llms/v${VERSION}"
|
||||
echo " - sdk/agents/v${VERSION}"
|
||||
echo " - sdk/core/v${VERSION}"
|
||||
echo " - sdk/sdk/v${VERSION}"
|
||||
echo " - v${VERSION}-sdk-shared"
|
||||
echo " - v${VERSION}-sdk-llms"
|
||||
echo " - v${VERSION}-sdk-agents"
|
||||
echo " - v${VERSION}-sdk-core"
|
||||
echo " - v${VERSION}-sdk-sdk"
|
||||
fi
|
||||
|
||||
+12
-12
@@ -91,7 +91,7 @@ Additional SDK flags: `--skip-tests`, `--skip-git-tags`.
|
||||
|
||||
The script checks out `main` (and pulls latest) before starting. If the working tree is dirty it aborts.
|
||||
|
||||
The SDK flow runs: tests → version bump → lockfile regeneration → tarball verification → publish (shared → llms → agents → core) → optional `sdk-v{VERSION}` tag creation.
|
||||
The SDK flow runs: tests → version bump → lockfile regeneration → tarball verification → publish (shared → llms → agents → core) → optional `v{VERSION}-sdk-{PACKAGE}` tag creation.
|
||||
|
||||
### CLI Release
|
||||
|
||||
@@ -101,7 +101,7 @@ Under the hood, every release starts the same way: prepare one release commit, t
|
||||
|
||||
Prepare the release commit from the code you want to release:
|
||||
|
||||
1. Draft user-facing release notes from the commits since the last `cli-vX.Y.Z` tag.
|
||||
1. Draft user-facing release notes from the commits since the last `vX.Y.Z-cli` tag.
|
||||
2. Choose the release version.
|
||||
3. Update `apps/cli/package.json`.
|
||||
4. Add the approved notes to `apps/cli/CHANGELOG.md`.
|
||||
@@ -115,12 +115,12 @@ Path A: publish from GitHub Actions.
|
||||
Use this for normal releases. Merge the release commit to `main`, create and push the matching release tag, then run:
|
||||
|
||||
```sh
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=cli-vX.Y.Z -f confirm_publish=publish
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=vX.Y.Z-cli -f confirm_publish=publish
|
||||
```
|
||||
|
||||
The workflow checks out the provided `cli-vX.Y.Z` tag, verifies it matches `apps/cli/package.json`, builds the platform packages, publishes to npm with the `latest` dist-tag, creates the GitHub release, and posts to Slack.
|
||||
The workflow checks out the provided `vX.Y.Z-cli` tag, verifies it matches `apps/cli/package.json`, builds the platform packages, publishes to npm with the `latest` dist-tag, creates the GitHub release, and posts to Slack.
|
||||
|
||||
Path B: publish locally.
|
||||
|
||||
@@ -129,13 +129,13 @@ Use this when publishing from an authenticated local machine. Start from a clean
|
||||
```sh
|
||||
gh auth status
|
||||
npm whoami
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
bun release cli
|
||||
gh release create cli-vX.Y.Z --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
gh release create vX.Y.Z-cli --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
```
|
||||
|
||||
The local helper verifies the working tree is clean, verifies `cli-vX.Y.Z` points at `HEAD` locally and on `origin`, runs tests, builds platform packages, and publishes to npm.
|
||||
The local helper verifies the working tree is clean, verifies `vX.Y.Z-cli` points at `HEAD` locally and on `origin`, runs tests, builds platform packages, and publishes to npm.
|
||||
|
||||
Nightly release:
|
||||
|
||||
@@ -143,7 +143,7 @@ Nightly release:
|
||||
gh workflow run cli-publish.yml -f publish_target=nightly
|
||||
```
|
||||
|
||||
Nightly also runs on a schedule. It publishes `X.Y.Z-nightly.TIMESTAMP` to npm with the `nightly` dist-tag and skips if there were no commits in the last 24 hours unless forced.
|
||||
Nightly also runs on a schedule. It publishes `X.Y.Z-nightly.TIMESTAMP` to npm with the `nightly` dist-tag, creates a `vX.Y.Z-cli-nightly.TIMESTAMP` git tag, and skips if there were no commits in the last 24 hours unless forced.
|
||||
|
||||
### Manual SDK Publish
|
||||
|
||||
@@ -158,7 +158,7 @@ If you need fine-grained control over individual steps:
|
||||
```sh
|
||||
cd packages/shared && bun publish && cd ../llms && bun publish && cd ../agents && bun publish && cd ../core && bun publish && cd ../../
|
||||
```
|
||||
7. For tagged production releases, create and push a git tag: `git tag -a sdk-v{VERSION} -m "SDK v{VERSION}" && git push origin sdk-v{VERSION}`.
|
||||
7. For tagged production releases, create and push package tags such as `v{VERSION}-sdk-shared`, `v{VERSION}-sdk-llms`, `v{VERSION}-sdk-agents`, `v{VERSION}-sdk-core`, and `v{VERSION}-sdk-sdk`.
|
||||
|
||||
### Workspace Dependency Rules
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
name: publish-cli
|
||||
description: Use when preparing, tagging, and publishing an apps/cli npm release. Guides changelog drafting, apps/cli/package.json version bumps, cli-vX.Y.Z tags, local npm publishing, and the publish-cli GitHub workflow.
|
||||
description: Use when preparing, tagging, and publishing an apps/cli npm release. Guides changelog drafting, apps/cli/package.json version bumps, vX.Y.Z-cli tags, local npm publishing, and the publish-cli GitHub workflow.
|
||||
---
|
||||
|
||||
# CLI Release
|
||||
|
||||
Use this skill when the user asks to release the CLI, publish `cline`, bump the CLI version, draft release notes, create a `cli-vX.Y.Z` tag, or trigger the CLI publish workflow.
|
||||
Use this skill when the user asks to release the CLI, publish `cline`, bump the CLI version, draft release notes, create a `vX.Y.Z-cli` tag, or trigger the CLI publish workflow.
|
||||
|
||||
The CLI is npm-only. Do not add alternate distribution or signing steps.
|
||||
|
||||
@@ -16,16 +16,16 @@ The skill should guide the user through one release preparation flow, then offer
|
||||
## Release contract
|
||||
|
||||
- Version source: `apps/cli/package.json`.
|
||||
- Main release tag: `cli-vX.Y.Z`, where `X.Y.Z` matches `apps/cli/package.json`.
|
||||
- Main release tag: `vX.Y.Z-cli`, where `X.Y.Z` matches `apps/cli/package.json`.
|
||||
- Nightly release version: `X.Y.Z-nightly.TIMESTAMP`.
|
||||
- Release prep includes approved release notes, a version bump, and an `apps/cli/CHANGELOG.md` update.
|
||||
- Publish paths:
|
||||
- GitHub workflow: `.github/workflows/cli-publish.yml`.
|
||||
- Local publish helper: `bun release cli`.
|
||||
- npm dist-tags and git tags are separate. `--tag latest` and `--tag nightly` are npm registry channels. `cli-vX.Y.Z` is a git tag for source history and GitHub releases.
|
||||
- The GitHub main release workflow runs from `main`, requires an existing `cli-vX.Y.Z` tag, checks out that tag, and publishes from it.
|
||||
- The GitHub nightly workflow publishes to npm with the `nightly` dist-tag and does not create a tag.
|
||||
- The local release helper requires a clean checkout and `cli-vX.Y.Z` to point at `HEAD` locally and on `origin` before publishing.
|
||||
- npm dist-tags and git tags are separate. `--tag latest` and `--tag nightly` are npm registry channels. `vX.Y.Z-cli` is a git tag for source history and GitHub releases.
|
||||
- The GitHub main release workflow runs from `main`, requires an existing `vX.Y.Z-cli` tag, checks out that tag, and publishes from it.
|
||||
- The GitHub nightly workflow publishes to npm with the `nightly` dist-tag and creates a `vX.Y.Z-cli-nightly.TIMESTAMP` git tag.
|
||||
- The local release helper requires a clean checkout and `vX.Y.Z-cli` to point at `HEAD` locally and on `origin` before publishing.
|
||||
- Local GitHub release creation requires `gh` to be authenticated with release permissions for the repo.
|
||||
- Always ask before pushing commits or tags.
|
||||
- Do not amend commits unless explicitly requested.
|
||||
@@ -37,11 +37,12 @@ The skill should guide the user through one release preparation flow, then offer
|
||||
```sh
|
||||
git status --short --branch
|
||||
git fetch origin --tags
|
||||
git tag --list 'cli-v*' --sort=-v:refname | head -10
|
||||
LAST_CLI_TAG=$(git describe --tags --abbrev=0 --match 'v*-cli' HEAD)
|
||||
printf '%s\n' "$LAST_CLI_TAG"
|
||||
node -p "require('./apps/cli/package.json').version"
|
||||
```
|
||||
|
||||
Find the latest CLI tag. If there is no `cli-v*` tag, use the first relevant CLI release commit as the baseline and say that the baseline is inferred.
|
||||
Find the latest CLI tag by ancestry, not by version sort. The release contract uses `vX.Y.Z-cli` tags.
|
||||
|
||||
2. Collect release commits.
|
||||
|
||||
@@ -110,15 +111,15 @@ git push origin HEAD
|
||||
For the GitHub main release path, ask before creating and pushing the release tag:
|
||||
|
||||
```sh
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
```
|
||||
|
||||
8. Publish.
|
||||
|
||||
Ask the user which path to use:
|
||||
|
||||
- GitHub main release. Use this after the release commit is on `main` and the matching `cli-vX.Y.Z` tag has been pushed. The workflow publishes to npm from that tag, creates the GitHub release, and posts to Slack.
|
||||
- GitHub main release. Use this after the release commit is on `main` and the matching `vX.Y.Z-cli` tag has been pushed. The workflow publishes to npm from that tag, creates the GitHub release, and posts to Slack.
|
||||
- Local release. Use this when the user wants to publish from this machine. The local machine must be authenticated to npm and GitHub.
|
||||
- GitHub nightly release.
|
||||
- Stop after the version commit.
|
||||
@@ -126,7 +127,7 @@ Ask the user which path to use:
|
||||
For GitHub main release:
|
||||
|
||||
```sh
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=cli-vX.Y.Z -f confirm_publish=publish
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=vX.Y.Z-cli -f confirm_publish=publish
|
||||
gh run list --workflow=cli-publish.yml --limit=1 --json url,status,conclusion,createdAt --jq '.[0]'
|
||||
```
|
||||
|
||||
@@ -147,15 +148,15 @@ For local publish:
|
||||
```sh
|
||||
gh auth status
|
||||
npm whoami
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
bun release cli
|
||||
```
|
||||
|
||||
After a successful local publish, ask before running:
|
||||
|
||||
```sh
|
||||
gh release create cli-vX.Y.Z --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
gh release create vX.Y.Z-cli --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
```
|
||||
|
||||
If publishing with another npm dist-tag:
|
||||
|
||||
@@ -79,7 +79,7 @@ cline auth # authenticate a provider
|
||||
|
||||
Every release starts by preparing one release commit from the code you want to publish:
|
||||
|
||||
1. Draft user-facing release notes from the commits since the last `cli-vX.Y.Z` tag.
|
||||
1. Draft user-facing release notes from the commits since the last `vX.Y.Z-cli` tag.
|
||||
2. Choose the release version. Because this publishes over the existing `cline` package, the version must be greater than the current published `cline` version. The handoff release is `3.0.0`.
|
||||
3. Update `apps/cli/package.json`.
|
||||
4. Add the approved notes to `apps/cli/CHANGELOG.md`.
|
||||
@@ -93,12 +93,12 @@ Then publish that release commit with one of these paths.
|
||||
Use this path for normal releases.
|
||||
|
||||
```bash
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=cli-vX.Y.Z -f confirm_publish=publish
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
gh workflow run cli-publish.yml -f publish_target=main -f git_tag=vX.Y.Z-cli -f confirm_publish=publish
|
||||
```
|
||||
|
||||
This path requires the release commit to be on `main` and the matching `cli-vX.Y.Z` tag to exist before the workflow runs. The workflow checks out the tag, publishes to npm with the `latest` dist-tag, creates the GitHub release, and posts to Slack.
|
||||
This path requires the release commit to be on `main` and the matching `vX.Y.Z-cli` tag to exist before the workflow runs. The workflow checks out the tag, publishes to npm with the `latest` dist-tag, creates the GitHub release, and posts to Slack.
|
||||
|
||||
### Publish Locally
|
||||
|
||||
@@ -109,10 +109,10 @@ Start from a clean checkout at the release commit:
|
||||
```bash
|
||||
gh auth status
|
||||
npm whoami
|
||||
git tag -a cli-vX.Y.Z -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/cli-vX.Y.Z
|
||||
git tag -a vX.Y.Z-cli -m "CLI vX.Y.Z"
|
||||
git push origin refs/tags/vX.Y.Z-cli
|
||||
bun release cli
|
||||
gh release create cli-vX.Y.Z --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
gh release create vX.Y.Z-cli --verify-tag --title "CLI vX.Y.Z" --notes "Paste the approved release notes here."
|
||||
```
|
||||
|
||||
The release helper checks the working tree, verifies the tag points at `HEAD` locally and on `origin`, runs tests, builds all platform packages, and publishes the platform packages plus the generated `cline` wrapper package to npm. The package version and tag must match.
|
||||
@@ -128,9 +128,9 @@ bun release cli --tag next
|
||||
The GitHub workflow at `.github/workflows/cli-publish.yml` automates publishing:
|
||||
|
||||
- Main releases are manual. Select `publish_target=main` and set `confirm_publish=publish`.
|
||||
- Main releases require `git_tag=cli-vX.Y.Z`, check out that tag, verify it matches `apps/cli/package.json`, run tests, build all platform packages, publish to npm with the `latest` dist-tag using trusted publishing, create a GitHub release, and post to Slack.
|
||||
- Main releases require `git_tag=vX.Y.Z-cli`, check out that tag, verify it matches `apps/cli/package.json`, run tests, build all platform packages, publish to npm with the `latest` dist-tag using trusted publishing, create a GitHub release, and post to Slack.
|
||||
- Nightly releases run on a schedule or manually with `publish_target=nightly`.
|
||||
- Nightly releases publish `X.Y.Z-nightly.TIMESTAMP` to npm with the `nightly` dist-tag and skip if there were no commits in the last 24 hours unless forced.
|
||||
- Nightly releases publish `X.Y.Z-nightly.TIMESTAMP` to npm with the `nightly` dist-tag, create a `vX.Y.Z-cli-nightly.TIMESTAMP` git tag, and skip if there were no commits in the last 24 hours unless forced.
|
||||
|
||||
CI publishing uses npm trusted publishing. Configure npm trusted publishers for the `cline` wrapper package and every platform package before relying on the workflow.
|
||||
|
||||
|
||||
+26
-10
@@ -47,7 +47,7 @@ if (!target || !["sdk", "cli"].includes(target)) {
|
||||
console.error("");
|
||||
console.error("Targets:");
|
||||
console.error(" sdk Publish @cline/{shared,llms,agents,core,sdk} to npm");
|
||||
console.error(" cli Publish cline from an existing cli-vX.Y.Z git tag");
|
||||
console.error(" cli Publish cline from an existing vX.Y.Z-cli git tag");
|
||||
console.error("");
|
||||
console.error("Options:");
|
||||
console.error(
|
||||
@@ -235,7 +235,7 @@ async function ensureCleanWorkingTree(): Promise<void> {
|
||||
}
|
||||
|
||||
async function ensureCliReleaseTag(version: string): Promise<void> {
|
||||
const expectedTag = `cli-v${version}`;
|
||||
const expectedTag = `v${version}-cli`;
|
||||
if (dryRun) {
|
||||
console.log(` [dry-run] Required pushed git tag: ${expectedTag}`);
|
||||
return;
|
||||
@@ -400,19 +400,35 @@ async function releaseSDK(version: string): Promise<number> {
|
||||
// Step 5: Git tag
|
||||
if (npmTag === "latest" && !skipGitTags) {
|
||||
header("Step 5/5: Creating git tag");
|
||||
const gitTag = `sdk-v${version}`;
|
||||
console.log(` Creating tag: ${gitTag}`);
|
||||
await run(["git", "tag", "-a", gitTag, "-m", `SDK v${version}`]);
|
||||
const gitTags = SDK_PUBLISH_ORDER.map(
|
||||
(workspace) => `v${version}-sdk-${workspace}`,
|
||||
);
|
||||
console.log(` Creating tags: ${gitTags.join(", ")}`);
|
||||
for (const workspace of SDK_PUBLISH_ORDER) {
|
||||
const gitTag = `v${version}-sdk-${workspace}`;
|
||||
await run([
|
||||
"git",
|
||||
"tag",
|
||||
"-a",
|
||||
gitTag,
|
||||
"-m",
|
||||
`@cline/${workspace}@${version}`,
|
||||
]);
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
const pushOk = await confirm(
|
||||
"\nPush tag to remote? This makes the release public.",
|
||||
"\nPush tags to remote? This makes the release public.",
|
||||
);
|
||||
if (pushOk) {
|
||||
await run(["git", "push", "origin", `refs/tags/${gitTag}`]);
|
||||
for (const gitTag of gitTags) {
|
||||
await run(["git", "push", "origin", `refs/tags/${gitTag}`]);
|
||||
}
|
||||
} else {
|
||||
console.log(` Skipped pushing tag. Push manually with:`);
|
||||
console.log(` git push origin refs/tags/${gitTag}`);
|
||||
console.log(" Skipped pushing tags. Push manually with:");
|
||||
for (const gitTag of gitTags) {
|
||||
console.log(` git push origin refs/tags/${gitTag}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (skipGitTags) {
|
||||
@@ -443,7 +459,7 @@ async function releaseSDK(version: string): Promise<number> {
|
||||
async function releaseCLI(version: string): Promise<number> {
|
||||
console.log(`\nRelease CLI`);
|
||||
console.log(` Version: ${version}`);
|
||||
console.log(` Git tag: cli-v${version}`);
|
||||
console.log(` Git tag: v${version}-cli`);
|
||||
console.log(` Tag: ${npmTag}`);
|
||||
console.log(` Dry run: ${dryRun}`);
|
||||
console.log(` Skip tests: ${skipTests}`);
|
||||
|
||||
Reference in New Issue
Block a user