From b6a8ab1e778db8c941592f1da900d81c485d9f8e Mon Sep 17 00:00:00 2001 From: rustfuture <121799572+rustfuture@users.noreply.github.com> Date: Mon, 5 Oct 2026 13:13:28 +0300 Subject: [PATCH] Publish prebuilt binaries with each release Pushing a v* tag now builds the CLI for Linux (x86_64, aarch64), macOS (Intel, Apple Silicon) and Windows, smoke-tests --version and attaches the archives with SHA-256 files to the GitHub release. install.sh and install.ps1 download the archive for the current machine and verify its checksum. Adds --version / -V, bumps the version to 0.1.1 and adds a "Try the released CLI" section to the quick start. --- .github/workflows/release.yml | 158 +++++++++++++++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 18 +++- install.ps1 | 129 +++++++++++++++++++++++ install.sh | 186 ++++++++++++++++++++++++++++++++++ packaging/README.txt | 27 +++++ src/main.rs | 4 + tests/ri_regression.rs | 13 +++ 9 files changed, 536 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 install.ps1 create mode 100755 install.sh create mode 100644 packaging/README.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9c05786 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,158 @@ +name: Release + +# Pushing a tag such as v0.4.0 builds the `repository-intelligence` CLI on native runners, +# packages it and publishes a GitHub release. Running the workflow by hand +# (workflow_dispatch) builds and uploads the archives as workflow artifacts +# but never publishes. See docs/releasing.md. + +on: + push: + tags: [ "v*" ] + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +jobs: + prepare: + name: Check version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - uses: actions/checkout@v4 + + - name: Read workspace version and compare with the tag + id: version + run: | + version="$(cargo metadata --no-deps --format-version 1 --locked \ + | jq -r '.packages[] | select(.name == "repository-intelligence") | .version')" + if [ -z "$version" ] || [ "$version" = "null" ]; then + echo "::error::could not read the repository-intelligence version from Cargo.toml" + exit 1 + fi + if [ "$GITHUB_REF_TYPE" = "tag" ] && [ "$GITHUB_REF_NAME" != "v$version" ]; then + echo "::error::tag $GITHUB_REF_NAME does not match the workspace version $version (expected v$version). Fix the version in Cargo.toml or push the right tag." + exit 1 + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + + build: + name: Build ${{ matrix.target }} + needs: prepare + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + include: + # Linux builds run on the oldest hosted images so the binaries link + # against an older glibc (2.35) and run on most current distributions. + - { target: x86_64-unknown-linux-gnu, os: ubuntu-22.04 } + - { target: aarch64-unknown-linux-gnu, os: ubuntu-22.04-arm } + - { target: x86_64-apple-darwin, os: macos-15-intel } + - { target: aarch64-apple-darwin, os: macos-latest } + - { target: x86_64-pc-windows-msvc, os: windows-latest } + env: + VERSION: ${{ needs.prepare.outputs.version }} + TARGET: ${{ matrix.target }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + targets: ${{ matrix.target }} + + - name: Build + run: cargo build --release --locked -p repository-intelligence --target ${{ matrix.target }} + + - name: Package (unix) + if: runner.os != 'Windows' + shell: bash + run: | + set -euo pipefail + name="repository-intelligence-${VERSION}-${TARGET}" + mkdir -p "dist/${name}" + cp "target/${TARGET}/release/repository-intelligence" LICENSE "dist/${name}/" + cp packaging/README.txt "dist/${name}/README.txt" + tar -C dist -czf "dist/${name}.tar.gz" "${name}" + cd dist + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "${name}.tar.gz" > "${name}.tar.gz.sha256" + else + shasum -a 256 "${name}.tar.gz" > "${name}.tar.gz.sha256" + fi + cat "${name}.tar.gz.sha256" + + - name: Package (windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $name = "repository-intelligence-$env:VERSION-$env:TARGET" + New-Item -ItemType Directory -Force -Path "dist/$name" | Out-Null + Copy-Item "target/$env:TARGET/release/repository-intelligence.exe" "dist/$name/" + Copy-Item LICENSE "dist/$name/" + Copy-Item packaging/README.txt "dist/$name/README.txt" + Compress-Archive -Path "dist/$name" -DestinationPath "dist/$name.zip" + $hash = (Get-FileHash "dist/$name.zip" -Algorithm SHA256).Hash.ToLower() + "$hash $name.zip" | Set-Content -Path "dist/$name.zip.sha256" -Encoding ascii + Get-Content "dist/$name.zip.sha256" + + - name: Smoke test the binary + shell: bash + run: | + set -euo pipefail + exe="target/${TARGET}/release/repository-intelligence" + if [ "$RUNNER_OS" = "Windows" ]; then exe="${exe}.exe"; fi + out="$("$exe" --version)" + echo "$out" + case "$out" in + *"${VERSION}"*) ;; + *) echo "::error::binary reports '$out', expected version ${VERSION}"; exit 1 ;; + esac + + - name: Upload archives + uses: actions/upload-artifact@v4 + with: + name: repository-intelligence-${{ matrix.target }} + path: | + dist/*.tar.gz + dist/*.zip + dist/*.sha256 + if-no-files-found: error + + release: + name: Publish release + # Only for pushed tags; a manual run stops after the build job. + if: github.ref_type == 'tag' + needs: [prepare, build] + runs-on: ubuntu-latest + permissions: + contents: write + env: + VERSION: ${{ needs.prepare.outputs.version }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + pattern: repository-intelligence-* + merge-multiple: true + + - name: List files + run: ls -l dist + + - name: Create the GitHub release + run: | + set -euo pipefail + flags="" + case "$VERSION" in *-*) flags="--prerelease" ;; esac + gh release create "$GITHUB_REF_NAME" \ + --repo "$GITHUB_REPOSITORY" \ + --verify-tag \ + --title "repository-intelligence $VERSION" \ + --generate-notes \ + $flags \ + dist/*.tar.gz dist/*.zip dist/*.sha256 diff --git a/Cargo.lock b/Cargo.lock index 78f3a4d..098b8fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "repository-intelligence" -version = "0.1.0" +version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index 52023ac..422967c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "repository-intelligence" -version = "0.1.0" +version = "0.1.1" edition = "2021" rust-version = "1.85" license = "MIT" diff --git a/README.md b/README.md index 6013c30..4240006 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Repository Intelligence searches local code and returns verbatim source lines fo [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) > [!NOTE] -> **Status:** Experimental research prototype (v0.1.0) for local code inspection. +> **Status:** Experimental research prototype (v0.1.1) for local code inspection. ![An offline search printing the top three matching source lines](docs/demo/offline-search.gif) @@ -20,6 +20,22 @@ Repository Intelligence searches local code and returns verbatim source lines fo ## Quick start +### Try the released CLI (macOS or Linux) + +The prebuilt CLI does not require Rust. The installer downloads a release, checks its SHA-256 checksum, and installs to `~/.local/bin`: + +```bash +curl -fsSL https://raw.githubusercontent.com/rustfuture/repository-intelligence/main/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +repository-intelligence --version +# Search the repository you are in, offline, and print the three best source lines +repository-intelligence --hybrid . "main function" --top 3 +``` + +Prebuilt Linux binaries require glibc; unsupported platforms can build from source. On Windows, use the [PowerShell installer](install.ps1). + +### Build from source + You need Git and Rust 1.85+ with Cargo ([rustup](https://rustup.rs/)). It has no third-party crate dependencies. Offline commands use a deterministic `HashEmbedding` provider without external services. Neural embeddings and model-assisted answers use a local Ollama service (`nomic-embed-text` and `qwen2.5-coder:1.5b`) or the AGY adapter (the Google Antigravity command-line client). ```sh diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..ff02e1b --- /dev/null +++ b/install.ps1 @@ -0,0 +1,129 @@ +# Installer for the `repository-intelligence` CLI (https://github.com/rustfuture/repository-intelligence). +# +# irm https://raw.githubusercontent.com/rustfuture/repository-intelligence/main/install.ps1 | iex +# +# Downloads the prebuilt Windows release archive, checks its SHA-256 checksum and +# copies repository-intelligence.exe into an install directory. It needs no administrator rights. +# It does NOT change your PATH: if the install directory is not on it, the script +# prints the command to add it. +# +# Environment variables (all optional): +# RI_VERSION Version to install, e.g. 0.3.0 or v0.3.0 (default: latest release) +# RI_INSTALL_DIR Where to put repository-intelligence.exe (default: $env:LOCALAPPDATA\repository-intelligence\bin) +# RI_DOWNLOAD_BASE Base URL, local directory or file:// URL holding the archive +# and its .sha256 file, instead of the GitHub release. Needs +# RI_VERSION. Meant for mirrors and testing. +# RI_REPO GitHub repository (default: rustfuture/repository-intelligence) +# +# Everything runs inside a function and reports problems with `throw`, never `exit`, +# so piping this script to `iex` cannot close your terminal. + +function Install-Tool { + Set-StrictMode -Version 2 + $ErrorActionPreference = 'Stop' + $ProgressPreference = 'SilentlyContinue' # the progress bar makes Windows PowerShell 5.1 downloads very slow + + $repo = if ($env:RI_REPO) { $env:RI_REPO } else { 'rustfuture/repository-intelligence' } + $fromSource = "cargo install --git https://github.com/$repo repository-intelligence" + + # Windows PowerShell 5.1 does not enable TLS 1.2 by default. + try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch { } + + # --- platform ------------------------------------------------------------- + if ($PSVersionTable.PSVersion.Major -ge 6 -and -not $IsWindows) { + throw "This installer is for Windows. On macOS or Linux use: curl -fsSL https://raw.githubusercontent.com/$repo/main/install.sh | sh" + } + $osArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() + switch ($osArch) { + 'X64' { } + 'Arm64' { Write-Host 'Windows on ARM: installing the x64 build, which runs under emulation.' } + default { throw "Unsupported CPU architecture: $osArch. No prebuilt binary is available; if you have Rust (1.85 or newer), build from source: $fromSource" } + } + $target = 'x86_64-pc-windows-msvc' + + # --- version -------------------------------------------------------------- + if ($env:RI_VERSION) { + $version = $env:RI_VERSION.TrimStart('v') + } elseif ($env:RI_DOWNLOAD_BASE) { + throw 'RI_DOWNLOAD_BASE is set, so also set RI_VERSION (for example $env:RI_VERSION = ''0.3.0'').' + } else { + Write-Host 'Looking up the latest release...' + try { + $release = Invoke-RestMethod -UseBasicParsing -Uri "https://api.github.com/repos/$repo/releases/latest" -Headers @{ 'User-Agent' = 'repository-intelligence-installer' } + } catch { + throw 'Could not look up the latest release (no release published yet, no network, or the GitHub API rate limit). Set $env:RI_VERSION, e.g. $env:RI_VERSION = ''0.3.0''' + } + $version = ([string]$release.tag_name).TrimStart('v') + } + if ($version -notmatch '^[0-9A-Za-z.+-]+$') { throw "Invalid version: $version" } + + $installDir = if ($env:RI_INSTALL_DIR) { $env:RI_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'repository-intelligence\bin' } + $name = "repository-intelligence-$version-$target" + $archive = "$name.zip" + $base = if ($env:RI_DOWNLOAD_BASE) { $env:RI_DOWNLOAD_BASE } else { "https://github.com/$repo/releases/download/v$version" } + $base = $base.TrimEnd('/', '\') + + $tmp = Join-Path ([IO.Path]::GetTempPath()) ("repository-intelligence-install-" + [Guid]::NewGuid().ToString('N')) + New-Item -ItemType Directory -Path $tmp | Out-Null + try { + Write-Host "Installing repository-intelligence $version for $target" + + # --- download --------------------------------------------------------- + foreach ($file in @($archive, "$archive.sha256")) { + $dest = Join-Path $tmp $file + try { + if ($base -match '^https?://') { + Invoke-WebRequest -UseBasicParsing -Uri "$base/$file" -OutFile $dest + } else { + $localBase = if ($base -match '^file://') { ([Uri]$base).LocalPath } else { $base } + Copy-Item -LiteralPath (Join-Path $localBase $file) -Destination $dest + } + } catch { + throw "Could not download $base/$file (is $version a published version for $target?)" + } + } + + # --- verify ----------------------------------------------------------- + $sumLine = (Get-Content -LiteralPath (Join-Path $tmp "$archive.sha256") -TotalCount 1) + $expected = ($sumLine -split '\s+')[0].ToLower() + if ($expected -notmatch '^[0-9a-f]{64}$') { throw "The checksum file $archive.sha256 is not valid." } + $actual = (Get-FileHash -LiteralPath (Join-Path $tmp $archive) -Algorithm SHA256).Hash.ToLower() + if ($expected -ne $actual) { + Write-Error "Checksum mismatch for $archive`n expected: $expected`n actual: $actual" -ErrorAction Continue + throw 'Refusing to install a file that does not match its checksum.' + } + Write-Host 'Checksum OK' + + # --- unpack and install ---------------------------------------------- + Expand-Archive -LiteralPath (Join-Path $tmp $archive) -DestinationPath $tmp -Force + $exe = Join-Path $tmp "$name\repository-intelligence.exe" + if (-not (Test-Path -LiteralPath $exe)) { throw "The archive does not contain $name\repository-intelligence.exe" } + + New-Item -ItemType Directory -Force -Path $installDir | Out-Null + $installed = Join-Path $installDir 'repository-intelligence.exe' + try { + Copy-Item -LiteralPath $exe -Destination $installed -Force + } catch { + throw "Could not write $installed. If repository-intelligence is running (for example as an agent hook), close it and try again; or set `$env:RI_INSTALL_DIR to another directory." + } + + Write-Host "Installed: $installed" + & $installed --version + if ($LASTEXITCODE -ne 0) { throw "The installed binary did not run. Build from source instead: $fromSource" } + + # --- PATH hint (never edited automatically) -------------------------- + $dirs = @($env:PATH -split ';' | Where-Object { $_ } | ForEach-Object { $_.TrimEnd('\') }) + if ($dirs -notcontains $installDir.TrimEnd('\')) { + Write-Host '' + Write-Host "$installDir is not on your PATH. To add it for your user account, run:" + Write-Host " [Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','User') + ';$installDir', 'User')" + Write-Host 'then open a new terminal. (This installer does not change your PATH.)' + } + Write-Host '' + Write-Host "Next: run 'repository-intelligence --help' to get started." + } finally { + Remove-Item -LiteralPath $tmp -Recurse -Force -ErrorAction SilentlyContinue + } +} + +Install-Tool diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..91b2a2c --- /dev/null +++ b/install.sh @@ -0,0 +1,186 @@ +#!/bin/sh +# Installer for the `repository-intelligence` CLI (https://github.com/rustfuture/repository-intelligence). +# +# curl -fsSL https://raw.githubusercontent.com/rustfuture/repository-intelligence/main/install.sh | sh +# +# Downloads the prebuilt release archive for this machine, checks its SHA-256 +# checksum and copies `repository-intelligence` into an install directory. It never uses sudo +# and never edits shell startup files. +# +# Environment variables (all optional): +# RI_VERSION Version to install, e.g. 0.3.0 or v0.3.0 (default: latest release) +# RI_INSTALL_DIR Where to put the binary (default: $HOME/.local/bin) +# RI_DOWNLOAD_BASE Base URL (or file:// URL) holding the archive and its +# .sha256 file, instead of the GitHub release. Needs +# RI_VERSION. Meant for mirrors and testing. +# RI_REPO GitHub repository (default: rustfuture/repository-intelligence) + +set -eu + +REPO="${RI_REPO:-rustfuture/repository-intelligence}" +FROM_SOURCE="cargo install --git https://github.com/${REPO} repository-intelligence" + +say() { printf '%s\n' "$*"; } +err() { printf 'repository-intelligence-install: error: %s\n' "$*" >&2; } +die() { err "$*"; exit 1; } + +have() { command -v "$1" >/dev/null 2>&1; } + +unsupported() { + err "$1" + err "No prebuilt binary is available for this platform. If you have Rust (1.85 or newer), build from source:" + err " ${FROM_SOURCE}" + exit 1 +} + +detect_target() { + os="$(uname -s)" + arch="$(uname -m)" + + case "$arch" in + x86_64 | amd64) arch="x86_64" ;; + aarch64 | arm64) arch="aarch64" ;; + *) unsupported "unsupported CPU architecture: ${arch}" ;; + esac + + case "$os" in + Linux) + # The Linux binaries are linked against glibc; musl (e.g. Alpine) cannot run them. + if have ldd && ldd --version 2>&1 | grep -qi musl; then + unsupported "this Linux uses musl libc, but the prebuilt binaries need glibc" + fi + TARGET="${arch}-unknown-linux-gnu" + ;; + Darwin) + # A shell running under Rosetta reports x86_64 on an Apple Silicon Mac. + if [ "$arch" = "x86_64" ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || true)" = "1" ]; then + arch="aarch64" + fi + TARGET="${arch}-apple-darwin" + ;; + MINGW* | MSYS* | CYGWIN*) + die "this looks like Windows. Use the PowerShell installer instead: irm https://raw.githubusercontent.com/${REPO}/main/install.ps1 | iex" + ;; + *) + unsupported "unsupported operating system: ${os}" + ;; + esac +} + +# fetch URL DEST +fetch() { + if have curl; then + curl -fsSL --retry 3 -o "$2" "$1" || return 1 + elif have wget; then + wget -q -O "$2" "$1" || return 1 + else + die "need curl or wget to download files" + fi +} + +# fetch_stdout URL +fetch_stdout() { + if have curl; then + curl -fsSL --retry 3 "$1" + elif have wget; then + wget -q -O - "$1" + else + die "need curl or wget to download files" + fi +} + +resolve_version() { + if [ -n "${RI_VERSION:-}" ]; then + VERSION="${RI_VERSION#v}" + elif [ -n "${RI_DOWNLOAD_BASE:-}" ]; then + die "RI_DOWNLOAD_BASE is set, so also set RI_VERSION (for example RI_VERSION=0.3.0)" + else + say "Looking up the latest release..." + json="$(fetch_stdout "https://api.github.com/repos/${REPO}/releases/latest")" || + die "could not look up the latest release (no release published yet, no network, or the GitHub API rate limit). Set RI_VERSION, e.g. RI_VERSION=0.3.0" + tag="$(printf '%s\n' "$json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)" + [ -n "$tag" ] || die "could not read the latest release tag. Set RI_VERSION, e.g. RI_VERSION=0.3.0" + VERSION="${tag#v}" + fi + case "$VERSION" in + '' | *[!0-9A-Za-z.+-]*) die "invalid version: ${VERSION}" ;; + esac +} + +sha256_of() { + if have sha256sum; then + sha256sum "$1" | awk '{print $1}' + elif have shasum; then + shasum -a 256 "$1" | awk '{print $1}' + else + die "need sha256sum or shasum to verify the download" + fi +} + +main() { + have tar || die "need tar to unpack the download" + have curl || have wget || die "need curl or wget to download files" + + detect_target + resolve_version + + INSTALL_DIR="${RI_INSTALL_DIR:-${HOME:?HOME is not set}/.local/bin}" + NAME="repository-intelligence-${VERSION}-${TARGET}" + ARCHIVE="${NAME}.tar.gz" + BASE="${RI_DOWNLOAD_BASE:-https://github.com/${REPO}/releases/download/v${VERSION}}" + BASE="${BASE%/}" + + TMP="$(mktemp -d 2>/dev/null || mktemp -d -t repository-intelligence-install)" + trap 'rm -rf "$TMP"' EXIT INT TERM HUP + + say "Installing repository-intelligence ${VERSION} for ${TARGET}" + fetch "${BASE}/${ARCHIVE}" "${TMP}/${ARCHIVE}" || + die "could not download ${BASE}/${ARCHIVE} (is ${VERSION} a published version for ${TARGET}?)" + fetch "${BASE}/${ARCHIVE}.sha256" "${TMP}/${ARCHIVE}.sha256" || + die "could not download ${BASE}/${ARCHIVE}.sha256" + + expected="$(awk 'NR == 1 {print tolower($1)}' "${TMP}/${ARCHIVE}.sha256")" + actual="$(sha256_of "${TMP}/${ARCHIVE}")" + case "$expected" in + '' | *[!0-9a-f]*) die "the checksum file ${ARCHIVE}.sha256 is not valid" ;; + esac + if [ "${#expected}" -ne 64 ]; then + die "the checksum file ${ARCHIVE}.sha256 is not valid" + fi + if [ "$expected" != "$actual" ]; then + err "checksum mismatch for ${ARCHIVE}" + err " expected: ${expected}" + err " actual: ${actual}" + die "refusing to install a file that does not match its checksum" + fi + say "Checksum OK" + + tar -xzf "${TMP}/${ARCHIVE}" -C "$TMP" || die "could not unpack ${ARCHIVE}" + [ -f "${TMP}/${NAME}/repository-intelligence" ] || die "the archive does not contain ${NAME}/repository-intelligence" + + mkdir -p "$INSTALL_DIR" || die "could not create ${INSTALL_DIR}; set RI_INSTALL_DIR to a writable directory" + # Copy under a temporary name and rename, so a running repository-intelligence is replaced safely. + cp "${TMP}/${NAME}/repository-intelligence" "${INSTALL_DIR}/.repository-intelligence.new.$$" || + die "could not write to ${INSTALL_DIR}; set RI_INSTALL_DIR to a writable directory" + chmod 755 "${INSTALL_DIR}/.repository-intelligence.new.$$" + mv -f "${INSTALL_DIR}/.repository-intelligence.new.$$" "${INSTALL_DIR}/repository-intelligence" + + say "Installed: ${INSTALL_DIR}/repository-intelligence" + "${INSTALL_DIR}/repository-intelligence" --version || + die "the installed binary did not run; it may not suit this system. Build from source instead: ${FROM_SOURCE}" + + case ":${PATH}:" in + *":${INSTALL_DIR}:"*) ;; + *) + say "" + say "${INSTALL_DIR} is not on your PATH. Add it, for example:" + say " export PATH=\"${INSTALL_DIR}:\$PATH\"" + say "(put that line in your shell startup file to keep it; this installer does not edit it)" + ;; + esac + + say "" + say "Next: run 'repository-intelligence --help' to get started." +} + +main "$@" diff --git a/packaging/README.txt b/packaging/README.txt new file mode 100644 index 0000000..fdfe858 --- /dev/null +++ b/packaging/README.txt @@ -0,0 +1,27 @@ +repository-intelligence (repository-intelligence) +================================================= + +Searches local code and returns verbatim source lines for a question. This archive holds the `repository-intelligence` command-line tool, built from the tagged release. + +Install +------- +Put the `repository-intelligence` binary (`repository-intelligence.exe` on Windows) in a directory on your PATH, +or use the installer, which does that for you and checks the checksum: + + macOS / Linux: curl -fsSL https://raw.githubusercontent.com/rustfuture/repository-intelligence/main/install.sh | sh + Windows: irm https://raw.githubusercontent.com/rustfuture/repository-intelligence/main/install.ps1 | iex + +Then: + + repository-intelligence --version + repository-intelligence --help + +Verify this download +-------------------- +Each archive has a matching .sha256 file on the release page: + + sha256sum -c repository-intelligence--.tar.gz.sha256 (Linux) + shasum -a 256 -c repository-intelligence--.tar.gz.sha256 (macOS) + +Docs and source: https://github.com/rustfuture/repository-intelligence +License: see LICENSE diff --git a/src/main.rs b/src/main.rs index daa399b..53671a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,6 +51,9 @@ fn main() { let top = parsed.0; let mut args = parsed.1.into_iter(); match mode.as_str() { + "--version" | "-V" => { + println!("repository-intelligence {}", env!("CARGO_PKG_VERSION")); + } "--help" | "-h" => { println!("Usage: repository-intelligence [OPTIONS] [query...]"); println!(); @@ -72,6 +75,7 @@ fn main() { println!(" --embedding Embedding provider (hash or nomic)"); println!(" --top Limit printed search results (positive integer)"); println!(" --help, -h Print this help message"); + println!(" --version, -V Print the version"); } "--answer" => answer_command(&mut args, false), "--answer-json" => answer_command(&mut args, true), diff --git a/tests/ri_regression.rs b/tests/ri_regression.rs index 6d6cfc0..650aae2 100644 --- a/tests/ri_regression.rs +++ b/tests/ri_regression.rs @@ -759,3 +759,16 @@ fn evidence_text_matches_its_declared_line_span() { } assert!(checked > 0, "expected at least one evidence item"); } + +#[test] +fn version_flag_prints_the_package_version() { + let output = Command::new(env!("CARGO_BIN_EXE_repository-intelligence")) + .arg("--version") + .output() + .expect("run CLI"); + assert!(output.status.success()); + assert_eq!( + String::from_utf8_lossy(&output.stdout).trim(), + format!("repository-intelligence {}", env!("CARGO_PKG_VERSION")) + ); +}