From 3af9b5f4448f4b6d9fd536344208a03fe075d578 Mon Sep 17 00:00:00 2001 From: Yonghye Kwon Date: Wed, 11 Mar 2026 00:02:10 +0900 Subject: [PATCH] ci: add release workflow for crates.io and npm binary distribution Set up cross-platform release CI triggered by version tags (v*). Builds native binaries for 5 targets (macOS arm64/x64, Linux x64/arm64, Windows x64), publishes Rust crates to crates.io in dependency order, and distributes CLI binaries via platform-specific npm packages. - Add publish metadata (description, repository, keywords) to all crates - Add LICENSE (MIT) - Create npm wrapper package with platform-specific optionalDependencies - Create GitHub Actions release workflow with matrix build - Add version-bump script for synchronized version updates - Update README with installation instructions Co-Authored-By: Claude Opus 4.6 Signed-off-by: Yonghye Kwon --- .github/workflows/release.yml | 250 +++++++++++++++++++++++++ .gitignore | 3 + Cargo.toml | 4 + LICENSE | 21 +++ README.md | 35 ++++ crates/marknest-core/Cargo.toml | 6 + crates/marknest-server/Cargo.toml | 10 +- crates/marknest-wasm/Cargo.toml | 6 +- crates/marknest/Cargo.toml | 9 +- npm/marknest-darwin-arm64/package.json | 14 ++ npm/marknest-darwin-x64/package.json | 14 ++ npm/marknest-linux-arm64/package.json | 14 ++ npm/marknest-linux-x64/package.json | 14 ++ npm/marknest-win32-x64/package.json | 14 ++ npm/marknest/bin/marknest | 58 ++++++ npm/marknest/package.json | 31 +++ references/INDEX.md | 1 + references/release-ci-npm-binary.md | 22 +++ scripts/version-bump.sh | 58 ++++++ 19 files changed, 580 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 LICENSE create mode 100644 npm/marknest-darwin-arm64/package.json create mode 100644 npm/marknest-darwin-x64/package.json create mode 100644 npm/marknest-linux-arm64/package.json create mode 100644 npm/marknest-linux-x64/package.json create mode 100644 npm/marknest-win32-x64/package.json create mode 100755 npm/marknest/bin/marknest create mode 100644 npm/marknest/package.json create mode 100644 references/release-ci-npm-binary.md create mode 100755 scripts/version-bump.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f2129f1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,250 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + name: Build (${{ matrix.target }}) + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-apple-darwin + os: macos-14 + npm_pkg: marknest-darwin-arm64 + binary_name: marknest + - target: x86_64-apple-darwin + os: macos-13 + npm_pkg: marknest-darwin-x64 + binary_name: marknest + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + npm_pkg: marknest-linux-x64 + binary_name: marknest + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + npm_pkg: marknest-linux-arm64 + binary_name: marknest + use_cross: true + - target: x86_64-pc-windows-msvc + os: windows-latest + npm_pkg: marknest-win32-x64 + binary_name: marknest.exe + runs-on: ${{ matrix.os }} + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Install cross (Linux ARM64) + if: matrix.use_cross + run: cargo install cross --git https://github.com/cross-rs/cross + + - name: Build release binary + run: | + if [ "${{ matrix.use_cross }}" = "true" ]; then + cross build --release --target ${{ matrix.target }} -p marknest + else + cargo build --release --target ${{ matrix.target }} -p marknest + fi + shell: bash + + - name: Prepare artifact + run: | + mkdir -p staging + cp target/${{ matrix.target }}/release/${{ matrix.binary_name }} staging/ + shell: bash + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: binary-${{ matrix.target }} + path: staging/${{ matrix.binary_name }} + retention-days: 1 + + publish-crates: + name: Publish to crates.io + needs: build + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Publish marknest-core + run: cargo publish -p marknest-core --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + + - name: Wait for crates.io index + run: sleep 30 + + - name: Publish marknest + run: cargo publish -p marknest --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + + - name: Wait for crates.io index + run: sleep 30 + + - name: Publish marknest-server + run: cargo publish -p marknest-server --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + + publish-npm: + name: Publish to npm + needs: build + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://registry.npmjs.org + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Place binaries into npm packages + run: | + declare -A TARGET_TO_PKG=( + ["aarch64-apple-darwin"]="marknest-darwin-arm64" + ["x86_64-apple-darwin"]="marknest-darwin-x64" + ["x86_64-unknown-linux-gnu"]="marknest-linux-x64" + ["aarch64-unknown-linux-gnu"]="marknest-linux-arm64" + ["x86_64-pc-windows-msvc"]="marknest-win32-x64" + ) + + for target in "${!TARGET_TO_PKG[@]}"; do + pkg="${TARGET_TO_PKG[$target]}" + pkg_dir="npm/${pkg}" + mkdir -p "${pkg_dir}/bin" + + if [ "$target" = "x86_64-pc-windows-msvc" ]; then + cp "artifacts/binary-${target}/marknest.exe" "${pkg_dir}/bin/" + else + cp "artifacts/binary-${target}/marknest" "${pkg_dir}/bin/" + chmod +x "${pkg_dir}/bin/marknest" + fi + done + + - name: Publish platform packages + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + for pkg_dir in npm/marknest-*/; do + echo "Publishing $(basename $pkg_dir)..." + cd "$pkg_dir" + npm publish --access public || true + cd ../.. + done + + - name: Publish umbrella package + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + cd npm/marknest + npm publish --access public + + github-release: + name: GitHub Release + needs: build + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Package release assets + run: | + mkdir -p release + + declare -A TARGETS=( + ["aarch64-apple-darwin"]="marknest-aarch64-apple-darwin" + ["x86_64-apple-darwin"]="marknest-x86_64-apple-darwin" + ["x86_64-unknown-linux-gnu"]="marknest-x86_64-unknown-linux-gnu" + ["aarch64-unknown-linux-gnu"]="marknest-aarch64-unknown-linux-gnu" + ["x86_64-pc-windows-msvc"]="marknest-x86_64-pc-windows-msvc" + ) + + for target in "${!TARGETS[@]}"; do + asset_name="${TARGETS[$target]}" + if [ "$target" = "x86_64-pc-windows-msvc" ]; then + cp "artifacts/binary-${target}/marknest.exe" "release/${asset_name}.exe" + else + cp "artifacts/binary-${target}/marknest" "release/${asset_name}" + chmod +x "release/${asset_name}" + tar -czf "release/${asset_name}.tar.gz" -C release "${asset_name}" + rm "release/${asset_name}" + fi + done + + - name: Get previous tag + id: prev_tag + run: | + PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") + echo "tag=${PREV_TAG}" >> "$GITHUB_OUTPUT" + + - name: Build contributors list + id: contributors + run: | + if [ -n "${{ steps.prev_tag.outputs.tag }}" ]; then + CONTRIBUTORS=$(git log ${{ steps.prev_tag.outputs.tag }}..HEAD --format='%an' | sort -u | grep -v 'dependabot' || true) + else + CONTRIBUTORS=$(git log --format='%an' | sort -u | grep -v 'dependabot' || true) + fi + # Write to file to avoid quoting issues + echo "$CONTRIBUTORS" > /tmp/contributors.txt + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ github.token }} + run: | + TAG="${GITHUB_REF_NAME}" + CONTRIBUTORS=$(cat /tmp/contributors.txt) + + BODY="## Installation + + ### Cargo + \`\`\`sh + cargo install marknest + \`\`\` + + ### npm / npx + \`\`\`sh + npx marknest --help + # or install globally + npm install -g marknest + \`\`\` + + ### Download binary + Download the appropriate binary for your platform from the assets below. + + ## Contributors + ${CONTRIBUTORS} + " + + gh release create "$TAG" release/* \ + --title "$TAG" \ + --notes "$BODY" diff --git a/.gitignore b/.gitignore index 87c669f..d161d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ dist/ .claude/ validation/.cache/ validation/.runs/ + +# npm platform package binaries (populated during CI release) +npm/marknest-*/bin/ diff --git a/Cargo.toml b/Cargo.toml index eee776c..318898d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,14 @@ resolver = "2" edition = "2024" license = "MIT" version = "0.1.0" +repository = "https://github.com/developer0hye/marknest" +homepage = "https://github.com/developer0hye/marknest" [workspace.dependencies] ammonia = "4.1.2" emojis = "0.6.4" +marknest-core = { version = "0.1.0", path = "crates/marknest-core" } +marknest = { version = "0.1.0", path = "crates/marknest" } pulldown-cmark = "0.13" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a40f9a9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Yonghye Kwon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index f2393b0..3cf00ac 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,41 @@ Key capabilities: - `validation/`: pinned 60-entry README corpus manifest, baseline artifacts, and hybrid PDF fidelity validator - `Dockerfile`: shared CLI and fallback-server runtime image +## Installation + +### Cargo + +```bash +cargo install marknest +``` + +### npm / npx + +```bash +# Run directly +npx marknest validate README.md + +# Or install globally +npm install -g marknest +marknest convert README.md -o output.pdf +``` + +### From source + +```bash +git clone https://github.com/developer0hye/marknest.git +cd marknest +cargo install --path crates/marknest +``` + +For PDF rendering, install the Playwright headless shell: + +```bash +npx playwright install chromium +# or for headless-only environments: +npx playwright install --with-deps chromium +``` + ## Development Run the formatter: diff --git a/crates/marknest-core/Cargo.toml b/crates/marknest-core/Cargo.toml index 0075323..a11b19f 100644 --- a/crates/marknest-core/Cargo.toml +++ b/crates/marknest-core/Cargo.toml @@ -1,8 +1,14 @@ [package] name = "marknest-core" +description = "Core library for Markdown workspace analysis, ZIP inspection, and self-contained HTML rendering" edition.workspace = true license.workspace = true version.workspace = true +repository.workspace = true +homepage.workspace = true +readme = "../../README.md" +keywords = ["markdown", "pdf", "html", "converter", "documentation"] +categories = ["command-line-utilities", "text-processing", "web-programming"] [dependencies] ammonia.workspace = true diff --git a/crates/marknest-server/Cargo.toml b/crates/marknest-server/Cargo.toml index 33c21ae..085e62c 100644 --- a/crates/marknest-server/Cargo.toml +++ b/crates/marknest-server/Cargo.toml @@ -1,13 +1,19 @@ [package] name = "marknest-server" +description = "Local HTTP fallback service for high-quality Markdown-to-PDF conversion via Playwright" edition.workspace = true license.workspace = true version.workspace = true +repository.workspace = true +homepage.workspace = true +readme = "../../README.md" +keywords = ["markdown", "pdf", "server", "converter"] +categories = ["command-line-utilities", "web-programming"] [dependencies] axum = { version = "0.8", features = ["multipart"] } -marknest = { path = "../marknest" } -marknest-core = { path = "../marknest-core" } +marknest.workspace = true +marknest-core.workspace = true serde.workspace = true serde_json.workspace = true tokio = { version = "1", features = ["rt-multi-thread", "macros", "net"] } diff --git a/crates/marknest-wasm/Cargo.toml b/crates/marknest-wasm/Cargo.toml index 8c8fd34..547aada 100644 --- a/crates/marknest-wasm/Cargo.toml +++ b/crates/marknest-wasm/Cargo.toml @@ -1,15 +1,19 @@ [package] name = "marknest-wasm" +description = "WASM bindings for MarkNest Markdown workspace analysis and HTML rendering" edition.workspace = true license.workspace = true version.workspace = true +repository.workspace = true +homepage.workspace = true +publish = false [lib] crate-type = ["cdylib", "rlib"] [dependencies] console_error_panic_hook = "0.1" -marknest-core = { path = "../marknest-core" } +marknest-core.workspace = true serde.workspace = true serde_json.workspace = true serde-wasm-bindgen = "0.6" diff --git a/crates/marknest/Cargo.toml b/crates/marknest/Cargo.toml index 86d677b..1fa5746 100644 --- a/crates/marknest/Cargo.toml +++ b/crates/marknest/Cargo.toml @@ -1,11 +1,18 @@ [package] name = "marknest" +description = "Markdown workspace analyzer and PDF converter CLI" edition.workspace = true license.workspace = true version.workspace = true +repository.workspace = true +homepage.workspace = true +readme = "../../README.md" +keywords = ["markdown", "pdf", "cli", "converter", "documentation"] +categories = ["command-line-utilities", "text-processing"] +exclude = ["playwright-runtime/node_modules/**"] [dependencies] -marknest-core = { path = "../marknest-core" } +marknest-core.workspace = true serde.workspace = true serde_json.workspace = true tempfile.workspace = true diff --git a/npm/marknest-darwin-arm64/package.json b/npm/marknest-darwin-arm64/package.json new file mode 100644 index 0000000..cb6e5e4 --- /dev/null +++ b/npm/marknest-darwin-arm64/package.json @@ -0,0 +1,14 @@ +{ + "name": "marknest-darwin-arm64", + "version": "0.1.0", + "description": "marknest binary for macOS ARM64 (Apple Silicon)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "os": ["darwin"], + "cpu": ["arm64"], + "files": ["bin"], + "preferUnpacked": true +} diff --git a/npm/marknest-darwin-x64/package.json b/npm/marknest-darwin-x64/package.json new file mode 100644 index 0000000..36a3dec --- /dev/null +++ b/npm/marknest-darwin-x64/package.json @@ -0,0 +1,14 @@ +{ + "name": "marknest-darwin-x64", + "version": "0.1.0", + "description": "marknest binary for macOS x64 (Intel)", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "os": ["darwin"], + "cpu": ["x64"], + "files": ["bin"], + "preferUnpacked": true +} diff --git a/npm/marknest-linux-arm64/package.json b/npm/marknest-linux-arm64/package.json new file mode 100644 index 0000000..0e58cab --- /dev/null +++ b/npm/marknest-linux-arm64/package.json @@ -0,0 +1,14 @@ +{ + "name": "marknest-linux-arm64", + "version": "0.1.0", + "description": "marknest binary for Linux ARM64", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "os": ["linux"], + "cpu": ["arm64"], + "files": ["bin"], + "preferUnpacked": true +} diff --git a/npm/marknest-linux-x64/package.json b/npm/marknest-linux-x64/package.json new file mode 100644 index 0000000..bf95b76 --- /dev/null +++ b/npm/marknest-linux-x64/package.json @@ -0,0 +1,14 @@ +{ + "name": "marknest-linux-x64", + "version": "0.1.0", + "description": "marknest binary for Linux x64", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "os": ["linux"], + "cpu": ["x64"], + "files": ["bin"], + "preferUnpacked": true +} diff --git a/npm/marknest-win32-x64/package.json b/npm/marknest-win32-x64/package.json new file mode 100644 index 0000000..6e67a9a --- /dev/null +++ b/npm/marknest-win32-x64/package.json @@ -0,0 +1,14 @@ +{ + "name": "marknest-win32-x64", + "version": "0.1.0", + "description": "marknest binary for Windows x64", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "os": ["win32"], + "cpu": ["x64"], + "files": ["bin"], + "preferUnpacked": true +} diff --git a/npm/marknest/bin/marknest b/npm/marknest/bin/marknest new file mode 100755 index 0000000..9ef2d2b --- /dev/null +++ b/npm/marknest/bin/marknest @@ -0,0 +1,58 @@ +#!/usr/bin/env node + +const { execFileSync } = require("child_process"); +const { existsSync } = require("fs"); +const path = require("path"); + +const PLATFORMS = { + "darwin-arm64": "marknest-darwin-arm64", + "darwin-x64": "marknest-darwin-x64", + "linux-x64": "marknest-linux-x64", + "linux-arm64": "marknest-linux-arm64", + "win32-x64": "marknest-win32-x64", +}; + +function getBinaryPath() { + const platformKey = `${process.platform}-${process.arch}`; + const packageName = PLATFORMS[platformKey]; + + if (!packageName) { + throw new Error( + `Unsupported platform: ${platformKey}. ` + + `Supported: ${Object.keys(PLATFORMS).join(", ")}` + ); + } + + const binaryName = process.platform === "win32" ? "marknest.exe" : "marknest"; + + // Try to resolve from node_modules (installed as optionalDependency) + try { + const packageDir = path.dirname(require.resolve(`${packageName}/package.json`)); + const binaryPath = path.join(packageDir, "bin", binaryName); + if (existsSync(binaryPath)) { + return binaryPath; + } + } catch { + // Package not installed + } + + throw new Error( + `Could not find marknest binary for ${platformKey}. ` + + `Please make sure ${packageName} is installed.\n` + + `Try: npm install ${packageName}` + ); +} + +try { + const binaryPath = getBinaryPath(); + const result = execFileSync(binaryPath, process.argv.slice(2), { + stdio: "inherit", + env: process.env, + }); +} catch (error) { + if (error.status !== undefined) { + process.exit(error.status); + } + console.error(error.message); + process.exit(1); +} diff --git a/npm/marknest/package.json b/npm/marknest/package.json new file mode 100644 index 0000000..f4f0435 --- /dev/null +++ b/npm/marknest/package.json @@ -0,0 +1,31 @@ +{ + "name": "marknest", + "version": "0.1.0", + "description": "Markdown workspace analyzer and PDF converter", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/developer0hye/marknest" + }, + "homepage": "https://github.com/developer0hye/marknest", + "keywords": [ + "markdown", + "pdf", + "converter", + "documentation", + "cli" + ], + "bin": { + "marknest": "bin/marknest" + }, + "files": [ + "bin" + ], + "optionalDependencies": { + "marknest-darwin-arm64": "0.1.0", + "marknest-darwin-x64": "0.1.0", + "marknest-linux-x64": "0.1.0", + "marknest-linux-arm64": "0.1.0", + "marknest-win32-x64": "0.1.0" + } +} diff --git a/references/INDEX.md b/references/INDEX.md index 7d4c059..e53309a 100644 --- a/references/INDEX.md +++ b/references/INDEX.md @@ -21,3 +21,4 @@ - `phase8-render-timeouts.md`: Configurable per-item Mermaid and Math runtime timeouts with shared defaults. - `phase8-html-sanitization.md`: HTML fragment sanitization with an allowlist that preserves Markdown rendering features while blocking scripts and unsafe embeds. - `phase8-table-of-contents.md`: Use pulldown-cmark heading events to assign stable heading IDs and build an optional in-document TOC. +- `release-ci-npm-binary.md`: Cross-platform release CI with crates.io and npm binary distribution via platform-specific packages. diff --git a/references/release-ci-npm-binary.md b/references/release-ci-npm-binary.md new file mode 100644 index 0000000..db130ce --- /dev/null +++ b/references/release-ci-npm-binary.md @@ -0,0 +1,22 @@ +# Release CI + npm Binary Distribution + +## Reference +- **esbuild**: Platform-specific npm packages with JS shim bin entry +- **Biome**: `@biomejs/cli-*` optional dependency pattern +- **Pattern**: Umbrella npm package with `optionalDependencies` for platform-specific binary packages + +## Structure +- Umbrella `marknest` npm package detects `process.platform`/`process.arch` +- Platform packages (`marknest-darwin-arm64`, etc.) contain only the binary +- `os` + `cpu` fields in `package.json` let npm auto-select the right package +- CI cross-compiles via GitHub Actions matrix (native + `cross` for linux-arm64) + +## Publish Order (crates.io) +1. `marknest-core` (no internal deps) +2. `marknest` (depends on core) +3. `marknest-server` (depends on both) +4. `marknest-wasm` → `publish = false` (browser-only, no crates.io) + +## Version Sync +- `scripts/version-bump.sh` updates all Cargo.toml + npm package.json files +- Tag push `v*` triggers the release workflow diff --git a/scripts/version-bump.sh b/scripts/version-bump.sh new file mode 100755 index 0000000..1aaacbb --- /dev/null +++ b/scripts/version-bump.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# Bump version across all Cargo.toml and npm package.json files. +# Usage: ./scripts/version-bump.sh 0.2.0 + +set -euo pipefail + +if [ $# -ne 1 ]; then + echo "Usage: $0 " + echo "Example: $0 0.2.0" + exit 1 +fi + +NEW_VERSION="$1" + +# Validate semver format +if ! echo "$NEW_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then + echo "Error: version must be semver (e.g., 0.2.0 or 1.0.0-beta.1)" + exit 1 +fi + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +echo "Bumping version to ${NEW_VERSION}..." + +# Update workspace Cargo.toml version +sed -i.bak "s/^version = \".*\"/version = \"${NEW_VERSION}\"/" "${REPO_ROOT}/Cargo.toml" +rm -f "${REPO_ROOT}/Cargo.toml.bak" + +# Update workspace dependency versions for internal crates +sed -i.bak "s/marknest-core = { version = \"[^\"]*\"/marknest-core = { version = \"${NEW_VERSION}\"/" "${REPO_ROOT}/Cargo.toml" +sed -i.bak "s/marknest = { version = \"[^\"]*\"/marknest = { version = \"${NEW_VERSION}\"/" "${REPO_ROOT}/Cargo.toml" +rm -f "${REPO_ROOT}/Cargo.toml.bak" + +# Update all npm package.json files +for pkg_json in "${REPO_ROOT}"/npm/*/package.json; do + sed -i.bak "s/\"version\": \"[^\"]*\"/\"version\": \"${NEW_VERSION}\"/" "$pkg_json" + rm -f "${pkg_json}.bak" +done + +# Update optionalDependencies versions in umbrella package +UMBRELLA="${REPO_ROOT}/npm/marknest/package.json" +sed -i.bak "s/\"marknest-darwin-arm64\": \"[^\"]*\"/\"marknest-darwin-arm64\": \"${NEW_VERSION}\"/" "$UMBRELLA" +sed -i.bak "s/\"marknest-darwin-x64\": \"[^\"]*\"/\"marknest-darwin-x64\": \"${NEW_VERSION}\"/" "$UMBRELLA" +sed -i.bak "s/\"marknest-linux-x64\": \"[^\"]*\"/\"marknest-linux-x64\": \"${NEW_VERSION}\"/" "$UMBRELLA" +sed -i.bak "s/\"marknest-linux-arm64\": \"[^\"]*\"/\"marknest-linux-arm64\": \"${NEW_VERSION}\"/" "$UMBRELLA" +sed -i.bak "s/\"marknest-win32-x64\": \"[^\"]*\"/\"marknest-win32-x64\": \"${NEW_VERSION}\"/" "$UMBRELLA" +rm -f "${UMBRELLA}.bak" + +echo "Updated Cargo.lock..." +cd "${REPO_ROOT}" && cargo generate-lockfile 2>/dev/null || true + +echo "Done. Version bumped to ${NEW_VERSION}" +echo "" +echo "Next steps:" +echo " 1. Review changes: git diff" +echo " 2. Commit: git commit -am 'chore: bump version to ${NEW_VERSION}'" +echo " 3. Tag: git tag v${NEW_VERSION}" +echo " 4. Push: git push && git push --tags"