diff --git a/.gitignore b/.gitignore index 364b391a01..152c482935 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,11 @@ logs # Turborepo .turbo +# Nix +result +result-* +.direnv + # IntelliJ and Qodo plugin folders .idea/ .qodo/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f92674a5b0..953350f1ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fix: Reset invalid model selection when using OpenAI Codex provider (PR #10777 by @hannesrudolph) - Fix: Add openai-codex to providers that don't require an API key (PR #10786 by @roomote) - Fix: Detect Gemini models with space-separated names for proper thought signature injection in LiteLLM (PR #10787 by @daniel-lxs) +- Add Nix flake for reproducible development environment with Node.js, pnpm, and native build dependencies ## [3.41.1] - 2026-01-16 diff --git a/README.md b/README.md index 75f37762f9..fed6f8e5a6 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ - [简体中文](locales/zh-CN/README.md) - [繁體中文](locales/zh-TW/README.md) - ... - + --- @@ -66,10 +66,10 @@ Learn more: [Using Modes](https://docs.roocode.com/basic-usage/using-modes) •
-| | | | -| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | -|
Custom Modes |
Checkpoints |
Context Management | +| | | | +| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +|
Installing Roo Code |
Configuring Profiles |
Codebase Indexing | +|
Custom Modes |
Checkpoints |
Context Management |

@@ -149,6 +149,32 @@ If you prefer to install the VSIX package manually: code --install-extension bin/roo-cline-.vsix ``` +### Nix Flake + +A `flake.nix` is provided for [Nix](https://nixos.org/) users: + +```sh +nix develop # Enter dev shell with all dependencies +pnpm install # Install npm packages +pnpm build # Build the project +pnpm test # Run tests +pnpm vsix # Create VSIX package +``` + +To build and install the extension directly: + +```sh +nix build .#vsix && code --install-extension result/*.vsix +``` + +The dev shell provides Node.js 20.x, pnpm, ripgrep, and build tools for native modules. + +After updating dependencies, run `nix run .#update-deps` to update `flake.lock` and the pnpm dependency hash. + +If flakes aren't enabled, prefix commands with: `nix --extra-experimental-features 'nix-command flakes' ` + +> **Note:** Roo Code is also available as a pre-built extension in [nixpkgs](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/applications/editors/vscode/extensions/rooveterinaryinc.roo-cline/default.nix) via `vscode-extensions.rooveterinaryinc.roo-cline`. + --- We use [changesets](https://github.com/changesets/changesets) for versioning and publishing. Check our `CHANGELOG.md` for release notes. diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000..5a9df81916 --- /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": 1768564909, + "narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-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 0000000000..cdb4838796 --- /dev/null +++ b/flake.nix @@ -0,0 +1,375 @@ +# Roo Code Nix Flake +# +# Provides a reproducible development environment +# +# Usage: +# nix develop # Enter dev shell +# nix run # Show welcome banner +# nix fmt # Format nix files +# nix flake check # Run all checks (lint, typecheck, test) +# +# Build and install extension: +# nix build .#vsix && code --install-extension result/*.vsix +# +# Inside dev shell: +# pnpm install # Install npm packages +# pnpm build # Build the project +# pnpm test # Run tests +# pnpm vsix # Create VS Code extension +# eslint # Lint files (eslint and eslint_d available) +# pnpm lint # Run linting via pnpm scripts +# +# Maintenance: +# nix run .#update-deps # Update flake.lock and pnpmDeps hash +# +# If flakes aren't enabled, prefix commands with: +# nix --extra-experimental-features 'nix-command flakes' +# +# See README.md section "Nix Flake" for more information + +{ + description = "Roo Code - AI-Powered Dev Team, Right in Your Editor"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + }: + let + versionFromPackageJson = (builtins.fromJSON (builtins.readFile ./src/package.json)).version; + + in + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = nixpkgs.legacyPackages.${system}; + lib = pkgs.lib; + + nodejs = pkgs.nodejs_20; + # Use pnpm_9 if available, otherwise fall back to pnpm + # pnpm 10.26.1 is available and newer than required 10.8.1, so we'll use that + pnpm = pkgs.pnpm; + + ignoredPaths = [ + ".direnv" + "result" + "result-dev" + "node_modules" + ".turbo" + "dist" + "bin" + ".vscode" + ".cursor" + ]; + + src = lib.cleanSourceWith { + src = lib.cleanSource ./.; + filter = + path: type: + let + baseName = builtins.baseNameOf path; + in + !(builtins.elem baseName ignoredPaths); + }; + + # Chromium is only available on Linux in nixpkgs + chromiumPath = if pkgs.stdenv.isLinux then "${pkgs.chromium}/bin/chromium" else null; + + basePnpmAttrs = { + inherit src; + strictDeps = true; + nativeBuildInputs = [ + nodejs + pnpm + pkgs.pnpmConfigHook + ]; + pnpmDeps = self.packages.${system}.pnpmDeps; + }; + + roo-code-welcome = pkgs.writeShellApplication { + name = "roo-code-welcome"; + runtimeInputs = [ + pkgs.jp2a + nodejs + pnpm + ]; + text = '' + echo "" + if [ -f "./src/assets/images/roo.png" ]; then + jp2a --colors --width=40 ./src/assets/images/roo.png 2>/dev/null || echo "🦘 Roo Code" + else + echo "🦘 Roo Code Development Environment" + fi + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Node.js: $(node --version)" + echo "pnpm: $(pnpm --version)" + echo "" + echo "📦 pnpm install - Install dependencies" + echo "🔧 pnpm build - Build the project" + echo "📋 pnpm test - Run tests (from root)" + echo "📦 pnpm vsix - Create VS Code extension" + echo "" + echo "💡 Tip: For webview-ui tests, run from webview-ui directory:" + echo " cd webview-ui && pnpm test " + echo "" + echo "For VS Code debugging: Press F5" + echo "" + ''; + }; + + mkPnpmCheck = + name: script: extraAttrs: + pkgs.stdenvNoCC.mkDerivation ( + basePnpmAttrs + // { + name = "roo-code-${name}"; + buildPhase = '' + runHook preBuild + export HOME=$TMPDIR + # Disable pnpm self-management (pnpm is provided by Nix) + echo "manage-package-manager-versions=false" >> .npmrc + pnpm run ${script} + runHook postBuild + ''; + installPhase = '' + mkdir -p $out + echo "${name} passed" > $out/result + ''; + } + // extraAttrs + ); + + in + { + formatter = pkgs.nixfmt-tree; + + devShells.default = pkgs.mkShell { + name = "roo-code-dev"; + + packages = + with pkgs; + [ + nodejs + pnpm + git + python3 + pkg-config + gnumake + # turbo is installed via pnpm as a devDependency (version 2.7.6 in package.json) + # We don't include system turbo to avoid version conflicts + # Users should run 'pnpm install' first to get the correct turbo version + ripgrep + jp2a + nodePackages.typescript-language-server + nodePackages.eslint + nodePackages.eslint_d + nil + ] + ++ lib.optionals stdenv.isLinux [ + chromium + ]; + + buildInputs = + with pkgs; + [ + openssl + ] + ++ lib.optionals stdenv.isLinux [ + stdenv.cc.cc.lib + ]; + + env = { + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = "1"; + RIPGREP_PATH = "${pkgs.ripgrep}/bin/rg"; + NODE_ENV = "development"; + } + // lib.optionalAttrs pkgs.stdenv.isLinux { + PUPPETEER_EXECUTABLE_PATH = chromiumPath; + }; + + shellHook = '' + ${lib.getExe roo-code-welcome} + ''; + }; + + packages = + let + version = versionFromPackageJson; + in + { + # Pre-fetch pnpm dependencies (for reproducible builds) + # Update hash when pnpm-lock.yaml changes: + # 1. Set hash = lib.fakeHash; + # 2. Run: nix build .#pnpmDeps + # 3. Copy the "got:" hash from the error message + pnpmDeps = pkgs.fetchPnpmDeps { + pname = "roo-code-pnpm-deps"; + inherit version src; + fetcherVersion = 2; + hash = "sha256-jtIRL4E4d0QjvQGHAVmcXvEXblRdg58VknaMlh/TxCY="; + }; + + vsix = pkgs.stdenvNoCC.mkDerivation ( + basePnpmAttrs + // { + pname = "roo-code-vsix"; + inherit version; + + buildPhase = '' + runHook preBuild + export HOME=$TMPDIR + # Disable pnpm self-management (pnpm is provided by Nix) + echo "manage-package-manager-versions=false" >> .npmrc + pnpm run vsix + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out + cp -v bin/*.vsix $out/ + runHook postInstall + ''; + + meta = with lib; { + description = "AI-powered autonomous coding agent that lives in your editor"; + homepage = "https://github.com/RooCodeInc/Roo-Code"; + license = licenses.asl20; + platforms = platforms.unix; + }; + } + ); + + default = self.packages.${system}.vsix; + }; + + apps = { + welcome = { + type = "app"; + program = lib.getExe roo-code-welcome; + }; + + build-vsix = { + type = "app"; + program = lib.getExe ( + pkgs.writeShellApplication { + name = "build-vsix"; + text = '' + echo "Building VSIX..." + nix build .#vsix --print-out-paths + ''; + } + ); + }; + + update-deps = { + type = "app"; + program = lib.getExe ( + pkgs.writeShellApplication { + name = "update-deps"; + runtimeInputs = [ + pkgs.gnused + pkgs.gnugrep + ]; + text = '' + # Safety check: ensure flake.nix has no uncommitted changes + if ! git diff --quiet flake.nix 2>/dev/null; then + echo "Error: flake.nix has uncommitted changes. Commit or stash them first." + exit 1 + fi + + echo "==> Updating flake inputs (nixpkgs, flake-utils)..." + nix flake update + + echo "" + echo "==> Updating pnpmDeps hash..." + + # Set hash to empty to trigger rebuild + sed -i 's|hash = "sha256-[^"]*";|hash = "";|' flake.nix + + # Build and capture the error output + if output=$(nix build .#pnpmDeps 2>&1); then + echo "Build succeeded - hash unchanged" + # Restore the original hash since build succeeded + git checkout flake.nix 2>/dev/null || true + exit 0 + fi + + # Extract the correct hash from "got: sha256-..." (with fallback patterns) + new_hash=$(echo "$output" | grep -oP 'got:\s+\Ksha256-[A-Za-z0-9+/=]+' | head -1) + + # Fallback: try alternative pattern if first didn't match + if [ -z "$new_hash" ]; then + new_hash=$(echo "$output" | grep -oE 'sha256-[A-Za-z0-9+/=]+' | tail -1) + fi + + if [ -z "$new_hash" ]; then + echo "Error: Could not extract hash from build output" + echo "$output" + # Restore flake.nix since we failed + git checkout flake.nix 2>/dev/null || true + exit 1 + fi + + # Update flake.nix with the new hash + sed -i "s|hash = \"\";|hash = \"$new_hash\";|" flake.nix + + echo "Updated pnpmDeps hash to: $new_hash" + echo "" + echo "Run 'nix fmt' to format, then commit flake.nix and flake.lock" + ''; + } + ); + }; + + default = self.apps.${system}.welcome; + }; + + checks = { + lint = mkPnpmCheck "lint" "lint" { }; + typecheck = mkPnpmCheck "typecheck" "check-types" { }; + test = mkPnpmCheck "test" "test" ( + { + CI = "true"; + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = "1"; + } + // lib.optionalAttrs pkgs.stdenv.isLinux { + nativeBuildInputs = basePnpmAttrs.nativeBuildInputs ++ [ pkgs.chromium ]; + PUPPETEER_EXECUTABLE_PATH = chromiumPath; + } + ); + + format = pkgs.stdenvNoCC.mkDerivation { + name = "roo-code-format-check"; + src = ./.; + strictDeps = true; + + nativeBuildInputs = [ pkgs.nixfmt-tree ]; + + buildPhase = '' + runHook preBuild + nixfmt --check flake.nix + runHook postBuild + ''; + + installPhase = '' + mkdir -p $out + echo "Format check passed" > $out/result + ''; + }; + }; + } + ) + // { + overlays.default = final: prev: { + roo-code-vsix = self.packages.${final.system}.vsix; + }; + }; +} diff --git a/package.json b/package.json index ed26ce1734..c96df8667a 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "prettier": "^3.4.2", "rimraf": "^6.0.1", "tsx": "^4.19.3", - "turbo": "^2.5.6", + "turbo": "^2.7.6", "typescript": "5.8.3" }, "lint-staged": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 177d0b3e5a..455f472af1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,8 +74,8 @@ importers: specifier: ^4.19.3 version: 4.19.4 turbo: - specifier: ^2.5.6 - version: 2.5.6 + specifier: ^2.7.6 + version: 2.7.6 typescript: specifier: 5.8.3 version: 5.8.3 @@ -530,7 +530,7 @@ importers: version: 5.2.0(eslint@9.27.0(jiti@2.4.2)) eslint-plugin-turbo: specifier: ^2.4.4 - version: 2.5.6(eslint@9.27.0(jiti@2.4.2))(turbo@2.5.6) + version: 2.5.6(eslint@9.27.0(jiti@2.4.2))(turbo@2.7.6) globals: specifier: ^16.0.0 version: 16.1.0 @@ -9886,38 +9886,38 @@ packages: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - turbo-darwin-64@2.5.6: - resolution: {integrity: sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A==} + turbo-darwin-64@2.7.6: + resolution: {integrity: sha512-bYu0qnWju2Ha3EbIkPCk1SMLT3sltKh1P/Jy5FER6BmH++H5z+T5MHh3W1Xoers9rk4N1VdKvog9FO1pxQyjhw==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.5.6: - resolution: {integrity: sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA==} + turbo-darwin-arm64@2.7.6: + resolution: {integrity: sha512-KCxTf3Y1hgNLYIWRLw8bwH8Zie9RyCGoxAlXYsCBI/YNqBSR+ZZK9KYzFxAqDaVaNvTwLFv3rJRGsXOFWg4+Uw==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.5.6: - resolution: {integrity: sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA==} + turbo-linux-64@2.7.6: + resolution: {integrity: sha512-vjoU8zIfNgvJR3cMitgw7inEoi6bmuVuFawDl5yKtxjAEhDktFdRBpGS3WojD4l3BklBbIK689ssXcGf21LxRA==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.5.6: - resolution: {integrity: sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ==} + turbo-linux-arm64@2.7.6: + resolution: {integrity: sha512-TcMpBvTqZf+1DptrVYLbZls7WY1UVNDTGaf0bo7/GCgWYv5eZHCVo4Td7kCJeDU4glbXg67REX0md0S0V6ghMg==} cpu: [arm64] os: [linux] - turbo-windows-64@2.5.6: - resolution: {integrity: sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg==} + turbo-windows-64@2.7.6: + resolution: {integrity: sha512-1/MhkYldiihjneY8QnnDMbAkHXn/udTWSVYS94EMlkE9AShozsLTTOT1gDOpX06EfEW5njP09suhMvxbvwuwpQ==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.5.6: - resolution: {integrity: sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q==} + turbo-windows-arm64@2.7.6: + resolution: {integrity: sha512-0wDVnUJLFAWm4ZzOQFDkbyyUqaszorTGf3Rdc22IRIyJTTLd6ajqdb+cWD89UZ1RKr953+PZR1gqgWQY4PDuhA==} cpu: [arm64] os: [win32] - turbo@2.5.6: - resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==} + turbo@2.7.6: + resolution: {integrity: sha512-PO9AvJLEsNLO+EYhF4zB+v10hOjsJe5kJW+S6tTbRv+TW7gf1Qer4mfjP9h3/y9h8ZiPvOrenxnEgDtFgaM5zw==} hasBin: true turndown@7.2.0: @@ -16131,11 +16131,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.5.6(eslint@9.27.0(jiti@2.4.2))(turbo@2.5.6): + eslint-plugin-turbo@2.5.6(eslint@9.27.0(jiti@2.4.2))(turbo@2.7.6): dependencies: dotenv: 16.0.3 eslint: 9.27.0(jiti@2.4.2) - turbo: 2.5.6 + turbo: 2.7.6 eslint-scope@8.3.0: dependencies: @@ -20741,32 +20741,32 @@ snapshots: tunnel@0.0.6: {} - turbo-darwin-64@2.5.6: + turbo-darwin-64@2.7.6: optional: true - turbo-darwin-arm64@2.5.6: + turbo-darwin-arm64@2.7.6: optional: true - turbo-linux-64@2.5.6: + turbo-linux-64@2.7.6: optional: true - turbo-linux-arm64@2.5.6: + turbo-linux-arm64@2.7.6: optional: true - turbo-windows-64@2.5.6: + turbo-windows-64@2.7.6: optional: true - turbo-windows-arm64@2.5.6: + turbo-windows-arm64@2.7.6: optional: true - turbo@2.5.6: + turbo@2.7.6: optionalDependencies: - turbo-darwin-64: 2.5.6 - turbo-darwin-arm64: 2.5.6 - turbo-linux-64: 2.5.6 - turbo-linux-arm64: 2.5.6 - turbo-windows-64: 2.5.6 - turbo-windows-arm64: 2.5.6 + turbo-darwin-64: 2.7.6 + turbo-darwin-arm64: 2.7.6 + turbo-linux-64: 2.7.6 + turbo-linux-arm64: 2.7.6 + turbo-windows-64: 2.7.6 + turbo-windows-arm64: 2.7.6 turndown@7.2.0: dependencies: