Skip to content

Latest commit

 

History

History
306 lines (249 loc) · 14.9 KB

File metadata and controls

306 lines (249 loc) · 14.9 KB

Releasing zcode-app-cli

Each release follows the current upstream runtime and provider schema. The lock file records the verified installer for reproducible builds; it is not a promise to support older runtime versions.

This document covers the maintainer-only workflows for synchronizing the upstream runtime, building the npm tarball, and publishing releases. End users do not need any of this — see the main README for installation and usage.

Remote extraction

The same path used by CI can be run locally:

brew install sevenzip
bun run sync -- --platform linux --arch x64

Use the committed artifact instead of the latest updater manifest when rebuilding a reviewed release:

bun run sync:locked

The synchronization command:

  1. reads the public stable-channel manifest used by ZCode Desktop, with the static CDN manifest as a fallback only when the service response is unavailable or invalid;
  2. downloads the matching installer;
  3. verifies its SHA-512 from the manifest;
  4. extracts resources/glm;
  5. applies the version-independent runtime patch plan and injects the local @zcode/tui adapter, retaining upstream text and marking the runtime as modified;
  6. extracts the strict global CLI option contract and validates the official CLI version;
  7. records provenance, CLI capabilities and each patch result in vendor/extraction.json;
  8. records the remote artifact URL and SHA-512 in zcode-runtime.lock.json;
  9. aligns the npm version prefix with the ZCode App version while preserving the independently incremented CLI build revision.

npm package contents

The published package is controlled by the files allowlist in package.json. It contains only:

  • bin/zcode.js, the bundled executable Node.js launcher;
  • vendor/, the extracted and patched zcode.cjs runtime, included built-in plugins (including document, PDF, presentation and spreadsheet plugins with their original licenses) and the compiled local @zcode/tui adapter;
  • setting.example.json, provider.example.json and zcode-runtime.lock.json;
  • the English and Simplified Chinese configuration guides and provider field references in docs/;
  • docs/THIRD_PARTY_CONTENT.md and the license texts, upstream notices and source provenance in LICENSES/;
  • README.md, LICENSE and the required npm package.json.

Tests, GitHub workflows, build scripts, launcher/TUI TypeScript sources, local config, .release/ artifacts and development node_modules are not published. npm installs the declared pi-tui and playwright-core dependencies. The launcher and TUI are compiled to JavaScript with tsdown; its launcher banner adds the Node.js shebang directly, with no post-build rewrite. The compiled TUI is injected into vendor/ before publication.

Commit preview packages

To request a preview of an open PR (including a contributor's fork), kingsword09 posts a new PR conversation comment containing exactly:

/pkg-pr-new

Only GitHub user ID 19650362 may request PR previews. Other commenters, edited comments, commands in code blocks, regular issues, and reruns by other accounts are ignored or rejected. New PR commits do not publish automatically; post the command again to test the updated commit.

The comment workflow must first be merged into main: GitHub runs issue_comment workflows from the default branch. The owner can also run Publish commit preview from Actions on main, with an optional pull_request number. An empty number previews main. Pushes to main retain their automatic preview builds.

.github/workflows/release-commit.yml resolves and pins the PR's head SHA in a trusted authorization job, builds that exact commit with a read-only token, runs the release checks, and install-tests the npm tarball. The exact tested tarball is uploaded to pkg.pr.new without repacking it. PR scripts receive no repository-write or npm-publishing credentials. A separate job running only the trusted workflow revision posts the result and logs link back to the PR. Unauthorized comments cannot cancel an active preview build.

Install the pkg-pr-new GitHub App on this repository before the first preview publication. No npm token or npm publish permission is needed. The publisher is pinned in devDependencies and bun.lock.

The workflow uses pkg.pr.new's default compact URLs and posts the actual returned URL as the install command, followed by the full repository URL for the same commit. If pkg.pr.new falls back to a full URL, that returned URL is used directly. Publication failures report their logs without an install link. Use the link in that comment or the workflow summary to test an existing session:

npx --yes https://pkg.pr.new/zcode-app-cli@<commit-sha> --resume <session-id>

Use the exact URL emitted by the successful workflow. This runs the preview without replacing the globally installed CLI. It uses the user's normal session store, so the tester can verify their affected sessions. Record the preview URL with the test result: preview tarballs retain the source package version, while their URLs identify the commit. Mutable branch and PR-number aliases are not used by comment-triggered previews. They do not update npm's latest tag or create a release tag. The tested tarball is also retained as a workflow artifact for 14 days, including when pkg.pr.new publication fails.

Versioning

Package versions use <app-version>-<build>, for example 3.3.5-2. The prefix tracks the upstream ZCode App. The globally increasing build revision tracks fixes and features in this project. Do not use 3.3.5+build.2: SemVer ignores +build metadata when comparing upgrades.

Increment the project revision before publishing a local fix or feature:

bun run version:build

The release workflows normally perform that increment for you. The command is also available for local inspection and exceptional manual preparation.

Release flow

Publishing is split into two workflows so the committed version, npm package, Git tag and GitHub Release all describe the same release:

  1. .github/workflows/prepare-release.yml extracts and validates the current official runtime, then opens or updates a Release PR containing the exact package.json version and zcode-runtime.lock.json build input;
  2. a maintainer reviews and merges that PR;
  3. .github/workflows/publish.yml checks out its merge commit, rebuilds the exact locked runtime, audits and install-tests the tarball, publishes through npm Trusted Publishing, then creates v<version> and the corresponding GitHub Release.

The generated vendor/ directory remains ignored by Git and is rebuilt in both workflows. Its updater URL and SHA-512 are committed in zcode-runtime.lock.json. Preparation resolves the latest manifest; publishing downloads the committed URL and verifies the locked SHA-512, so a later upstream update cannot silently change a reviewed release.

The scheduled workflow follows the Desktop stable channel (channel=1) without credentials or a personal device_mid. Static latest-*.yml files can lag the service and are therefore recovery inputs, not the primary update signal. If upstream rolls its stable channel back, synchronization keeps a newer committed lock instead of silently downgrading it; adopting a rollback requires an explicit maintainer review of zcode-runtime.lock.json.

The preparation workflow checks upstream once per day at 01:30 in the Asia/Shanghai timezone, in upstream mode. GitHub documents scheduled triggers as best effort: under high Actions load a scheduled event can still be delayed or dropped. The preparation itself is idempotent: the fixed release branch is created or updated only when the runtime lock or package version changes. A same-version upstream repack increments the global build so npm still receives an immutable new version. From the Actions page, run Prepare ZCode CLI release with one of these modes:

  • cli increments the global build and also aligns with the latest App;
  • upstream checks for an App update without incrementing the build.

The modes use release/zcode-cli and release/zcode-upstream respectively. If both PRs are open, merge one and rerun the other preparation mode so its version is recalculated from the new main branch.

Runtime patches are registered as required or optional. Required bridge, OAuth, HTTP and public CLI contract failures stop preparation. Optional diagnostics and presentation fixes record a skipped capability and allow the validated runtime to continue. Session cache aggregation lives in the local TUI and reads persisted messages through the adapter, so upstream minifier symbol changes do not affect it.

app-server-standalone-auth is required. It enables local CLI credentials by default while preserving explicit Host authentication. Missing or ambiguous protocol anchors and partial auth injections stop synchronization; a release must not silently lose account-backed app-server turns. Runtime tests exercise both credential owners against a local HTTPS model fixture.

If a required compatibility check fails, synchronization writes JSON and Markdown reports under .release/. The scheduled workflow uploads both files and creates or updates the fixed Automated upstream runtime compatibility failure issue. A later successful scheduled validation closes that issue. This separates an upstream incompatibility from download, checksum, permission and publishing failures without weakening the release gate. Discovery failures are still uploaded for diagnosis, but they do not create a compatibility issue.

The workflow also runs a least-privilege keepalive job on scheduled events. It calls GitHub's workflow-enable API instead of creating dummy commits, which prevents the public-repository 60-day inactivity rule from disabling this schedule. This cannot eliminate platform-wide outages or dropped events; for a hard delivery deadline, use an external scheduler or run the workflow manually:

gh workflow run prepare-release.yml --ref main -f kind=upstream
gh workflow enable prepare-release.yml

Merging either Release PR publishes automatically. Publish ZCode CLI release can also be started manually for recovery. Its publish checkbox can be disabled to run all validation and consistency checks without changing npm, Git tags or GitHub Releases. Publication, tag creation and GitHub Release creation are independently idempotent, so a partially completed run can be retried safely.

Local release build

Local packaging uses the same commands as the publishing workflow. Start from the exact clean commit whose version will be published:

bun install --frozen-lockfile
bun run release:build
git diff --exit-code -- package.json zcode-runtime.lock.json
bun run release:pack

release:build runs TypeScript checking and all tests, downloads the artifact from zcode-runtime.lock.json, verifies its SHA-512, builds and injects the TUI, then runs runtime and PTY smoke tests. release:pack runs the offline prepack guard, creates .release/zcode-app-cli-<version>.tgz, audits every included path and executable mode, installs it into a temporary directory, and runs the installed zcode --version. It also checks the runtime modification notice and initializes the included plugins using an isolated temporary home, verifying that Browser Use and the four document plugins are enabled and their original license files are present. Installation is limited to three minutes, the version check to 15 seconds, and plugin initialization to 30 seconds; timed-out checks terminate their subprocesses before cleanup. Only after all checks pass are the final size, integrity and file count written to .release/release.json.

Inspect that manifest and then publish explicitly:

npm login
npm publish --access public --tag latest --provenance=false

The final npm publish intentionally remains explicit to avoid an accidental registry mutation. It reruns the same offline prepack guard and fails if the compiled TUI, runtime provenance, lock file, launcher permissions or package allowlist are stale. --provenance=false applies only to this local bootstrap path; GitHub OIDC generates provenance automatically.

Publish from the repository root as shown, rather than passing the .tgz to npm publish: directory publication lets npm record the current Git gitHead, which the recovery workflow later verifies. The tarball is the audited preview and install-test artifact.

Initial npm setup

If the package does not exist on npm yet, bootstrap it once from the exact committed main revision using the local release build above. If its Git diff check fails, do not publish from that working tree; refresh the Release PR or restore the committed version and lock first.

Synchronization preserves the build when the upstream App version changes. For example, syncing 3.3.5-12 against ZCode App 3.4.0 produces 3.4.0-12.

Before enabling publication:

  1. confirm that zcode-app-cli is the npm package name you control;
  2. review the licenses of the selected Desktop artifact and its dependencies. The public first-party source is Apache-2.0, but its source revision is not the provenance record for the extracted binary. Keep the license and copied notices in LICENSES/, the runtime modification notice, and the artifact metadata. The four document-related plugins are included in this project's non-commercial distribution with their original skill license files. See Third-party content;
  3. under the GitHub repository's Settings → Actions → General, enable Allow GitHub Actions to create and approve pull requests;
  4. open the package on npmjs.com and select Settings → Trusted Publisher → GitHub Actions;
  5. enter the GitHub organization or user, repository, and workflow filename publish.yml; leave the environment name empty because this workflow does not use a GitHub Environment, and select npm publish under Allowed actions;
  6. save the publisher, prepare a cli release, and merge its Release PR to verify an OIDC publication.

The publisher runs on a GitHub-hosted runner with Node 24, grants id-token: write, and updates npm to the current release. It never reads an NPM_TOKEN repository secret; npm attaches provenance from the OIDC identity. After verifying the first OIDC release, npm recommends setting Publishing access to require 2FA and disallow tokens, then revoking any obsolete automation token.

The publisher skips an identical existing version, refuses older versions, verifies every existing npm release's gitHead, and refuses to reuse a tag that points at another commit. The latest dist-tag therefore advances only to the newest validated App-plus-build release.