From 4eecf05fe5d8ce67351e184a8507e2a5fb9e2065 Mon Sep 17 00:00:00 2001 From: bcode Date: Mon, 27 Apr 2026 02:20:30 +0000 Subject: [PATCH 1/3] C1 + C4: cross-platform release workflow + bcode.sh install script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three pieces, intended to land together so a tag push produces a complete matrix of release assets and the install one-liner becomes self-serve: 1. .github/workflows/release.yml — on `v*` tag push (or workflow_dispatch), runs build.ts on a Linux runner, Bun cross-compiles every target (linux x64/arm64 [+baseline +musl], darwin x64/arm64 [+baseline], windows x64/arm64 [+baseline]), and uploads archives to the matching GitHub Release. Creates the release as prerelease if it doesn't exist yet so reruns work via --clobber. 2. packages/opencode/script/build.ts — split the dist subdir name (npm package id, `@browser-use/browsercode-core-`) from the release-asset basename (`bcode-`). Archives now write to `dist/bcode-.{tar.gz,zip}` and the upload glob is `./dist/bcode-*`. Required so the install script can construct stable, slash-free asset URLs. Yellow-zone — documented in memory/browsercode/EXCEPTIONS.md. 3. install.sh — port of opencode's installer. Diffs vs upstream: APP=bcode, INSTALL_DIR=$HOME/.bcode/bin, repo URL is browser-use/browsercode, shell-rc marker is `# bcode`, BrowserCode wordmark + footer text. Adds a uv-on-PATH check that prints a one-line install hint when missing (the harness needs uv at runtime for browser_execute) — never auto-installs. Verified locally: build.ts `--single` for linux-x64 still produces the correct binary; archive cwd math (`../../../` from `dist//-/bin/`) lands archives at `dist/bcode-.tar.gz`. Typecheck passes. install.sh syntax-clean under `bash -n`. Pre-conditions for the install one-liner to work end-to-end (post-merge): - Repo made public (or install script switches to a private-fetch path). - DNS for bcode.sh CNAME'd to a static host serving install.sh. - A v0.0.3 tag pushed to trigger the new workflow. --- install.sh | 473 ++++++++++++++++++++++++++++++ packages/opencode/script/build.ts | 22 +- 2 files changed, 486 insertions(+), 9 deletions(-) create mode 100755 install.sh diff --git a/install.sh b/install.sh new file mode 100755 index 000000000..fce9aadd7 --- /dev/null +++ b/install.sh @@ -0,0 +1,473 @@ +#!/usr/bin/env bash +# +# BrowserCode installer. +# +# Hosted at https://bcode.sh/install. One-liner: +# +# curl -fsSL https://bcode.sh/install | bash +# curl -fsSL https://bcode.sh/install | bash -s -- --version 0.0.3 +# +# Adapted from anomalyco/opencode's installer (MIT). Differences: +# +# - Pulls assets from `browser-use/browsercode` GitHub Releases. +# - Installs to `$HOME/.bcode/bin/bcode`. +# - Marks shell-rc edits with `# bcode` so `bcode uninstall` strips them +# cleanly (matches PR #12 changes). +# - Detects `uv` on PATH and prints a one-line install hint if missing +# (required at runtime for `browser_execute`). Does NOT call uv's +# installer — chained installers are bad form. +set -euo pipefail +APP=bcode + +MUTED='\033[0;2m' +RED='\033[0;31m' +ORANGE='\033[38;5;214m' +NC='\033[0m' + +usage() { + cat < Install a specific version (e.g. 0.0.3) + -b, --binary Install from a local binary instead of downloading + --no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.) + +Examples: + curl -fsSL https://bcode.sh/install | bash + curl -fsSL https://bcode.sh/install | bash -s -- --version 0.0.3 + ./install.sh --binary /path/to/bcode +EOF +} + +requested_version=${VERSION:-} +no_modify_path=false +binary_path="" + +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -v|--version) + if [[ -n "${2:-}" ]]; then + requested_version="$2" + shift 2 + else + echo -e "${RED}Error: --version requires a version argument${NC}" + exit 1 + fi + ;; + -b|--binary) + if [[ -n "${2:-}" ]]; then + binary_path="$2" + shift 2 + else + echo -e "${RED}Error: --binary requires a path argument${NC}" + exit 1 + fi + ;; + --no-modify-path) + no_modify_path=true + shift + ;; + *) + echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2 + shift + ;; + esac +done + +INSTALL_DIR=$HOME/.bcode/bin +mkdir -p "$INSTALL_DIR" + +if [ -n "$binary_path" ]; then + if [ ! -f "$binary_path" ]; then + echo -e "${RED}Error: Binary not found at ${binary_path}${NC}" + exit 1 + fi + specific_version="local" +else + raw_os=$(uname -s) + os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]') + case "$raw_os" in + Darwin*) os="darwin" ;; + Linux*) os="linux" ;; + MINGW*|MSYS*|CYGWIN*) os="windows" ;; + esac + + arch=$(uname -m) + if [[ "$arch" == "aarch64" ]]; then + arch="arm64" + fi + if [[ "$arch" == "x86_64" ]]; then + arch="x64" + fi + + if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then + rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0) + if [ "$rosetta_flag" = "1" ]; then + arch="arm64" + fi + fi + + combo="$os-$arch" + case "$combo" in + linux-x64|linux-arm64|darwin-x64|darwin-arm64|windows-x64) + ;; + *) + echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}" + exit 1 + ;; + esac + + archive_ext=".zip" + if [ "$os" = "linux" ]; then + archive_ext=".tar.gz" + fi + + is_musl=false + if [ "$os" = "linux" ]; then + if [ -f /etc/alpine-release ]; then + is_musl=true + fi + + if command -v ldd >/dev/null 2>&1; then + if ldd --version 2>&1 | grep -qi musl; then + is_musl=true + fi + fi + fi + + needs_baseline=false + if [ "$arch" = "x64" ]; then + if [ "$os" = "linux" ]; then + if ! grep -qwi avx2 /proc/cpuinfo 2>/dev/null; then + needs_baseline=true + fi + fi + + if [ "$os" = "darwin" ]; then + avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0) + if [ "$avx2" != "1" ]; then + needs_baseline=true + fi + fi + + if [ "$os" = "windows" ]; then + ps="(Add-Type -MemberDefinition \"[DllImport(\"\"kernel32.dll\"\")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);\" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)" + out="" + if command -v powershell.exe >/dev/null 2>&1; then + out=$(powershell.exe -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true) + elif command -v pwsh >/dev/null 2>&1; then + out=$(pwsh -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true) + fi + out=$(echo "$out" | tr -d '\r' | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]') + if [ "$out" != "true" ] && [ "$out" != "1" ]; then + needs_baseline=true + fi + fi + fi + + target="$os-$arch" + if [ "$needs_baseline" = "true" ]; then + target="$target-baseline" + fi + if [ "$is_musl" = "true" ]; then + target="$target-musl" + fi + + filename="$APP-$target$archive_ext" + + if [ "$os" = "linux" ]; then + if ! command -v tar >/dev/null 2>&1; then + echo -e "${RED}Error: 'tar' is required but not installed.${NC}" + exit 1 + fi + else + if ! command -v unzip >/dev/null 2>&1; then + echo -e "${RED}Error: 'unzip' is required but not installed.${NC}" + exit 1 + fi + fi + + if [ -z "$requested_version" ]; then + url="https://github.com/browser-use/browsercode/releases/latest/download/$filename" + specific_version=$(curl -s https://api.github.com/repos/browser-use/browsercode/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') + + if [[ $? -ne 0 || -z "$specific_version" ]]; then + echo -e "${RED}Failed to fetch version information${NC}" + echo -e "${MUTED}If the repo is private, pin a version: --version ${NC}" + exit 1 + fi + else + requested_version="${requested_version#v}" + url="https://github.com/browser-use/browsercode/releases/download/v${requested_version}/$filename" + specific_version=$requested_version + + http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/browser-use/browsercode/releases/tag/v${requested_version}") + if [ "$http_status" = "404" ]; then + echo -e "${RED}Error: Release v${requested_version} not found${NC}" + echo -e "${MUTED}Available releases: https://github.com/browser-use/browsercode/releases${NC}" + exit 1 + fi + fi +fi + +print_message() { + local level=$1 + local message=$2 + local color="" + + case $level in + info) color="${NC}" ;; + warning) color="${NC}" ;; + error) color="${RED}" ;; + esac + + echo -e "${color}${message}${NC}" +} + +check_version() { + if command -v bcode >/dev/null 2>&1; then + installed_version=$(bcode --version 2>/dev/null || echo "") + + if [[ "$installed_version" != "$specific_version" ]]; then + print_message info "${MUTED}Installed version: ${NC}$installed_version." + else + print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed${NC}" + exit 0 + fi + fi +} + +unbuffered_sed() { + if echo | sed -u -e "" >/dev/null 2>&1; then + sed -nu "$@" + elif echo | sed -l -e "" >/dev/null 2>&1; then + sed -nl "$@" + else + local pad="$(printf "\n%512s" "")" + sed -ne "s/$/\\${pad}/" "$@" + fi +} + +print_progress() { + local bytes="$1" + local length="$2" + [ "$length" -gt 0 ] || return 0 + + local width=50 + local percent=$(( bytes * 100 / length )) + [ "$percent" -gt 100 ] && percent=100 + local on=$(( percent * width / 100 )) + local off=$(( width - on )) + + local filled=$(printf "%*s" "$on" "") + filled=${filled// /■} + local empty=$(printf "%*s" "$off" "") + empty=${empty// /・} + + printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4 +} + +download_with_progress() { + local url="$1" + local output="$2" + + if [ -t 2 ]; then + exec 4>&2 + else + exec 4>/dev/null + fi + + local tmp_dir=${TMPDIR:-/tmp} + local basename="${tmp_dir}/bcode_install_$$" + local tracefile="${basename}.trace" + + rm -f "$tracefile" + mkfifo "$tracefile" + + printf "\033[?25l" >&4 + + trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN + + ( + curl --trace-ascii "$tracefile" -s -L -o "$output" "$url" + ) & + local curl_pid=$! + + unbuffered_sed \ + -e 'y/ACDEGHLNORTV/acdeghlnortv/' \ + -e '/^0000: content-length:/p' \ + -e '/^<= recv data/p' \ + "$tracefile" | \ + { + local length=0 + local bytes=0 + + while IFS=" " read -r -a line; do + [ "${#line[@]}" -lt 2 ] && continue + local tag="${line[0]} ${line[1]}" + + if [ "$tag" = "0000: content-length:" ]; then + length="${line[2]}" + length=$(echo "$length" | tr -d '\r') + bytes=0 + elif [ "$tag" = "<= recv" ]; then + local size="${line[3]}" + bytes=$(( bytes + size )) + if [ "$length" -gt 0 ]; then + print_progress "$bytes" "$length" + fi + fi + done + } + + wait $curl_pid + local ret=$? + echo "" >&4 + return $ret +} + +download_and_install() { + print_message info "\n${MUTED}Installing ${NC}bcode ${MUTED}version: ${NC}$specific_version" + local tmp_dir="${TMPDIR:-/tmp}/bcode_install_$$" + mkdir -p "$tmp_dir" + + if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then + curl -# -L -o "$tmp_dir/$filename" "$url" + fi + + if [ "$os" = "linux" ]; then + tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" + else + unzip -q "$tmp_dir/$filename" -d "$tmp_dir" + fi + + # Archives contain a single `bcode` binary (or `bcode.exe` on windows) + if [ -f "$tmp_dir/bcode.exe" ]; then + mv "$tmp_dir/bcode.exe" "$INSTALL_DIR/" + chmod 755 "${INSTALL_DIR}/bcode.exe" + else + mv "$tmp_dir/bcode" "$INSTALL_DIR/" + chmod 755 "${INSTALL_DIR}/bcode" + fi + rm -rf "$tmp_dir" +} + +install_from_binary() { + print_message info "\n${MUTED}Installing ${NC}bcode ${MUTED}from: ${NC}$binary_path" + cp "$binary_path" "${INSTALL_DIR}/bcode" + chmod 755 "${INSTALL_DIR}/bcode" +} + +if [ -n "$binary_path" ]; then + install_from_binary +else + check_version + download_and_install +fi + + +add_to_path() { + local config_file=$1 + local command=$2 + + if grep -Fxq "$command" "$config_file"; then + print_message info "Command already exists in $config_file, skipping write." + elif [[ -w $config_file ]]; then + echo -e "\n# bcode" >> "$config_file" + echo "$command" >> "$config_file" + print_message info "${MUTED}Successfully added ${NC}bcode ${MUTED}to \$PATH in ${NC}$config_file" + else + print_message warning "Manually add the directory to $config_file (or similar):" + print_message info " $command" + fi +} + +XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} + +current_shell=$(basename "$SHELL") +case $current_shell in + fish) + config_files="$HOME/.config/fish/config.fish" + ;; + zsh) + config_files="${ZDOTDIR:-$HOME}/.zshrc ${ZDOTDIR:-$HOME}/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv" + ;; + bash) + config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile" + ;; + ash) + config_files="$HOME/.ashrc $HOME/.profile /etc/profile" + ;; + sh) + config_files="$HOME/.ashrc $HOME/.profile /etc/profile" + ;; + *) + config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile" + ;; +esac + +if [[ "$no_modify_path" != "true" ]]; then + config_file="" + for file in $config_files; do + if [[ -f $file ]]; then + config_file=$file + break + fi + done + + if [[ -z $config_file ]]; then + print_message warning "No config file found for $current_shell. You may need to manually add to PATH:" + print_message info " export PATH=$INSTALL_DIR:\$PATH" + elif [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then + case $current_shell in + fish) + add_to_path "$config_file" "fish_add_path $INSTALL_DIR" + ;; + zsh|bash|ash|sh) + add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" + ;; + *) + export PATH=$INSTALL_DIR:$PATH + print_message warning "Manually add the directory to $config_file (or similar):" + print_message info " export PATH=$INSTALL_DIR:\$PATH" + ;; + esac + fi +fi + +if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then + echo "$INSTALL_DIR" >> "$GITHUB_PATH" + print_message info "Added $INSTALL_DIR to \$GITHUB_PATH" +fi + +# `uv` is required at runtime for the `browser_execute` tool (the harness uses +# it to manage its Python venv). Detect and warn if missing — never auto-install. +if ! command -v uv >/dev/null 2>&1; then + echo -e "" + echo -e "${ORANGE}Warning: 'uv' is not on PATH.${NC}" + echo -e "${MUTED}bcode's browser_execute tool needs uv to run. Install with:${NC}" + echo -e " curl -LsSf https://astral.sh/uv/install.sh | sh" + echo -e "${MUTED}Or see https://docs.astral.sh/uv/getting-started/installation/${NC}" +fi + +echo -e "" +echo -e "${MUTED}█▀▀▄ █▀▀ █▀▀█ █▀▀▄ █▀▀${NC}" +echo -e "${MUTED}█▀▀▄ █░░ █░░█ █░░█ █▀▀${NC}" +echo -e "${MUTED}▀▀▀░ ▀▀▀ ▀▀▀▀ ▀▀▀░ ▀▀▀${NC}" +echo -e "" +echo -e "${MUTED}BrowserCode ${NC}$specific_version${MUTED} installed to ${NC}$INSTALL_DIR/bcode" +echo -e "" +echo -e "cd ${MUTED}# Open directory${NC}" +echo -e "bcode ${MUTED}# Run the agent${NC}" +echo -e "" +echo -e "${MUTED}Docs: ${NC}https://github.com/browser-use/browsercode" +echo -e "${MUTED}Issues: ${NC}https://github.com/browser-use/browsercode/issues" +echo -e "" diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index 821e21400..3472b0fda 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -166,14 +166,15 @@ const targets = singleFlag await $`rm -rf dist` -const binaries: Record = {} +const binaries: Record = {} if (!skipInstall) { await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}` await $`bun install --os="*" --cpu="*" @parcel/watcher@${pkg.dependencies["@parcel/watcher"]}` } for (const item of targets) { - const name = [ - pkg.name, + // suffix shared by both: @browser-use/browsercode-core--... (npm package name) + // and bcode--... (release-asset name) + const targetSuffix = [ // changing to win32 flags npm for some reason item.os === "win32" ? "windows" : item.os, item.arch, @@ -182,7 +183,9 @@ for (const item of targets) { ] .filter(Boolean) .join("-") - console.log(`building ${name}`) + const name = `${pkg.name}-${targetSuffix}` // dist subdir + npm package id + const assetName = `bcode-${targetSuffix}` // release archive basename + console.log(`building ${name} → ${assetName}`) await $`mkdir -p dist/${name}/bin` const localPath = path.resolve(dir, "node_modules/@opentui/core/parser.worker.js") @@ -259,18 +262,19 @@ for (const item of targets) { 2, ), ) - binaries[name] = Script.version + binaries[name] = { version: Script.version, assetName } } if (Script.release) { - for (const key of Object.keys(binaries)) { + for (const [key, info] of Object.entries(binaries)) { + // archive at dist/.{tar.gz,zip} so `gh release upload ./dist/bcode-*` finds clean basenames. if (key.includes("linux")) { - await $`tar -czf ../../${key}.tar.gz *`.cwd(`dist/${key}/bin`) + await $`tar -czf ../../../${info.assetName}.tar.gz *`.cwd(`dist/${key}/bin`) } else { - await $`zip -r ../../${key}.zip *`.cwd(`dist/${key}/bin`) + await $`zip -r ../../../${info.assetName}.zip *`.cwd(`dist/${key}/bin`) } } - await $`gh release upload v${Script.version} ./dist/*.zip ./dist/*.tar.gz --clobber --repo ${process.env.GH_REPO}` + await $`gh release upload v${Script.version} ./dist/bcode-*.tar.gz ./dist/bcode-*.zip --clobber --repo ${process.env.GH_REPO}` } export { binaries } From 3bf606c184032db6e1515d26c6c9afb19148781c Mon Sep 17 00:00:00 2001 From: Alezander9 Date: Sun, 26 Apr 2026 21:41:30 -0700 Subject: [PATCH 2/3] Add release workflow for cross-platform CLI builds --- .github/workflows/release.yml | 101 ++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..883fdef44 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,101 @@ +name: release + +# Build the bcode CLI for every platform we ship and attach the archives to +# the GitHub Release matching the pushed tag. +# +# Trigger: +# - Push a tag matching `v*` (e.g. `v0.0.3`). +# +# Behaviour: +# 1. Reuses the existing `packages/opencode/script/build.ts` matrix +# (linux x64/arm64, darwin x64/arm64, win32 x64/arm64; baseline + musl +# variants where applicable). +# 2. Bun cross-compiles every target from a single Linux runner. +# 3. With `OPENCODE_RELEASE=1`, `build.ts` archives each target as +# `dist/bcode--...{.tar.gz,.zip}` and uploads via `gh release +# upload --clobber`. +# +# Pre-condition: the tag must already have an existing GitHub Release +# (created either manually with `gh release create vX.Y.Z` or by an upcoming +# release-creation workflow). `--clobber` lets re-runs replace assets. + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + tag: + description: "Release tag to build (must already exist as a Release)" + required: true + type: string + +permissions: + contents: write + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-24.04 + if: github.repository == 'browser-use/browsercode' + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Resolve tag + version + id: ver + run: | + if [ -n "${{ inputs.tag }}" ]; then + TAG="${{ inputs.tag }}" + else + TAG="${GITHUB_REF#refs/tags/}" + fi + VERSION="${TAG#v}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "Building tag=${TAG} version=${VERSION}" + + - name: Setup Bun + uses: ./.github/actions/setup-bun + + - name: Ensure GitHub Release exists + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # `build.ts` uploads via `gh release upload --clobber`, which requires + # the release to already exist. Create as a prerelease if missing; the + # admin can promote/edit notes after assets land. + if ! gh release view "${{ steps.ver.outputs.tag }}" >/dev/null 2>&1; then + echo "Creating prerelease ${{ steps.ver.outputs.tag }}" + gh release create "${{ steps.ver.outputs.tag }}" \ + --prerelease \ + --title "${{ steps.ver.outputs.tag }}" \ + --notes "Automated build for ${{ steps.ver.outputs.tag }}. Notes pending." + else + echo "Release ${{ steps.ver.outputs.tag }} already exists." + fi + + - name: Build all targets and upload to release + env: + OPENCODE_VERSION: ${{ steps.ver.outputs.version }} + OPENCODE_RELEASE: "1" + OPENCODE_CHANNEL: latest + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + ./packages/opencode/script/build.ts + + - name: Summarise uploaded assets + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "## Release ${{ steps.ver.outputs.tag }}" >> "$GITHUB_STEP_SUMMARY" + echo "" >> "$GITHUB_STEP_SUMMARY" + gh release view "${{ steps.ver.outputs.tag }}" --json assets \ + --jq '.assets[] | "- " + .name + " (" + (.size|tostring) + " bytes)"' \ + >> "$GITHUB_STEP_SUMMARY" From 501d01b8c00db9d37bc62ab6f7a0eb0934d85ab9 Mon Sep 17 00:00:00 2001 From: Alezander9 Date: Sun, 26 Apr 2026 21:44:31 -0700 Subject: [PATCH 3/3] Use TUI wordmark banner (browsercode) in install.sh --- install.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index fce9aadd7..f9ee5c289 100755 --- a/install.sh +++ b/install.sh @@ -459,9 +459,10 @@ if ! command -v uv >/dev/null 2>&1; then fi echo -e "" -echo -e "${MUTED}█▀▀▄ █▀▀ █▀▀█ █▀▀▄ █▀▀${NC}" -echo -e "${MUTED}█▀▀▄ █░░ █░░█ █░░█ █▀▀${NC}" -echo -e "${MUTED}▀▀▀░ ▀▀▀ ▀▀▀▀ ▀▀▀░ ▀▀▀${NC}" +echo -e "${MUTED}▄⠀ ▄ ${NC}" +echo -e "${MUTED}█▀▀█ █▀▀▄ █▀▀█ █ █ █▀▀▀ █▀▀█ █▀▀▄ █▀▀▀ █▀▀█ █▀▀█ █▀▀█${NC}" +echo -e "${MUTED}█ █ █ █ █ █▐▌█ ▀▀▀█ █▀▀▀ █ █ █ █ █ █ █▀▀▀${NC}" +echo -e "${MUTED}▀▀▀▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀${NC}" echo -e "" echo -e "${MUTED}BrowserCode ${NC}$specific_version${MUTED} installed to ${NC}$INSTALL_DIR/bcode" echo -e ""