From 7f25b782f8dfc3b4c2831a741df29bdd131e3932 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 03:19:51 +0000 Subject: [PATCH] Release v0.7.7: publish @codeplans/cli to npm - App and CLI both at 0.7.7. The CLI reads its version from its own package.json, so --version can't drift from what's published. - New Publish CLI workflow: builds, tests and publishes @codeplans/cli with npm provenance, using the NPM_TOKEN repository secret. It runs from Publish Release (whose workflow-token releases don't fire other workflows), on releases published in the GitHub UI, or by hand. It fails if the CLI version doesn't match the tag, and skips versions already on npm and tags from before the CLI existed. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01S4TnKMMhfyax9SrxJkMcDM --- .github/workflows/publish-cli.yml | 76 +++++++++++++++++++++++++++ .github/workflows/publish-release.yml | 13 +++++ cli/package.json | 2 +- cli/src/cli.ts | 4 +- package.json | 2 +- 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publish-cli.yml diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml new file mode 100644 index 0000000..f5dce5d --- /dev/null +++ b/.github/workflows/publish-cli.yml @@ -0,0 +1,76 @@ +name: Publish CLI + +# Publishes @codeplans/cli to npm. It runs after Publish Release creates a +# release, when a release is published from the GitHub UI, or by hand. The +# version in cli/package.json must match the tag (v0.7.7 → 0.7.7), and a +# version that is already on npm (or a tag from before the CLI existed) is +# skipped, so re-running and backfilling releases are safe. +on: + release: + types: [published] + workflow_call: + inputs: + tag: + required: true + type: string + secrets: + NPM_TOKEN: + required: true + workflow_dispatch: + inputs: + tag: + description: Release tag to publish the CLI from (e.g. v0.7.7) + required: true + type: string + +permissions: + contents: read + id-token: write # npm provenance + +jobs: + publish: + runs-on: ubuntu-latest + env: + TAG: ${{ inputs.tag || github.event.release.tag_name }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.TAG }} + - uses: pnpm/action-setup@v4 + with: + version: 10 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + registry-url: https://registry.npmjs.org + - run: pnpm install --frozen-lockfile + - name: Check the version + id: version + run: | + if [ ! -f cli/package.json ]; then + echo "$TAG has no CLI; nothing to publish." + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + version=$(node -p "require('./cli/package.json').version") + if [ "v$version" != "$TAG" ]; then + echo "::error::cli/package.json is $version, but the tag is $TAG" + exit 1 + fi + if npm view "@codeplans/cli@$version" version >/dev/null 2>&1; then + echo "@codeplans/cli@$version is already on npm; nothing to publish." + echo "skip=true" >> "$GITHUB_OUTPUT" + fi + - name: Test + if: steps.version.outputs.skip != 'true' + run: pnpm vitest run cli + - name: Build and publish + if: steps.version.outputs.skip != 'true' + working-directory: cli + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + npm run build + test "$(node dist/index.js --version)" = "${TAG#v}" + npm publish --access public --provenance diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index b01f845..0332ff2 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -46,3 +46,16 @@ jobs: else gh release create "$TAG" --verify-tag --title "${TITLE:-$TAG}" --notes "$NOTES" fi + + # Releases made here use the workflow token, which doesn't trigger other + # workflows, so the CLI is published from here explicitly. + cli: + needs: publish + permissions: + contents: read + id-token: write + uses: ./.github/workflows/publish-cli.yml + with: + tag: ${{ inputs.tag }} + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/cli/package.json b/cli/package.json index e0928d7..d5d53ff 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@codeplans/cli", - "version": "0.1.0", + "version": "0.7.7", "description": "Command-line tool for CodePlans: script workspace setups, work with code plans, tasks and work items from your terminal.", "license": "MIT", "type": "module", diff --git a/cli/src/cli.ts b/cli/src/cli.ts index d6c4527..52cc741 100644 --- a/cli/src/cli.ts +++ b/cli/src/cli.ts @@ -2,12 +2,14 @@ // node:util parseArgs; the runner adds --json, --profile and --help, turns // errors into messages on stderr and exit codes, and creates the client lazily // (login and help never need one). +import { readFileSync } from 'node:fs' import { parseArgs, type ParseArgsConfig } from 'node:util' import { Client, CliError, EXIT, type FetchLike } from './client.js' import { configPath, resolveConnection, type Connection, type Env } from './config.js' import { createOut, paint, table, type Out, type Sink } from './output.js' -export const VERSION = '0.1.0' +/** From the package's own package.json (one level up from both src/ and dist/), so it can't drift. */ +export const VERSION: string = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version type Options = NonNullable export type Values = Record diff --git a/package.json b/package.json index daebff2..bede5cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeplans", - "version": "0.7.6", + "version": "0.7.7", "description": "Manage and track coordinated changes across your software architecture.", "author": "Sai Prakash ", "homepage": "https://codeplans.ai",