diff --git a/.github/workflows/release-components.yml b/.github/workflows/release-components.yml
index 56317e4f..c00c471b 100644
--- a/.github/workflows/release-components.yml
+++ b/.github/workflows/release-components.yml
@@ -8,24 +8,24 @@ jobs:
release-microcontroller:
name: Build and Upload microcontroller
runs-on: ubuntu-latest
+ permissions:
+ contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Create ZIP of 'microcontroller' directory
- run: zip -r release-microcontroller-${{ github.ref_name }}.zip microcontroller
+ env:
+ TAG_NAME: ${{ github.ref_name }}
+ run: zip -r "release-microcontroller-${TAG_NAME}.zip" microcontroller
- name: Upload microcontroller ZIP to Release
- uses: actions/upload-release-asset@v1
- with:
- upload_url: ${{ github.event.release.upload_url }}
- asset_path: ./release-microcontroller-${{ github.ref_name }}.zip
- asset_name: release-microcontroller-${{ github.ref_name }}.zip
- asset_content_type: application/zip
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ TAG_NAME: ${{ github.ref_name }}
+ run: gh release upload "$TAG_NAME" "release-microcontroller-${TAG_NAME}.zip" --clobber
+
release-lang-cli-notebook:
name: Publish @bscript/lang, @bscript/cli, and @bscript/notebook
runs-on: ubuntu-latest
@@ -48,18 +48,25 @@ jobs:
- name: Determine npm dist-tag
id: npm_tag
+ env:
+ IS_PRERELEASE: ${{ github.event.release.prerelease }}
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
- if [ "${{ github.event.release.prerelease }}" = "true" ]; then
- NPM_TAG=$(node -e "
- const m = process.argv[1].match(/-([0-9A-Za-z-]+)/);
+ if [ "$IS_PRERELEASE" = "true" ]; then
+ NPM_TAG=$(node -e '
+ const version = process.argv[1];
+ const m = version.match(/^\d+\.\d+\.\d+-([0-9A-Za-z-]+)/);
if (!m) {
- console.error('::error::GitHub pre-release requires a semver prerelease segment (e.g. 2.0.0-alpha.1)');
+ console.error("::error::GitHub pre-release requires a semver prerelease segment (e.g. 2.0.0-alpha.1)");
+ process.exit(1);
+ }
+ if (/^\d+$/.test(m[1])) {
+ console.error("::error::Prerelease identifier must not be numeric (" + m[1] + "); use e.g. 2.0.0-alpha.1");
process.exit(1);
}
process.stdout.write(m[1]);
- " "$TAG_VERSION")
+ ' "$TAG_VERSION")
echo "Pre-release: publishing to npm dist-tag '${NPM_TAG}' (version ${TAG_VERSION})"
else
if [[ "$TAG_VERSION" == *-* ]]; then
@@ -71,49 +78,39 @@ jobs:
fi
echo "tag=${NPM_TAG}" >> "$GITHUB_OUTPUT"
+ echo "version=${TAG_VERSION}" >> "$GITHUB_OUTPUT"
- - name: Verify Version of @bscript/lang Matches Tag
+ - name: Verify Package Versions Match Tag
+ env:
+ TAG_VERSION: ${{ steps.npm_tag.outputs.version }}
run: |
- TAG_VERSION="${GITHUB_REF_NAME#v}"
- PKG_VERSION=$(node -p "require('./lang/package.json').version")
-
- if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
- echo "::error::Version Mismatch! Tag ($TAG_VERSION) != ./lang/package.json ($PKG_VERSION)"
- exit 1
- fi
- echo "Version check of @bscript/lang passed: $TAG_VERSION"
+ node -e '
+ const fs = require("fs");
+ const tagVersion = process.env.TAG_VERSION;
+ const workspaces = ["lang", "notebook", "cli"];
+ const errors = [];
- - name: Verify Version of @bscript/cli Matches Tag and @bscript/cli Installs Correct @bscript/lang Version
- run: |
- TAG_VERSION="${GITHUB_REF_NAME#v}"
- PKG_VERSION=$(node -p "require('./cli/package.json').version")
- DEP_LANG_VERSION=$(node -p "require('./cli/package.json').dependencies['@bscript/lang']")
-
- if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
- echo "::error::Version Mismatch! Tag ($TAG_VERSION) != ./cli/package.json ($PKG_VERSION)"
- exit 1
- fi
- if [ "$TAG_VERSION" != "$DEP_LANG_VERSION" ]; then
- echo "::error::Version Mismatch! @bscript/lang@($DEP_LANG_VERSION) in dependencies is incorrect."
- exit 1
- fi
- echo "Version check of @bscript/cli passed: $TAG_VERSION"
+ for (const workspace of workspaces) {
+ const pkg = JSON.parse(fs.readFileSync(`./${workspace}/package.json`, "utf8"));
- - name: Verify Version of @bscript/notebook Matches Tag and @bscript/notebook Installs Correct @bscript/lang Version
- run: |
- TAG_VERSION="${GITHUB_REF_NAME#v}"
- PKG_VERSION=$(node -p "require('./notebook/package.json').version")
- DEP_LANG_VERSION=$(node -p "require('./notebook/package.json').dependencies['@bscript/lang']")
-
- if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
- echo "::error::Version Mismatch! Tag ($TAG_VERSION) != ./notebook/package.json ($PKG_VERSION)"
- exit 1
- fi
- if [ "$TAG_VERSION" != "$DEP_LANG_VERSION" ]; then
- echo "::error::Version Mismatch! @bscript/lang@($DEP_LANG_VERSION) in dependencies is incorrect."
- exit 1
- fi
- echo "Version check of @bscript/notebook passed: $TAG_VERSION"
+ if (pkg.version !== tagVersion) {
+ errors.push(`${pkg.name}: version ${pkg.version} does not match tag ${tagVersion}`);
+ }
+
+ for (const [dep, range] of Object.entries(pkg.dependencies ?? {})) {
+ if (dep.startsWith("@bscript/") && range !== tagVersion) {
+ errors.push(`${pkg.name}: dependency ${dep}@${range} must be pinned to ${tagVersion}`);
+ }
+ }
+ }
+
+ if (errors.length > 0) {
+ for (const error of errors) console.error(`::error::${error}`);
+ process.exit(1);
+ }
+
+ console.log(`Version check passed for ${workspaces.join(", ")}: ${tagVersion}`);
+ '
- name: Install Dependencies
run: npm ci
@@ -121,14 +118,40 @@ jobs:
- name: Build Packages
run: npm run build --workspaces --if-present
+ # Published in dependency order (lang -> notebook -> cli) so that a freshly
+ # published package can always resolve the @bscript/* versions it depends on.
- name: Publish @bscript/lang to npm
working-directory: ./lang
- run: npm publish --tag ${{ steps.npm_tag.outputs.tag }} || echo 'Failed or skipped publishing @bscript/lang'
+ env:
+ NPM_TAG: ${{ steps.npm_tag.outputs.tag }}
+ TAG_VERSION: ${{ steps.npm_tag.outputs.version }}
+ run: |
+ if npm view "@bscript/lang@${TAG_VERSION}" version > /dev/null 2>&1; then
+ echo "@bscript/lang@${TAG_VERSION} is already published; skipping."
+ exit 0
+ fi
+ npm publish --tag "$NPM_TAG"
- - name: Publish @bscript/cli to npm
- working-directory: ./cli
- run: npm publish --tag ${{ steps.npm_tag.outputs.tag }} || echo 'Failed or skipped publishing @bscript/cli'
-
- name: Publish @bscript/notebook to npm
working-directory: ./notebook
- run: npm publish --tag ${{ steps.npm_tag.outputs.tag }} || echo 'Failed or skipped publishing @bscript/notebook'
+ env:
+ NPM_TAG: ${{ steps.npm_tag.outputs.tag }}
+ TAG_VERSION: ${{ steps.npm_tag.outputs.version }}
+ run: |
+ if npm view "@bscript/notebook@${TAG_VERSION}" version > /dev/null 2>&1; then
+ echo "@bscript/notebook@${TAG_VERSION} is already published; skipping."
+ exit 0
+ fi
+ npm publish --tag "$NPM_TAG"
+
+ - name: Publish @bscript/cli to npm
+ working-directory: ./cli
+ env:
+ NPM_TAG: ${{ steps.npm_tag.outputs.tag }}
+ TAG_VERSION: ${{ steps.npm_tag.outputs.version }}
+ run: |
+ if npm view "@bscript/cli@${TAG_VERSION}" version > /dev/null 2>&1; then
+ echo "@bscript/cli@${TAG_VERSION} is already published; skipping."
+ exit 0
+ fi
+ npm publish --tag "$NPM_TAG"
diff --git a/.github/workflows/release-website.yml b/.github/workflows/release-website.yml
index 41de78da..cc1f2d99 100644
--- a/.github/workflows/release-website.yml
+++ b/.github/workflows/release-website.yml
@@ -36,14 +36,18 @@ jobs:
- name: Determine Version
id: determine_version
+ env:
+ EVENT_NAME: ${{ github.event_name }}
+ TAG_NAME: ${{ github.ref_name }}
+ RELEASE_IS_PRERELEASE: ${{ github.event.release.prerelease }}
+ INPUT_VERSION: ${{ inputs.version }}
run: |
# 1. Get raw version number (e.g. 2.0.5 or 2.1.0-alpha.1)
- if [ "${{ github.event_name }}" == "release" ]; then
- TAG_NAME=${{ github.ref_name }}
- RAW_VERSION=${TAG_NAME#v}
- IS_PRERELEASE="${{ github.event.release.prerelease }}"
+ if [ "$EVENT_NAME" = "release" ]; then
+ RAW_VERSION="${TAG_NAME#v}"
+ IS_PRERELEASE="$RELEASE_IS_PRERELEASE"
else
- RAW_VERSION="${{ inputs.version }}"
+ RAW_VERSION="$INPUT_VERSION"
if [[ "$RAW_VERSION" == *-* ]]; then
IS_PRERELEASE="true"
else
@@ -53,8 +57,14 @@ jobs:
echo "Detected raw version: $RAW_VERSION"
echo "Pre-release: $IS_PRERELEASE"
- # 2. Validate GitHub release type vs semver
- if [ "${{ github.event_name }}" == "release" ]; then
+ # 2. Validate the version format
+ if ! [[ "$RAW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
+ echo "::error::Invalid version: ${RAW_VERSION}. Expected format like 2.0.5 or 2.1.0-alpha.1"
+ exit 1
+ fi
+
+ # 3. Validate GitHub release type vs semver
+ if [ "$EVENT_NAME" = "release" ]; then
if [ "$IS_PRERELEASE" = "true" ] && [[ "$RAW_VERSION" != *-* ]]; then
echo "::error::GitHub pre-release requires a semver prerelease segment (e.g. 2.1.0-alpha.1)"
exit 1
@@ -65,25 +75,38 @@ jobs:
fi
fi
- # 3. Convert to Docusaurus doc version
+ # 4. Convert to Docusaurus doc version
if [ "$IS_PRERELEASE" = "true" ]; then
- DOC_VERSION=$(node -e "
- const m = process.argv[1].match(/^(\d+\.\d+\.\d+)-([0-9A-Za-z-]+)/);
+ DOC_VERSION=$(node -e '
+ const version = process.argv[1];
+ const m = version.match(/^(\d+\.\d+\.\d+)-([0-9A-Za-z-]+)/);
if (!m) {
- console.error('::error::Could not derive doc version from prerelease (${RAW_VERSION}). Expected format like 2.1.0-alpha.1');
+ console.error("::error::Could not derive doc version from prerelease (" + version + "). Expected format like 2.1.0-alpha.1");
process.exit(1);
}
- process.stdout.write(m[1] + '-' + m[2].split('.')[0] + '.x');
- " "$RAW_VERSION")
+ process.stdout.write(m[1] + "-" + m[2] + ".x");
+ ' "$RAW_VERSION")
else
BASE_VER=${RAW_VERSION%.*}
DOC_VERSION="${BASE_VER}.x"
fi
+ # 5. Build the pull request texts. They contain ": ", which is not valid inside
+ # an unquoted YAML value in the create-pull-request step.
+ if [ "$IS_PRERELEASE" = "true" ]; then
+ PR_TITLE="docs: update pre-release version ${DOC_VERSION} (${RAW_VERSION})"
+ PR_BODY="Automated docs update for pre-release ${DOC_VERSION} (tag version ${RAW_VERSION})."
+ else
+ PR_TITLE="docs: update version ${DOC_VERSION}"
+ PR_BODY="Automated docs update for version ${DOC_VERSION}."
+ fi
+
echo "Target Docusaurus Version: $DOC_VERSION"
- echo "doc_version=$DOC_VERSION" >> $GITHUB_OUTPUT
- echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT
- echo "raw_version=$RAW_VERSION" >> $GITHUB_OUTPUT
+ echo "doc_version=$DOC_VERSION" >> "$GITHUB_OUTPUT"
+ echo "is_prerelease=$IS_PRERELEASE" >> "$GITHUB_OUTPUT"
+ echo "raw_version=$RAW_VERSION" >> "$GITHUB_OUTPUT"
+ echo "pr_title=$PR_TITLE" >> "$GITHUB_OUTPUT"
+ echo "pr_body=$PR_BODY" >> "$GITHUB_OUTPUT"
- name: Remove prerelease doc versions on stable release
if: steps.determine_version.outputs.is_prerelease != 'true'
@@ -117,17 +140,33 @@ jobs:
fi
}
- # e.g. stable 2.1.0 -> 2.1.0-alpha.x, 2.1.0-beta.x
+ # Any prerelease docs whose base version is at or below the stable release are
+ # superseded by it, e.g. stable 2.1.1 removes 2.1.0-alpha.x and 2.1.1-beta.x.
PRERELEASE_VERSIONS=$(
{
if [ -f "$VERSIONS_JSON" ]; then
- jq -r --arg raw "$RAW_VERSION" '.[] | select(startswith($raw + "-") and endswith(".x"))' "$VERSIONS_JSON"
+ jq -r '.[]' "$VERSIONS_JSON"
fi
shopt -s nullglob
- for dir in versioned_docs/version-"${RAW_VERSION}"-*.x; do
+ for dir in versioned_docs/version-*; do
basename "$dir" | sed 's/^version-//'
done
- } | sort -u
+ } | sort -u | node -e '
+ const stable = process.env.RAW_VERSION.split("-")[0].split(".").map(Number);
+ const isSuperseded = (base) => {
+ for (let i = 0; i < 3; i++) {
+ if (base[i] !== stable[i]) return base[i] < stable[i];
+ }
+ return true;
+ };
+
+ for (const line of require("fs").readFileSync(0, "utf8").split("\n")) {
+ const docVersion = line.trim();
+ const m = docVersion.match(/^(\d+)\.(\d+)\.(\d+)-[0-9A-Za-z-]+\.x$/);
+ if (!m) continue;
+ if (isSuperseded(m.slice(1, 4).map(Number))) console.log(docVersion);
+ }
+ '
)
if [ -z "$PRERELEASE_VERSIONS" ]; then
@@ -170,20 +209,40 @@ jobs:
echo "Version $DOC_VERSION does not exist yet. Ready to create."
fi
+ # The pull request has to be based on main, but the snapshot must contain the docs
+ # as they were at the released tag, not whatever landed on main afterwards.
+ - name: Check Out Docs From the Released Tag
+ if: github.event_name == 'release'
+ working-directory: ./website
+ env:
+ TAG_NAME: ${{ github.ref_name }}
+ run: |
+ if git rev-parse --verify "refs/tags/${TAG_NAME}" > /dev/null 2>&1; then
+ git checkout "refs/tags/${TAG_NAME}" -- docs sidebars.ts
+ echo "Using docs from tag ${TAG_NAME}."
+ else
+ echo "::warning::Tag ${TAG_NAME} not found; falling back to the docs on main."
+ fi
+
- name: Run Docusaurus Versioning
working-directory: ./website
env:
DOC_VERSION: ${{ steps.determine_version.outputs.doc_version }}
run: |
echo "Creating version $DOC_VERSION..."
- npm run docusaurus docs:version $DOC_VERSION
+ npm run docusaurus docs:version "$DOC_VERSION"
+
+ - name: Restore Docs From main
+ if: github.event_name == 'release'
+ working-directory: ./website
+ run: git restore --source=HEAD --staged --worktree -- docs sidebars.ts
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- commit-message: ${{ steps.determine_version.outputs.is_prerelease == 'true' && format('docs: update pre-release version {0} ({1})', steps.determine_version.outputs.doc_version, steps.determine_version.outputs.raw_version) || format('docs: update version {0}', steps.determine_version.outputs.doc_version) }}
- title: ${{ steps.determine_version.outputs.is_prerelease == 'true' && format('docs: update pre-release version {0} ({1})', steps.determine_version.outputs.doc_version, steps.determine_version.outputs.raw_version) || format('docs: update version {0}', steps.determine_version.outputs.doc_version) }}
- body: ${{ steps.determine_version.outputs.is_prerelease == 'true' && format('Automated docs update for pre-release {0} (tag version {1}).', steps.determine_version.outputs.doc_version, steps.determine_version.outputs.raw_version) || format('Automated docs update for version {0}.', steps.determine_version.outputs.doc_version) }}
+ commit-message: ${{ steps.determine_version.outputs.pr_title }}
+ title: ${{ steps.determine_version.outputs.pr_title }}
+ body: ${{ steps.determine_version.outputs.pr_body }}
branch: docs-version-${{ steps.determine_version.outputs.doc_version }}
base: main
diff --git a/cli/package.json b/cli/package.json
index dce4a1c3..5b37105c 100644
--- a/cli/package.json
+++ b/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@bscript/cli",
- "version": "2.0.2",
+ "version": "2.1.0-alpha.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"engines": {
@@ -60,8 +60,8 @@
},
"dependencies": {
"@abandonware/noble": "^1.9.2-26",
- "@bscript/lang": "2.0.2",
- "@bscript/notebook": "2.0.2",
+ "@bscript/lang": "2.1.0-alpha.1",
+ "@bscript/notebook": "2.1.0-alpha.1",
"axios": "^1.12.2",
"chalk": "^4.1.2",
"commander": "^14.0.1",
diff --git a/lang/package.json b/lang/package.json
index 8fb2e163..1745d3ae 100644
--- a/lang/package.json
+++ b/lang/package.json
@@ -1,6 +1,6 @@
{
"name": "@bscript/lang",
- "version": "2.0.2",
+ "version": "2.1.0-alpha.1",
"exports": "./dist/index.js",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/notebook/package.json b/notebook/package.json
index 2e80f5f8..535aa62d 100644
--- a/notebook/package.json
+++ b/notebook/package.json
@@ -1,6 +1,6 @@
{
"name": "@bscript/notebook",
- "version": "2.0.2",
+ "version": "2.1.0-alpha.1",
"engines": {
"node": ">=18.0.0"
},
diff --git a/package.json b/package.json
index 87073790..edcad10b 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
"typescript": "^5.9.2"
},
"scripts": {
- "build": "tsc -b"
+ "build": "tsc -b",
+ "build:all": "tsc -b && npm run build -w @bscript/notebook"
},
"allowScripts": {
"@abandonware/noble@1.9.2-26": true,
diff --git a/website/docs/reference/cli.md b/website/docs/reference/cli.md
index bc92a50f..d4ad257d 100644
--- a/website/docs/reference/cli.md
+++ b/website/docs/reference/cli.md
@@ -1,15 +1,15 @@
+import InstallCli from '@site/src/components/InstallCli';
+
# CLI
The BlueScript CLI (`bscript`) is the primary tool for managing projects, setting up board environments, and running code on your devices.
## Installation
-```bash
-npm install -g @bscript/cli
-```
+
:::info Prerequisites
-On Windows, install the Visual C++ Build Environment before `npm install -g @bscript/cli` (required by node-gyp for native dependencies such as `serialport`). See [Windows prerequisites](../tutorial/get-started/setup-environment-windows.md).
+On Windows, install the Visual C++ Build Environment before installing the CLI (required by node-gyp for native dependencies such as `serialport`). See [Windows prerequisites](../tutorial/get-started/setup-environment-windows.md).
:::
## Project Management
diff --git a/website/docs/tutorial/get-started/setup-environment.md b/website/docs/tutorial/get-started/setup-environment.md
index 4fc6b3a1..fa7fe81b 100644
--- a/website/docs/tutorial/get-started/setup-environment.md
+++ b/website/docs/tutorial/get-started/setup-environment.md
@@ -1,4 +1,5 @@
import OsTabs from '@site/src/components/OsTabs';
+import InstallCli from '@site/src/components/InstallCli';
import TabItem from '@theme/TabItem';
# Set up your environment
@@ -52,25 +53,19 @@ BlueScript provides a command-line interface (CLI) to manage projects and commun
-```bash
-npm install -g @bscript/cli
-```
+
Install the [Visual C++ Build Environment](./setup-environment-windows.md#nodejs-and-visual-c-build-environment) first, then:
-```bash
-npm install -g @bscript/cli
-```
+
-```bash
-npm install -g @bscript/cli
-```
+
diff --git a/website/docs/tutorial/guides/try-without-microcontroller.md b/website/docs/tutorial/guides/try-without-microcontroller.md
index 53bdabcd..699f716f 100644
--- a/website/docs/tutorial/guides/try-without-microcontroller.md
+++ b/website/docs/tutorial/guides/try-without-microcontroller.md
@@ -3,6 +3,7 @@ sidebar_label: Try Without Microcontroller
---
import OsTabs from '@site/src/components/OsTabs';
+import InstallCli from '@site/src/components/InstallCli';
import TabItem from '@theme/TabItem';
# Try Without Microcontroller
@@ -57,9 +58,7 @@ xcode-select --install
If you have not installed the CLI yet:
-```bash
-npm install -g @bscript/cli
-```
+
On Windows, install the [Visual C++ Build Environment](../get-started/setup-environment-windows.md#nodejs-and-visual-c-build-environment) before running this command.
diff --git a/website/src/components/InstallCli/index.tsx b/website/src/components/InstallCli/index.tsx
new file mode 100644
index 00000000..3451434c
--- /dev/null
+++ b/website/src/components/InstallCli/index.tsx
@@ -0,0 +1,87 @@
+import {
+ useActivePlugin,
+ useDocsPreferredVersion,
+ useDocsVersion,
+ useDocVersionSuggestions,
+} from '@docusaurus/plugin-content-docs/client';
+import Link from '@docusaurus/Link';
+import Admonition from '@theme/Admonition';
+import CodeBlock from '@theme/CodeBlock';
+
+const STABLE_DOC_VERSION = /^\d+\.\d+\.x$/;
+const PRERELEASE_DOC_VERSION = /^\d+\.\d+\.\d+-([0-9A-Za-z-]+)\.x$/;
+
+const FROM_SOURCE_INSTALL = `git clone https://github.com/csg-tokyo/bluescript.git
+cd bluescript
+npm install
+npm run build:all
+cd cli
+npm link`;
+
+/**
+ * Map a Docusaurus docs version to an npm install package specifier.
+ * - last stable → @bscript/cli (latest)
+ * - older stable (e.g. 2.0.x) → @bscript/cli@2.0
+ * - prerelease (e.g. 2.1.0-alpha.x) → @bscript/cli@alpha (npm dist-tag)
+ */
+export function toNpmPackageSpec(
+ docVersion: string,
+ isLast = false,
+): string {
+ const prerelease = docVersion.match(PRERELEASE_DOC_VERSION);
+ if (prerelease) {
+ return `@bscript/cli@${prerelease[1]}`;
+ }
+
+ if (isLast && STABLE_DOC_VERSION.test(docVersion)) {
+ return '@bscript/cli';
+ }
+
+ if (STABLE_DOC_VERSION.test(docVersion)) {
+ return `@bscript/cli@${docVersion.replace(/\.x$/, '')}`;
+ }
+
+ return '@bscript/cli';
+}
+
+function NextVersionNote(): JSX.Element {
+ const {pluginId} = useActivePlugin({failfast: true});
+ const {savePreferredVersionName} = useDocsPreferredVersion(pluginId);
+ const {latestDocSuggestion, latestVersionSuggestion} =
+ useDocVersionSuggestions(pluginId);
+
+ const latestDocPath =
+ latestDocSuggestion?.path ??
+ latestVersionSuggestion.docs.find(
+ (doc) => doc.id === latestVersionSuggestion.mainDocId,
+ )!.path;
+
+ return (
+
+ The Next version is not released yet, so it cannot be installed from
+ npm. For the released package, switch to the{' '}
+ savePreferredVersionName(latestVersionSuggestion.name)}>
+ latest version ({latestVersionSuggestion.label})
+
+ .
+
+ );
+}
+
+export default function InstallCli(): JSX.Element {
+ const {version, isLast} = useDocsVersion();
+
+ if (version === 'current') {
+ return (
+ <>
+ {FROM_SOURCE_INSTALL}
+
+ >
+ );
+ }
+
+ const pkg = toNpmPackageSpec(version, isLast);
+ return {`npm install -g ${pkg}`};
+}
diff --git a/website/versioned_docs/version-2.0.x/reference/cli.md b/website/versioned_docs/version-2.0.x/reference/cli.md
index 9e5ffab7..85bc4158 100644
--- a/website/versioned_docs/version-2.0.x/reference/cli.md
+++ b/website/versioned_docs/version-2.0.x/reference/cli.md
@@ -1,12 +1,12 @@
+import InstallCli from '@site/src/components/InstallCli';
+
# CLI
The BlueScript CLI (`bscript`) is the primary tool for managing projects, setting up board environments, and running code on your devices.
## Installation
-```bash
-npm install -g @bscript/cli
-```
+
## Project Management
diff --git a/website/versioned_docs/version-2.0.x/tutorial/get-started/setup-environment.md b/website/versioned_docs/version-2.0.x/tutorial/get-started/setup-environment.md
index c8abd70b..00fd199f 100644
--- a/website/versioned_docs/version-2.0.x/tutorial/get-started/setup-environment.md
+++ b/website/versioned_docs/version-2.0.x/tutorial/get-started/setup-environment.md
@@ -1,3 +1,5 @@
+import InstallCli from '@site/src/components/InstallCli';
+
# Set up your environment
:::danger macOS Only
@@ -24,9 +26,7 @@ Before we begin, ensure you have the following:
BlueScript provides a command-line interface (CLI) to manage projects and communicate with your device. Install it globally using npm:
-```bash
-npm install -g @bscript/cli
-```
+
Verify the installation: