diff --git a/INSTALL.md b/INSTALL.md index 96f4d9d..608c4b8 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -5,15 +5,15 @@ ## 1. 推荐:二进制安装(无需 Node) ```bash -curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash +curl -fsSL https://bailian.aliyun.com/install.sh | bash ``` -可选:`BAILIAN_CHANNEL`(默认 `latest`)、`BAILIAN_VERSION`(钉版本)、`BAILIAN_CLI_CDN`(覆盖 CDN 根)。 +可选:默认读 `manifest.json`(正式版);`bash install.sh --channel sync-release` 读 channel 清单做验证;`--version` 钉版本;`--cdn` / `BAILIAN_CLI_CDN` 覆盖资源 CDN 根。 Windows PowerShell: ```powershell -irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex +irm https://bailian.aliyun.com/install.ps1 | iex ``` 校验: diff --git a/README.md b/README.md index 5d7fcd1..e1343fe 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,10 @@ No timeline scrubbing. No frame-by-frame editing. Just one sentence → one vide ```bash # Recommended — no Node required -curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash +curl -fsSL https://bailian.aliyun.com/install.sh | bash # Windows (PowerShell) -irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex +irm https://bailian.aliyun.com/install.ps1 | iex # Node users / developers (Node.js >= 18.17) npm install -g bailian-cli diff --git a/README.zh.md b/README.zh.md index 5ec6326..69eda4b 100644 --- a/README.zh.md +++ b/README.zh.md @@ -76,10 +76,10 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_ ```bash # 推荐 — 无需本机 Node.js -curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash +curl -fsSL https://bailian.aliyun.com/install.sh | bash # Windows(PowerShell) -irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex +irm https://bailian.aliyun.com/install.ps1 | iex # Node 用户 / 开发者(需要 Node.js >= 18.17) npm install -g bailian-cli diff --git a/packages/cli/README.md b/packages/cli/README.md index 5d7fcd1..e1343fe 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -78,10 +78,10 @@ No timeline scrubbing. No frame-by-frame editing. Just one sentence → one vide ```bash # Recommended — no Node required -curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash +curl -fsSL https://bailian.aliyun.com/install.sh | bash # Windows (PowerShell) -irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex +irm https://bailian.aliyun.com/install.ps1 | iex # Node users / developers (Node.js >= 18.17) npm install -g bailian-cli diff --git a/packages/cli/README.zh.md b/packages/cli/README.zh.md index 5ec6326..69eda4b 100644 --- a/packages/cli/README.zh.md +++ b/packages/cli/README.zh.md @@ -76,10 +76,10 @@ _专为 AI Agent 打造,每个命令均可作为结构化工具调用。_ ```bash # 推荐 — 无需本机 Node.js -curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash +curl -fsSL https://bailian.aliyun.com/install.sh | bash # Windows(PowerShell) -irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex +irm https://bailian.aliyun.com/install.ps1 | iex # Node 用户 / 开发者(需要 Node.js >= 18.17) npm install -g bailian-cli diff --git a/packages/core/src/install/cdn.ts b/packages/core/src/install/cdn.ts index 8460a1e..a25dd1b 100644 --- a/packages/core/src/install/cdn.ts +++ b/packages/core/src/install/cdn.ts @@ -5,9 +5,9 @@ * * Layout under the base: * v/.zip —— immutable per-version binaries + SHA256SUMS - * manifest.json —— stable pointer; same rolling-manifest shape as latest.json - * latest.json —— stable rolling manifest (os-arch keyed, sha256) - * .json —— per-channel rolling manifests (beta versions) + * manifest.json —— stable install/update pointer (rolling-manifest shape) + * latest.json —— stable alias; same body as manifest.json + * .json —— per-channel rolling manifests (betas / local verify) * * Override with `BAILIAN_CLI_CDN`. */ @@ -16,8 +16,9 @@ export const DEFAULT_CLI_CDN_BASE = "https://bailian-wiki.oss-cn-hangzhou.aliyun /** GitHub Releases base — used when writing manifests attached to gh release assets. */ export const GITHUB_RELEASES_BASE = "https://github.com/modelstudioai/cli/releases"; -export const DEFAULT_INSTALL_SCRIPT_URL = `${DEFAULT_CLI_CDN_BASE}/install.sh`; -export const DEFAULT_INSTALL_PS1_URL = `${DEFAULT_CLI_CDN_BASE}/install.ps1`; +/** User-facing install entry (docs / update hints); asset downloads still use getCliCdnBase(). */ +export const DEFAULT_INSTALL_SCRIPT_URL = "https://bailian.aliyun.com/install.sh"; +export const DEFAULT_INSTALL_PS1_URL = "https://bailian.aliyun.com/install.ps1"; export function getCliCdnBase(): string { const fromEnv = process.env.BAILIAN_CLI_CDN?.trim(); @@ -26,12 +27,17 @@ export function getCliCdnBase(): string { } /** - * Rolling channel manifest at the CDN base root: `{base}/{channel}.json`. - * `latest.json` (stable) and `.json` (betas) share the same shape; - * both are written by CI on publish. + * Rolling manifest URL at the CDN base root. + * Stable (`latest` / `stable` / empty) → `manifest.json`. + * Named channel → `{channel}.json` (e.g. sync-release for local verify). + * All share the same rolling-manifest shape from binary-build. */ export function channelManifestUrl(channel = "latest"): string { - return `${getCliCdnBase()}/${channel}.json`; + const normalized = channel.trim(); + if (!normalized || normalized === "latest" || normalized === "stable") { + return `${getCliCdnBase()}/manifest.json`; + } + return `${getCliCdnBase()}/${normalized}.json`; } /** Immutable per-version asset: `{base}/v{version}/{fileName}`. */ diff --git a/packages/core/tests/install-method.test.ts b/packages/core/tests/install-method.test.ts index e4aa557..2c1f085 100644 --- a/packages/core/tests/install-method.test.ts +++ b/packages/core/tests/install-method.test.ts @@ -33,3 +33,20 @@ test("binaryInnerFileName keeps exe suffix inside zip", () => { expect(binaryInnerFileName("1.2.3", "windows", "x64", true)).toBe("bl-1.2.3-windows-x64.exe"); expect(binaryInnerFileName("1.2.3", "darwin", "arm64", false)).toBe("bl-1.2.3-darwin-arm64"); }); + +test("channelManifestUrl maps stable to manifest.json", async () => { + const { channelManifestUrl } = await import("../src/install/cdn.ts"); + const previous = process.env.BAILIAN_CLI_CDN; + delete process.env.BAILIAN_CLI_CDN; + expect(channelManifestUrl()).toBe( + "https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/manifest.json", + ); + expect(channelManifestUrl("latest")).toBe( + "https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/manifest.json", + ); + expect(channelManifestUrl("sync-release")).toBe( + "https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/sync-release.json", + ); + if (previous === undefined) delete process.env.BAILIAN_CLI_CDN; + else process.env.BAILIAN_CLI_CDN = previous; +}); diff --git a/packaging/install.ps1 b/packaging/install.ps1 index e18c4d4..2dcd270 100644 --- a/packaging/install.ps1 +++ b/packaging/install.ps1 @@ -1,19 +1,18 @@ -# Binary install script for the OSS release layout (see packages/core/src/install/cdn.ts). +# Binary install script for the OSS release # -# irm https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.ps1 | iex -# $env:BAILIAN_CHANNEL = "sync-release"; irm ... | iex -# $env:BAILIAN_VERSION = "1.10.1"; irm ... | iex +# irm https://bailian.aliyun.com/install.ps1 | iex +# .\install.ps1 -Channel sync-release # local / channel verify +# .\install.ps1 -Version 1.10.1 # -# Layout: -# {CDN}/{channel}.json — rolling manifest (version + assets) -# {CDN}/v{version}/{file}.zip — per-platform zip -param() +param( + [string]$Channel = $env:BAILIAN_CHANNEL, + [string]$Version = $env:BAILIAN_VERSION, + [string]$Cdn = $env:BAILIAN_CLI_CDN +) $ErrorActionPreference = "Stop" -$CdnBase = if ($env:BAILIAN_CLI_CDN) { $env:BAILIAN_CLI_CDN.TrimEnd("/") } else { "https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release" } -$Channel = if ($env:BAILIAN_CHANNEL) { $env:BAILIAN_CHANNEL } else { "latest" } -$Version = $env:BAILIAN_VERSION +$CdnBase = if ($Cdn) { $Cdn.TrimEnd("/") } else { "https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release" } $InstallRoot = if ($env:BAILIAN_SHARE_DIR) { $env:BAILIAN_SHARE_DIR } else { Join-Path $env:LOCALAPPDATA "bailian-cli" } $ConfigDir = if ($env:BAILIAN_CONFIG_DIR) { $env:BAILIAN_CONFIG_DIR } else { Join-Path $env:USERPROFILE ".bailian" } @@ -32,7 +31,13 @@ if ($Arch -eq "arm64") { } $PlatformKey = "windows-$Arch" -$ManifestUrl = "$CdnBase/$Channel.json" +if (-not [string]::IsNullOrWhiteSpace($Channel) -and $Channel -ne "latest" -and $Channel -ne "stable") { + $ManifestLabel = "$Channel.json" + $ManifestUrl = "$CdnBase/$Channel.json" +} else { + $ManifestLabel = "manifest.json" + $ManifestUrl = "$CdnBase/manifest.json" +} Write-Log "Fetching $ManifestUrl" $Manifest = Invoke-RestMethod -Uri $ManifestUrl @@ -41,7 +46,7 @@ if ([string]::IsNullOrWhiteSpace($Version)) { $Version = $Manifest.version } if ([string]::IsNullOrWhiteSpace($Version)) { - throw "Could not parse version from $Channel channel manifest" + throw "Could not parse version from $ManifestLabel" } $ZipFile = $null @@ -126,7 +131,7 @@ try { Write-Log "Added $ShimDir to your user PATH. Open a new terminal to use bl." } - Write-Log "Installed: $Target (bailian-cli $Version) [$Channel]" + Write-Log "Installed: $Target (bailian-cli $Version) [$ManifestLabel]" Write-Log "Done. Run: bl --help" } finally { diff --git a/packaging/install.sh b/packaging/install.sh index f0e98ff..5f47a45 100755 --- a/packaging/install.sh +++ b/packaging/install.sh @@ -1,19 +1,16 @@ #!/usr/bin/env bash -# Binary install script for the OSS release layout (see packages/core/src/install/cdn.ts). +# Binary install script for the OSS release # -# curl -fsSL https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release/install.sh | bash -# BAILIAN_CHANNEL=latest bash install.sh -# BAILIAN_CHANNEL=sync-release bash install.sh -# BAILIAN_VERSION=1.10.1 bash install.sh +# curl -fsSL https://bailian.aliyun.com/install.sh | bash +# bash install.sh --channel sync-release # local / channel verify +# bash install.sh --version 1.10.1 +# curl -fsSL …/install.sh | bash -s -- --channel sync-release # -# Layout: -# {CDN}/{channel}.json —— rolling manifest (version + assets) -# {CDN}/v{version}/{file}.zip —— per-platform zip set -euo pipefail CDN_BASE="${BAILIAN_CLI_CDN:-https://bailian-wiki.oss-cn-hangzhou.aliyuncs.com/release}" CDN_BASE="${CDN_BASE%/}" -CHANNEL="${BAILIAN_CHANNEL:-latest}" +CHANNEL="${BAILIAN_CHANNEL:-}" VERSION="${BAILIAN_VERSION:-}" BIN_DIR="${BAILIAN_BIN_DIR:-${HOME}/.local/bin}" SHARE_DIR="${BAILIAN_SHARE_DIR:-${HOME}/.local/share/bailian-cli}" @@ -22,10 +19,61 @@ CONFIG_DIR="${BAILIAN_CONFIG_DIR:-${HOME}/.bailian}" ZIP_FILE="" ZIP_SHA256="" INNER_NAME="" +MANIFEST_LABEL="manifest.json" log() { printf '%s\n' "$*" >&2; } die() { log "error: $*"; exit 1; } +usage() { + cat >&2 <<'EOF' +Usage: install.sh [--channel ] [--version ] [--cdn ] [--help] + + --channel Install from {CDN}/{name}.json (default: manifest.json) + --version Pin a release version (checksum via SHA256SUMS if needed) + --cdn Override CDN base (default / BAILIAN_CLI_CDN) + --help Show this help + +Env fallbacks: BAILIAN_CHANNEL, BAILIAN_VERSION, BAILIAN_CLI_CDN, + BAILIAN_BIN_DIR, BAILIAN_SHARE_DIR, BAILIAN_CONFIG_DIR +EOF +} + +parse_args() { + while [[ $# -gt 0 ]]; do + case "$1" in + --channel|-c) + [[ $# -ge 2 ]] || die "$1 requires a value" + CHANNEL="$2" + shift 2 + ;; + --version) + [[ $# -ge 2 ]] || die "$1 requires a value" + VERSION="$2" + shift 2 + ;; + --cdn) + [[ $# -ge 2 ]] || die "$1 requires a value" + CDN_BASE="${2%/}" + shift 2 + ;; + --help|-h) + usage + exit 0 + ;; + --) + shift + break + ;; + -*) + die "unknown option: $1 (try --help)" + ;; + *) + die "unexpected argument: $1 (try --help)" + ;; + esac + done +} + need_cmd() { command -v "$1" >/dev/null 2>&1 || die "required command not found: $1" } @@ -141,7 +189,13 @@ resolve_asset() { need_cmd curl local manifest_path parsed manifest_url manifest_path="$(mktemp)" - manifest_url="${CDN_BASE}/${CHANNEL}.json" + if [[ -n "${CHANNEL}" && "${CHANNEL}" != "latest" && "${CHANNEL}" != "stable" ]]; then + MANIFEST_LABEL="${CHANNEL}.json" + manifest_url="${CDN_BASE}/${CHANNEL}.json" + else + MANIFEST_LABEL="manifest.json" + manifest_url="${CDN_BASE}/manifest.json" + fi log "Fetching ${manifest_url}" if ! curl -fsSL "${manifest_url}" -o "${manifest_path}"; then rm -f "${manifest_path}" @@ -150,7 +204,7 @@ resolve_asset() { if ! parsed="$(parse_manifest_asset "${manifest_path}" "${PLATFORM_KEY}" "${VERSION}")"; then rm -f "${manifest_path}" - die "failed to parse asset metadata from ${CHANNEL}.json for ${PLATFORM_KEY}" + die "failed to parse asset metadata from ${MANIFEST_LABEL} for ${PLATFORM_KEY}" fi rm -f "${manifest_path}" @@ -160,7 +214,7 @@ resolve_asset() { INNER_NAME="$(printf '%s\n' "${parsed}" | cut -f4)" [[ -n "${VERSION}" && -n "${ZIP_FILE}" && -n "${INNER_NAME}" ]] \ - || die "incomplete asset metadata from ${CHANNEL}.json" + || die "incomplete asset metadata from ${MANIFEST_LABEL}" } sha256_file() { @@ -253,11 +307,12 @@ warn_npm_conflict() { } main() { + parse_args "$@" need_cmd curl need_cmd uname detect_os_arch resolve_asset - log "Installing bailian-cli ${VERSION} (${PLATFORM_KEY}) from ${CDN_BASE} [${CHANNEL}]" + log "Installing bailian-cli ${VERSION} (${PLATFORM_KEY}) from ${CDN_BASE} [${MANIFEST_LABEL}]" download_and_install warn_npm_conflict warn_path