diff --git a/INSTALL_FLOWCHAIN_WINDOWS.ps1 b/INSTALL_FLOWCHAIN_WINDOWS.ps1 new file mode 100644 index 00000000..04485126 --- /dev/null +++ b/INSTALL_FLOWCHAIN_WINDOWS.ps1 @@ -0,0 +1,436 @@ +param( + [string]$InstallRoot = (Join-Path ([Environment]::GetFolderPath("UserProfile")) "FlowMemory"), + [string]$RepoUrl = "https://github.com/FlowmemoryAI/FlowMemory.git", + [string]$Branch = "main", + [switch]$SkipToolInstall, + [switch]$SkipRepoSetup, + [switch]$SkipSmoke, + [switch]$NoServers, + [switch]$CheckOnly +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +function Write-Step { + param([string]$Message) + Write-Host "" + Write-Host "== $Message ==" -ForegroundColor Cyan +} + +function Write-Ok { + param([string]$Message) + Write-Host "[ok] $Message" -ForegroundColor Green +} + +function Write-Warn { + param([string]$Message) + Write-Host "[warn] $Message" -ForegroundColor Yellow +} + +function Invoke-Checked { + param( + [string]$FilePath, + [string[]]$ArgumentList + ) + + Write-Host "> $FilePath $($ArgumentList -join ' ')" -ForegroundColor DarkGray + & $FilePath @ArgumentList + if ($LASTEXITCODE -ne 0) { + throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $($ArgumentList -join ' ')" + } +} + +function Add-UserPathEntry { + param([string]$PathToAdd) + + $expanded = [Environment]::ExpandEnvironmentVariables($PathToAdd) + if (-not (Test-Path -LiteralPath $expanded)) { + return + } + + $userPath = [Environment]::GetEnvironmentVariable("Path", "User") + if ([string]::IsNullOrWhiteSpace($userPath)) { + $userPath = "" + } + + $parts = $userPath.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries) + $alreadyPresent = $false + foreach ($part in $parts) { + if ($part.TrimEnd("\") -ieq $expanded.TrimEnd("\")) { + $alreadyPresent = $true + break + } + } + + if (-not $alreadyPresent) { + $newPath = if ([string]::IsNullOrWhiteSpace($userPath)) { $expanded } else { "$userPath;$expanded" } + [Environment]::SetEnvironmentVariable("Path", $newPath, "User") + } +} + +function Refresh-Path { + $machinePath = [Environment]::GetEnvironmentVariable("Path", "Machine") + $userPath = [Environment]::GetEnvironmentVariable("Path", "User") + $extras = @( + (Join-Path $env:ProgramFiles "Git\cmd"), + (Join-Path $env:ProgramFiles "Git\bin"), + (Join-Path $env:ProgramFiles "nodejs"), + (Join-Path $env:USERPROFILE ".cargo\bin"), + (Join-Path $env:USERPROFILE ".foundry\bin"), + (Join-Path $env:LOCALAPPDATA "Programs\Python\Python312"), + (Join-Path $env:LOCALAPPDATA "Programs\Python\Python312\Scripts") + ) + + $env:Path = (@($machinePath, $userPath) + $extras | Where-Object { + -not [string]::IsNullOrWhiteSpace($_) + }) -join ";" +} + +function Test-Tool { + param([string]$Command) + Refresh-Path + return [bool](Get-Command $Command -ErrorAction SilentlyContinue) +} + +function Test-Python { + Refresh-Path + if (Get-Command py -ErrorAction SilentlyContinue) { + & py -3 --version *> $null + if ($LASTEXITCODE -eq 0) { + return $true + } + } + + if (Get-Command python -ErrorAction SilentlyContinue) { + & python --version *> $null + if ($LASTEXITCODE -eq 0) { + return $true + } + } + + return $false +} + +function Install-WingetPackage { + param( + [string]$DisplayName, + [string]$Command, + [string]$PackageId + ) + + if (Test-Tool $Command) { + Write-Ok "$DisplayName is already installed" + return + } + + if ($SkipToolInstall) { + Write-Warn "$DisplayName is missing, and -SkipToolInstall was set" + return + } + + Write-Step "Install $DisplayName" + Invoke-Checked "winget" @( + "install", + "--id", + $PackageId, + "--exact", + "--source", + "winget", + "--accept-package-agreements", + "--accept-source-agreements", + "--silent" + ) + Refresh-Path + + if (-not (Test-Tool $Command)) { + throw "$DisplayName was installed, but '$Command' is not available in this PowerShell session. Close PowerShell, open it again, and rerun this installer." + } + + Write-Ok "$DisplayName installed" +} + +function Install-Python { + if (Test-Python) { + Write-Ok "Python 3 is already installed" + return + } + + if ($SkipToolInstall) { + Write-Warn "Python 3 is missing, and -SkipToolInstall was set" + return + } + + Write-Step "Install Python 3" + Invoke-Checked "winget" @( + "install", + "--id", + "Python.Python.3.12", + "--exact", + "--source", + "winget", + "--accept-package-agreements", + "--accept-source-agreements", + "--silent" + ) + Refresh-Path + + if (-not (Test-Python)) { + throw "Python 3 was installed, but it is not available in this PowerShell session. Close PowerShell, open it again, and rerun this installer." + } + + Write-Ok "Python 3 installed" +} + +function Install-Rust { + if ((Test-Tool "cargo") -and (Test-Tool "rustc")) { + Write-Ok "Rust and Cargo are already installed" + return + } + + if ($SkipToolInstall) { + Write-Warn "Rust/Cargo is missing, and -SkipToolInstall was set" + return + } + + Write-Step "Install Rust toolchain" + Invoke-Checked "winget" @( + "install", + "--id", + "Rustlang.Rustup", + "--exact", + "--source", + "winget", + "--accept-package-agreements", + "--accept-source-agreements", + "--silent" + ) + Add-UserPathEntry (Join-Path $env:USERPROFILE ".cargo\bin") + Refresh-Path + + if (Test-Tool "rustup") { + Invoke-Checked "rustup" @("default", "stable") + } + + if (-not ((Test-Tool "cargo") -and (Test-Tool "rustc"))) { + throw "Rust was installed, but Cargo/Rustc are not available in this PowerShell session. Close PowerShell, open it again, and rerun this installer." + } + + Write-Ok "Rust and Cargo installed" +} + +function Get-GitBash { + Refresh-Path + + $programFilesX86 = [Environment]::GetFolderPath("ProgramFilesX86") + $candidates = @( + (Join-Path $env:ProgramFiles "Git\bin\bash.exe"), + (Join-Path $env:ProgramFiles "Git\usr\bin\bash.exe") + ) + + if (-not [string]::IsNullOrWhiteSpace($programFilesX86)) { + $candidates += @( + (Join-Path $programFilesX86 "Git\bin\bash.exe"), + (Join-Path $programFilesX86 "Git\usr\bin\bash.exe") + ) + } + + $bashCommand = Get-Command bash.exe -ErrorAction SilentlyContinue + if ($bashCommand) { + $candidates += $bashCommand.Source + } + + foreach ($candidate in $candidates) { + if (-not [string]::IsNullOrWhiteSpace($candidate) -and (Test-Path -LiteralPath $candidate)) { + return $candidate + } + } + + return $null +} + +function Install-Foundry { + if (Test-Tool "forge") { + Write-Ok "Foundry is already installed" + return + } + + if ($SkipToolInstall) { + Write-Warn "Foundry is missing, and -SkipToolInstall was set" + return + } + + $bash = Get-GitBash + if ([string]::IsNullOrWhiteSpace($bash)) { + throw "Git Bash is required to install Foundry on Windows. Rerun this installer so Git can be installed first." + } + + Write-Step "Install Foundry" + Write-Host "Foundry's Windows installer runs through Git Bash, so this step uses Git Bash automatically." + Invoke-Checked $bash @("-lc", "curl -L https://foundry.paradigm.xyz | bash") + Invoke-Checked $bash @("-lc", 'export PATH="$HOME/.foundry/bin:$PATH"; foundryup') + + Add-UserPathEntry (Join-Path $env:USERPROFILE ".foundry\bin") + Refresh-Path + + if (-not (Test-Tool "forge")) { + throw "Foundry installed, but 'forge' is not available in this PowerShell session. Close PowerShell, open it again, and rerun this installer." + } + + Write-Ok "Foundry installed" +} + +function Show-ToolStatus { + Write-Step "Tool status" + + $tools = @( + @{ Name = "winget"; Available = (Test-Tool "winget") }, + @{ Name = "git"; Available = (Test-Tool "git") }, + @{ Name = "node"; Available = (Test-Tool "node") }, + @{ Name = "npm"; Available = (Test-Tool "npm") }, + @{ Name = "cargo"; Available = (Test-Tool "cargo") }, + @{ Name = "rustc"; Available = (Test-Tool "rustc") }, + @{ Name = "forge"; Available = (Test-Tool "forge") }, + @{ Name = "python3"; Available = (Test-Python) } + ) + + $missing = @() + foreach ($tool in $tools) { + if ($tool.Available) { + Write-Ok $tool.Name + } else { + Write-Warn $tool.Name + $missing += $tool.Name + } + } + + return $missing +} + +function Install-Tools { + Write-Step "Prepare Windows tools" + if ($SkipToolInstall) { + Write-Warn "Skipping tool installation because -SkipToolInstall was set" + return + } + + if (-not (Test-Tool "winget")) { + throw "winget is missing. Install or update 'App Installer' from the Microsoft Store, then rerun this installer." + } + + Invoke-Checked "winget" @("source", "update") + Install-WingetPackage -DisplayName "Git for Windows" -Command "git" -PackageId "Git.Git" + Install-WingetPackage -DisplayName "Node.js LTS" -Command "node" -PackageId "OpenJS.NodeJS.LTS" + + if (-not (Test-Tool "npm")) { + throw "Node.js is installed, but npm is missing. Close PowerShell, open it again, and rerun this installer." + } + + Install-Python + Install-Rust + Install-Foundry +} + +function Get-RepoDirectory { + $localSetup = Join-Path $PSScriptRoot "START_FLOWCHAIN_LOCAL.ps1" + $localGit = Join-Path $PSScriptRoot ".git" + if ((Test-Path -LiteralPath $localSetup) -and (Test-Path -LiteralPath $localGit)) { + Write-Ok "Using current repository at $PSScriptRoot" + return $PSScriptRoot + } + + $repoDir = Join-Path $InstallRoot "FlowMemory" + New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null + + if (Test-Path -LiteralPath (Join-Path $repoDir ".git")) { + Write-Step "Update existing FlowMemory checkout" + Invoke-Checked "git" @("-C", $repoDir, "fetch", "origin") + Invoke-Checked "git" @("-C", $repoDir, "checkout", $Branch) + Invoke-Checked "git" @("-C", $repoDir, "pull", "--ff-only", "origin", $Branch) + return $repoDir + } + + if (Test-Path -LiteralPath $repoDir) { + $entries = Get-ChildItem -LiteralPath $repoDir -Force -ErrorAction SilentlyContinue + if ($entries.Count -gt 0) { + $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" + $repoDir = Join-Path $InstallRoot "FlowMemory-$timestamp" + Write-Warn "Existing non-git folder found. Cloning into $repoDir instead." + } + } + + Write-Step "Clone FlowMemory" + Invoke-Checked "git" @("clone", "--branch", $Branch, $RepoUrl, $repoDir) + return $repoDir +} + +function Run-RepoSetup { + param([string]$RepoDir) + + if ($SkipRepoSetup) { + Write-Warn "Skipping repo setup because -SkipRepoSetup was set" + return + } + + $setupScript = Join-Path $RepoDir "START_FLOWCHAIN_LOCAL.ps1" + if (-not (Test-Path -LiteralPath $setupScript)) { + throw "Expected setup script not found: $setupScript" + } + + Write-Step "Run FlowChain local setup" + $args = @( + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-File", + $setupScript + ) + + if ($SkipSmoke) { + $args += "-SkipSmoke" + } + + if ($NoServers) { + $args += "-NoServers" + } + + Invoke-Checked "powershell" $args +} + +Write-Host "FlowChain beginner Windows installer" -ForegroundColor Cyan +Write-Host "This installs local developer tools, clones FlowMemory, and starts the local/private test package." +Write-Host "It does not install production validator software, deploy mainnet contracts, or use real funds." + +if (-not $SkipToolInstall) { + Write-Host "" + Write-Host "Windows may ask for permission while installing tools. Click Yes if prompted." -ForegroundColor Yellow +} + +Refresh-Path + +if ($CheckOnly) { + $missingTools = @(Show-ToolStatus) + if ($missingTools.Count -gt 0) { + throw "Missing tools: $($missingTools -join ', ')" + } + exit 0 +} + +Install-Tools +$missingAfterInstall = @(Show-ToolStatus) +if ($missingAfterInstall.Count -gt 0) { + throw "Missing tools after install attempt: $($missingAfterInstall -join ', ')" +} + +$repoDirectory = Get-RepoDirectory +Run-RepoSetup -RepoDir $repoDirectory + +Write-Host "" +Write-Host "FlowChain local/private setup is ready." -ForegroundColor Green +Write-Host "Repository: $repoDirectory" +Write-Host "Dashboard: http://127.0.0.1:5173/" +Write-Host "Control plane: http://127.0.0.1:8675/" +Write-Host "" +Write-Host "To rerun later:" +Write-Host "cd `"$repoDirectory`"" +Write-Host "powershell -ExecutionPolicy Bypass -File .\START_FLOWCHAIN_LOCAL.ps1 -SkipInstall" diff --git a/README.md b/README.md index c588dea2..92f1f8e0 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,12 @@ This repository contains the FlowMemory V0 foundation: project operating docs, l ## Start Here -For a second computer or a non-technical local test, use the beginner setup -guide: +For a second computer or a non-technical local test, use the beginner Windows +installer. It installs missing tools, clones the repo, installs dependencies, +runs the local setup, and opens the local control plane and dashboard: ```powershell -git clone -b release/flowchain-private-testnet https://github.com/FlowmemoryAI/FlowMemory.git -cd FlowMemory -powershell -ExecutionPolicy Bypass -File .\START_FLOWCHAIN_LOCAL.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -Command '$p=Join-Path $env:TEMP "INSTALL_FLOWCHAIN_WINDOWS.ps1"; Invoke-WebRequest "https://raw.githubusercontent.com/FlowmemoryAI/FlowMemory/main/INSTALL_FLOWCHAIN_WINDOWS.ps1" -OutFile $p; & powershell -NoProfile -ExecutionPolicy Bypass -File $p' ``` Detailed guide: `docs/EASY_SECOND_COMPUTER_SETUP.md`. diff --git a/docs/EASY_SECOND_COMPUTER_SETUP.md b/docs/EASY_SECOND_COMPUTER_SETUP.md index 331e0371..c7da3370 100644 --- a/docs/EASY_SECOND_COMPUTER_SETUP.md +++ b/docs/EASY_SECOND_COMPUTER_SETUP.md @@ -7,26 +7,41 @@ not public validator software, and not a production bridge. ## Install These First +Nothing manually for the normal Windows path. + +The root installer installs or verifies: + 1. Git for Windows -2. Node.js LTS -3. Rust with Cargo -4. Foundry -5. Python 3 +2. Node.js LTS with npm +3. Python 3 +4. Rust with Cargo +5. Foundry + +Foundry is installed through Git Bash because Foundry's Windows installer does +not support PowerShell directly. -## One-Command Setup +## Beginner Setup Open PowerShell and run: ```powershell -git clone -b release/flowchain-private-testnet https://github.com/FlowmemoryAI/FlowMemory.git -cd FlowMemory -powershell -ExecutionPolicy Bypass -File .\START_FLOWCHAIN_LOCAL.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -Command '$p=Join-Path $env:TEMP "INSTALL_FLOWCHAIN_WINDOWS.ps1"; Invoke-WebRequest "https://raw.githubusercontent.com/FlowmemoryAI/FlowMemory/main/INSTALL_FLOWCHAIN_WINDOWS.ps1" -OutFile $p; & powershell -NoProfile -ExecutionPolicy Bypass -File $p' ``` -The script installs dependencies, checks prerequisites, initializes local state, -runs the deterministic local chain demo, runs the smoke path, exports a local -bundle, runs the bridge mock, and opens the control plane and dashboard in -separate PowerShell windows. +The installer downloads this repo, installs dependencies, checks prerequisites, +initializes local state, runs the deterministic local chain demo, runs the smoke +path, exports a local bundle, runs the bridge mock, and opens the control plane +and dashboard in separate PowerShell windows. + +Windows may ask for permission while tools install. Click **Yes** if prompted. + +## Already Cloned Setup + +If the repo is already cloned: + +```powershell +powershell -ExecutionPolicy Bypass -File .\INSTALL_FLOWCHAIN_WINDOWS.ps1 +``` ## Faster Re-Run diff --git a/docs/FLOWCHAIN_SECOND_COMPUTER_SETUP.md b/docs/FLOWCHAIN_SECOND_COMPUTER_SETUP.md index 630b06b0..4b034adc 100644 --- a/docs/FLOWCHAIN_SECOND_COMPUTER_SETUP.md +++ b/docs/FLOWCHAIN_SECOND_COMPUTER_SETUP.md @@ -14,29 +14,33 @@ FlowChain private/local L1 testnet package for second-computer validation. ## Prerequisites -Install these on the second computer: +For the normal Windows path, do not manually install these first. The root +installer installs or verifies them for the user: - Git for Windows. - Node.js LTS with npm. - Rust toolchain with Cargo. -- Foundry, if running contract hardening or `npm run launch:candidate`. -- Python 3, if validating hardware simulator fixtures. +- Foundry. +- Python 3. + +Foundry is special on Windows. Foundry's installer does not support PowerShell +directly, so `INSTALL_FLOWCHAIN_WINDOWS.ps1` uses Git Bash for that step after +Git is installed. Do not put private keys, RPC credentials, API keys, seed phrases, or webhook URLs in committed files. ## Current Merged Setup Path -For the release integration branch, the easiest setup path is: +The beginner setup path is: ```powershell -git clone -b release/flowchain-private-testnet https://github.com/FlowmemoryAI/FlowMemory.git -cd FlowMemory -powershell -ExecutionPolicy Bypass -File .\START_FLOWCHAIN_LOCAL.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -Command '$p=Join-Path $env:TEMP "INSTALL_FLOWCHAIN_WINDOWS.ps1"; Invoke-WebRequest "https://raw.githubusercontent.com/FlowmemoryAI/FlowMemory/main/INSTALL_FLOWCHAIN_WINDOWS.ps1" -OutFile $p; & powershell -NoProfile -ExecutionPolicy Bypass -File $p' ``` -This wraps the manual commands below and opens the control plane and workbench -in separate PowerShell windows. +This installs missing tools, clones or updates the repo, wraps the manual +commands below, and opens the control plane and workbench in separate +PowerShell windows. Use this path today on a clean second computer. It validates the merged V0 launch-core, no-value local devnet prototype, dashboard workbench, hardware @@ -44,6 +48,17 @@ simulator fixture, and Windows wrapper layer. It does not yet prove the full native AgentAccount, ModelPassport, MemoryCell, Challenge, FinalityReceipt, or control-plane lifecycle. +If the repo is already cloned, run from the repo root: + +```powershell +powershell -ExecutionPolicy Bypass -File .\INSTALL_FLOWCHAIN_WINDOWS.ps1 +``` + +## Manual Developer Path + +Use this only when intentionally installing tools yourself or debugging the +installer. + Clone and install: ```powershell diff --git a/docs/FLOWCHAIN_TROUBLESHOOTING.md b/docs/FLOWCHAIN_TROUBLESHOOTING.md index 561fe1b1..1b256d4b 100644 --- a/docs/FLOWCHAIN_TROUBLESHOOTING.md +++ b/docs/FLOWCHAIN_TROUBLESHOOTING.md @@ -7,6 +7,26 @@ path from `docs/FLOWCHAIN_SECOND_COMPUTER_SETUP.md`. ## First Command +On a clean Windows computer, the first command should be the beginner installer: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -Command '$p=Join-Path $env:TEMP "INSTALL_FLOWCHAIN_WINDOWS.ps1"; Invoke-WebRequest "https://raw.githubusercontent.com/FlowmemoryAI/FlowMemory/main/INSTALL_FLOWCHAIN_WINDOWS.ps1" -OutFile $p; & powershell -NoProfile -ExecutionPolicy Bypass -File $p' +``` + +If the repo is already cloned, run from the repo root: + +```powershell +powershell -ExecutionPolicy Bypass -File .\INSTALL_FLOWCHAIN_WINDOWS.ps1 +``` + +To only check installed tools: + +```powershell +powershell -ExecutionPolicy Bypass -File .\INSTALL_FLOWCHAIN_WINDOWS.ps1 -CheckOnly +``` + +## Repo Command Check + From the repo root: ```powershell @@ -20,10 +40,11 @@ or workbench commands. | Symptom | Likely cause | Fix | | --- | --- | --- | +| `winget is missing` | Windows App Installer is missing or outdated. | Install or update **App Installer** from the Microsoft Store, then rerun `INSTALL_FLOWCHAIN_WINDOWS.ps1`. | | `git was not found on PATH` | Git for Windows is missing or PowerShell was opened before install. | Install Git for Windows, reopen PowerShell, rerun `npm run flowchain:prereq`. | | `node` or `npm` missing | Node.js LTS is missing or PATH is stale. | Install Node.js LTS, reopen PowerShell, run `npm install`. | | `cargo` or `rustc` missing | Rust toolchain is missing. | Install Rust with rustup, reopen PowerShell, run `cargo test --manifest-path crates/flowmemory-devnet/Cargo.toml`. | -| `forge is required` | Foundry is missing. | Install Foundry before `npm run launch:candidate` or `npm run flowchain:smoke`. | +| `forge is required` | Foundry is missing. | Run `powershell -ExecutionPolicy Bypass -File .\INSTALL_FLOWCHAIN_WINDOWS.ps1`; the installer uses Git Bash for Foundry. | | Dashboard dependency error | Dashboard deps are separate from root npm workspaces. | Run `npm install --prefix apps/dashboard`. | | Crypto dependency error during strict prereq | Crypto deps are separate from root npm workspaces. | Run `npm install --prefix crypto`. | | Workbench does not open | Vite dev server did not start or the port changed. | Run `npm run workbench:dev` again and use the URL printed by Vite. |