diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 0e334de7..df8ed376 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -1,3 +1,4 @@ +--- name: Nix Build Verification concurrency: @@ -9,13 +10,15 @@ on: branches: - main paths: - - 'nix/**' + - 'flake.nix' + - 'flake.lock' - '.github/workflows/nix-build.yml' push: branches: - main paths: - - 'nix/**' + - 'flake.nix' + - 'flake.lock' - '.github/workflows/nix-build.yml' workflow_dispatch: @@ -53,7 +56,7 @@ jobs: - name: Build with Nix run: | - nix-build nix/default.nix --show-trace + nix build .#infer --show-trace --print-build-logs - name: Verify binary run: | @@ -93,15 +96,15 @@ jobs: - name: Check Nix formatting (nixfmt-rfc-style) run: | - nix-shell -p nixfmt-rfc-style --run "nixfmt --check nix/package.nix nix/default.nix" + nix-shell -p nixfmt-rfc-style --run "nixfmt --check flake.nix" - name: Lint with statix run: | - nix-shell -p statix --run "statix check nix/" + nix-shell -p statix --run "statix check flake.nix" - - name: Evaluate Nix expression + - name: Check flake evaluates on all systems run: | - nix-instantiate --eval --strict nix/default.nix --show-trace + nix flake check --all-systems --no-build --show-trace summary: name: Build Summary @@ -124,4 +127,4 @@ jobs: exit 1 fi - echo "✅ All Nix build checks passed!" + echo "All Nix build checks passed!" diff --git a/.github/workflows/nix-version-sync.yml b/.github/workflows/nix-version-sync.yml deleted file mode 100644 index eb04f674..00000000 --- a/.github/workflows/nix-version-sync.yml +++ /dev/null @@ -1,152 +0,0 @@ -name: Nix Version Sync - -on: - release: - types: - - published - workflow_dispatch: - inputs: - version: - description: 'Version to sync (e.g., 0.103.0)' - required: true - type: string - -permissions: - contents: write - pull-requests: write - -jobs: - update-nix-version: - name: Update Nix package version - runs-on: ubuntu-24.04 - - steps: - - name: Checkout repository - uses: actions/checkout@v6.0.2 - with: - ref: main - fetch-depth: 0 - - - name: Install Nix - uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - extra_nix_config: | - experimental-features = nix-command flakes - - - name: Set up Magic Nix Cache - uses: DeterminateSystems/magic-nix-cache-action@v13 - - - name: Determine version - id: version - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - VERSION="${{ inputs.version }}" - else - VERSION="${{ github.event.release.tag_name }}" - VERSION="${VERSION#v}" - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - echo "Version to sync: $VERSION" - - - name: Calculate source hash - id: source-hash - run: | - VERSION="${{ steps.version.outputs.version }}" - URL="https://github.com/inference-gateway/cli/archive/refs/tags/v${VERSION}.tar.gz" - - echo "Downloading source from: $URL" - # nix-prefetch-url emits a nix-base32 hash; convert to SRI (base64) - # because that's what fetchFromGitHub's `hash` attribute expects. - NIX32_HASH=$(nix-prefetch-url --unpack "$URL") - SRI_HASH=$(nix-hash --to-sri --type sha256 "$NIX32_HASH") - # Strip the "sha256-" prefix so the consumer can prepend it consistently. - HASH="${SRI_HASH#sha256-}" - echo "Source hash: sha256-$HASH" - echo "hash=$HASH" >> $GITHUB_OUTPUT - - - name: Update version in Nix expression - run: | - VERSION="${{ steps.version.outputs.version }}" - HASH="${{ steps.source-hash.outputs.hash }}" - sed -i "s/version = \"[0-9.]*\";/version = \"$VERSION\";/" nix/package.nix - sed -i "s|hash = \"sha256-[A-Za-z0-9+/=]*\";|hash = \"sha256-$HASH\";|" nix/package.nix - echo "Updated nix/package.nix with version $VERSION" - cat nix/package.nix | grep -A2 "version =" - - - name: Calculate vendor hash - id: vendor-hash - run: | - echo "Attempting build to calculate vendorHash..." - sed -i 's|vendorHash = "sha256-[A-Za-z0-9+/=]*";|vendorHash = "";|' nix/package.nix - BUILD_OUTPUT=$(nix-build nix/default.nix 2>&1 || true) - # `got: sha256-=` is already SRI-formatted in the build error, - # so we just capture it verbatim. - VENDOR_HASH=$(echo "$BUILD_OUTPUT" | grep -oP "got:\s+sha256-\K[A-Za-z0-9+/=]+" | head -1) - - if [ -z "$VENDOR_HASH" ]; then - echo "::error::Failed to calculate vendorHash" - echo "$BUILD_OUTPUT" - exit 1 - fi - - echo "Vendor hash: sha256-$VENDOR_HASH" - echo "hash=$VENDOR_HASH" >> $GITHUB_OUTPUT - - - name: Update vendor hash in Nix expression - run: | - VENDOR_HASH="${{ steps.vendor-hash.outputs.hash }}" - sed -i "s|vendorHash = \"[^\"]*\";|vendorHash = \"sha256-$VENDOR_HASH\";|" nix/package.nix - echo "Updated vendorHash in nix/package.nix" - - - name: Format Nix file - run: | - nix-shell -p nixfmt-rfc-style --run "nixfmt nix/package.nix" - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v8.1.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - commit-message: 'chore(nix): Update package to v${{ steps.version.outputs.version }}' - title: 'chore(nix): Update package to v${{ steps.version.outputs.version }}' - body: | - ## Automated Nix Package Update - - This PR updates the Nix package expression to version **${{ steps.version.outputs.version }}**. - - ### Changes - - ✅ Updated `version` to `${{ steps.version.outputs.version }}` - - ✅ Updated source `hash` to `sha256-${{ steps.source-hash.outputs.hash }}` - - ✅ Updated `vendorHash` to `sha256-${{ steps.vendor-hash.outputs.hash }}` - - ✅ Formatted with nixfmt-rfc-style - - The `Nix Build Verification` workflow runs on this PR and is the - authoritative gate for verifying the updated hashes build cleanly. - - ### Verification - ```bash - nix-build nix/default.nix - result/bin/infer version - ``` - - ### Related - - Release: ${{ github.event.release.html_url || 'Manual trigger' }} - - --- - 🤖 Auto-generated by `.github/workflows/nix-version-sync.yml` - branch: chore/nix-update-v${{ steps.version.outputs.version }} - delete-branch: true - labels: | - nix - dependencies - automated - - - name: Summary - run: | - echo "## ✅ Nix Package Updated" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Version**: ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY - echo "- **Source Hash**: sha256-${{ steps.source-hash.outputs.hash }}" >> $GITHUB_STEP_SUMMARY - echo "- **Vendor Hash**: sha256-${{ steps.vendor-hash.outputs.hash }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "A pull request has been created to merge these changes." >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b48633fb..1d6c3026 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,11 +65,15 @@ jobs: @semantic-release/commit-analyzer@13.0.1 \ @semantic-release/release-notes-generator@14.1.0 \ @semantic-release/changelog@6.0.3 \ + @semantic-release/exec@7.1.0 \ @semantic-release/git@10.0.1 \ @semantic-release/github@1.0.0 \ conventional-changelog-conventionalcommits@9.1.0 \ conventional-changelog-cli@5.0.0 + - name: Install Determinate Nix + uses: DeterminateSystems/determinate-nix-action@v3 + - name: Check for existing releases id: check_releases env: diff --git a/.releaserc.yaml b/.releaserc.yaml index d417e732..a833adc6 100644 --- a/.releaserc.yaml +++ b/.releaserc.yaml @@ -87,9 +87,15 @@ plugins: The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + - - "@semantic-release/exec" + - prepareCmd: | + sed -i.bak 's|version = "[^"]*";|version = "${nextRelease.version}";|' flake.nix && rm flake.nix.bak + determinate-nixd fix hashes --auto-apply flake.nix + - - "@semantic-release/git" - assets: - CHANGELOG.md + - flake.nix message: | chore(release): ${nextRelease.version} [skip ci] @@ -124,6 +130,21 @@ plugins: curl -fsSL https://raw.githubusercontent.com/inference-gateway/cli/main/install.sh | bash -s -- --install-dir $HOME/.local/bin ``` + ### Nix Flake + + Run directly without installing: + + ```bash + nix run github:inference-gateway/cli/<%= nextRelease.gitTag %> + ``` + + Or pin it in a [Flox](https://flox.dev) manifest (`.flox/env/manifest.toml`): + + ```toml + [install] + infer.flake = "github:inference-gateway/cli/<%= nextRelease.gitTag %>" + ``` + ### Binary Download Download the appropriate binary for your platform from the assets below. diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..6da30234 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1778580735, + "narHash": "sha256-t+8AVV8ExvOmslz2sLIgw/hJBKlyl65rJvxjvvjHgpE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "48d91f2c0ce7b9e589f967d4f685153dd765dcdd", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..ce97b25e --- /dev/null +++ b/flake.nix @@ -0,0 +1,148 @@ +{ + description = "Inference Gateway CLI - infer"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs) lib stdenv; + + version = "0.109.3"; + + infer = pkgs.buildGoModule (finalAttrs: { + __structuredAttrs = true; + + pname = "infer"; + inherit version; + + src = lib.cleanSourceWith { + src = ./.; + filter = + path: type: + let + baseName = baseNameOf (toString path); + relPath = lib.removePrefix (toString ./. + "/") (toString path); + in + !( + baseName == ".git" + || baseName == "dist" + || baseName == "result" + || baseName == ".flox" + || baseName == ".infer" + || baseName == ".task" + || baseName == "node_modules" + || (type == "regular" && relPath == "infer") + || (type == "directory" && lib.hasPrefix "internal/display/macos/ComputerUse/build" relPath) + ); + }; + + vendorHash = "sha256-+ntde+NYik4gEicMlyonBAE+gkHoYYiw3G0dbQ/gX2I="; + + goSum = ./go.sum; + + proxyVendor = true; + + env.CGO_ENABLED = if stdenv.hostPlatform.isDarwin then "1" else "0"; + + ldflags = [ + "-s" + "-w" + "-X=github.com/inference-gateway/cli/cmd.version=${version}" + "-X=github.com/inference-gateway/cli/cmd.commit=${self.shortRev or "dirty"}" + ]; + + preCheck = '' + export HOME=$TMPDIR + ''; + + checkFlags = [ + "-skip=TestIntegration" + ]; + + nativeBuildInputs = [ + pkgs.installShellFiles + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ pkgs.swift ]; + + buildInputs = lib.optionals stdenv.hostPlatform.isDarwin [ pkgs.apple-sdk ]; + + preBuild = lib.optionalString stdenv.hostPlatform.isDarwin '' + export SDKROOT="${pkgs.apple-sdk}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk" + pushd internal/display/macos/ComputerUse > /dev/null + bash ./build.sh + popd > /dev/null + ''; + + postInstall = '' + if [ -f $out/bin/cli ]; then + mv $out/bin/cli $out/bin/infer + fi + + installShellCompletion --cmd infer \ + --bash <($out/bin/infer completion bash) \ + --fish <($out/bin/infer completion fish) \ + --zsh <($out/bin/infer completion zsh) + ''; + + meta = { + description = "Command-line interface for the Inference Gateway - AI model interaction manager"; + longDescription = '' + The Inference Gateway CLI is a command-line tool for managing AI model interactions. + It provides interactive chat, autonomous agent execution, and extensive tool + integration for LLMs, with support for both the MCP and A2A protocols, as well + as computer use for GUI automation. It can also run as a Telegram bot for + remote-controlling the agent from chat. + ''; + homepage = "https://github.com/inference-gateway/cli"; + changelog = "https://github.com/inference-gateway/cli/blob/v${version}/CHANGELOG.md"; + license = lib.licenses.mit; + maintainers = [ + { + name = "Eden Reich"; + email = "eden.reich@gmail.com"; + github = "edenreich"; + githubId = 26537388; + } + ]; + mainProgram = "infer"; + platforms = lib.platforms.unix; + }; + }); + in + { + packages = { + default = infer; + inherit infer; + }; + + apps.default = { + type = "app"; + program = "${infer}/bin/infer"; + meta = { + description = "Run the infer CLI"; + mainProgram = "infer"; + }; + }; + + devShells.default = pkgs.mkShell { + packages = [ + pkgs.go + pkgs.go-task + pkgs.golangci-lint + pkgs.gopls + ]; + }; + } + ); +}