# Duckweed 一键安装脚本 (Windows PowerShell) # 用法: irm https://www.duckweed.ai/install.ps1 | iex # 或: powershell -ExecutionPolicy ByPass -c "irm https://www.duckweed.ai/install.ps1 | iex" $ErrorActionPreference = "Stop" $Version = "0.1.0" $DuckweedHome = if ($env:DUCKWEED_HOME) { $env:DUCKWEED_HOME } else { "$env:USERPROFILE\.duckweed" } $DuckweedRepo = "https://www.duckweed.ai/releases/duckweed-latest.tar.gz" function Write-Info { param($msg) Write-Host "[Duckweed] $msg" -ForegroundColor Cyan } function Write-Ok { param($msg) Write-Host "[Duckweed] $msg" -ForegroundColor Green } function Write-Warn { param($msg) Write-Host "[Duckweed] $msg" -ForegroundColor Yellow } function Write-Err { param($msg) Write-Host "[Duckweed] $msg" -ForegroundColor Red } # ── 步骤 1: 安装 uv ── function Install-Uv { $uvPath = Get-Command uv -ErrorAction SilentlyContinue if ($uvPath) { Write-Ok "uv 已安装: $($uvPath.Source)" return } Write-Info "正在安装 uv (Python 包管理器)..." powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # 刷新 PATH $uvBin = "$env:USERPROFILE\.local\bin" $cargoBin = "$env:USERPROFILE\.cargo\bin" foreach ($p in @($uvBin, $cargoBin)) { if (Test-Path $p) { $env:PATH = "$p;$env:PATH" } } $uvCheck = Get-Command uv -ErrorAction SilentlyContinue if ($uvCheck) { Write-Ok "uv 安装成功" } else { Write-Err "uv 安装失败,请手动安装: https://docs.astral.sh/uv/" exit 1 } } # ── 步骤 2: 下载 Duckweed ── function Download-Duckweed { if ((Test-Path "$DuckweedHome\pyproject.toml")) { Write-Warn "已存在安装: $DuckweedHome" Write-Info "正在更新..." if (Test-Path "$DuckweedHome\.git") { Push-Location $DuckweedHome git pull --ff-only 2>$null Pop-Location return } } Write-Info "正在下载 Duckweed v$Version..." New-Item -ItemType Directory -Force -Path $DuckweedHome | Out-Null $tmpFile = [System.IO.Path]::GetTempFileName() + ".tar.gz" try { Invoke-WebRequest -Uri $DuckweedRepo -OutFile $tmpFile -UseBasicParsing # 解压 — 优先用 tar(Windows 10+ 内置) Write-Info "正在解压..." tar xzf $tmpFile -C $DuckweedHome --strip-components=1 2>$null if ($LASTEXITCODE -ne 0) { # 如果 tar 失败,尝试不带 --strip-components tar xzf $tmpFile -C $DuckweedHome 2>$null } } finally { Remove-Item $tmpFile -Force -ErrorAction SilentlyContinue } Write-Ok "下载完成: $DuckweedHome" } # ── 步骤 3: 安装 Python 依赖 ── function Install-Deps { Write-Info "正在安装 Python 依赖..." Push-Location $DuckweedHome # 创建 venv(uv 自动下载 Python 3.10) Write-Info "创建虚拟环境..." uv venv --python 3.10 .venv 2>&1 | Select-Object -Last 3 # 安装依赖 Write-Info "安装依赖包..." $venvPython = ".venv\Scripts\python.exe" uv pip install --python $venvPython -e . 2>&1 | Select-Object -Last 5 Pop-Location Write-Ok "Python 依赖安装完成" } # ── 步骤 4: 初始化数据目录 ── function Initialize-Data { Write-Info "正在初始化数据目录..." Push-Location $DuckweedHome $venvPython = ".venv\Scripts\python.exe" & $venvPython -m scripts.cli init 2>$null if ($LASTEXITCODE -ne 0) { # 手动创建 foreach ($d in @("data\identity", "data\graph\nodes", "data\raw_logs", "data\projects", "data\vault", "data\kubeconfig")) { New-Item -ItemType Directory -Force -Path $d | Out-Null } } Pop-Location Write-Ok "数据目录已初始化" } # ── 步骤 5: 创建全局命令 ── function Create-Wrapper { $binDir = "$env:USERPROFILE\.local\bin" New-Item -ItemType Directory -Force -Path $binDir | Out-Null # 创建 .cmd wrapper(可直接在 CMD 和 PowerShell 中运行) $wrapperCmd = @" @echo off set "DUCKWEED_HOME=%USERPROFILE%\.duckweed" if defined DUCKWEED_HOME_OVERRIDE set "DUCKWEED_HOME=%DUCKWEED_HOME_OVERRIDE%" cd /d "%DUCKWEED_HOME%" "%DUCKWEED_HOME%\.venv\Scripts\python.exe" -m scripts.cli %* "@ Set-Content -Path "$binDir\duckweed.cmd" -Value $wrapperCmd -Encoding ASCII # 创建 .ps1 wrapper $wrapperPs1 = @' $DH = if ($env:DUCKWEED_HOME) { $env:DUCKWEED_HOME } else { "$env:USERPROFILE\.duckweed" } Push-Location $DH & "$DH\.venv\Scripts\python.exe" -m scripts.cli @args Pop-Location '@ Set-Content -Path "$binDir\duckweed.ps1" -Value $wrapperPs1 -Encoding UTF8 Write-Ok "命令已创建: $binDir\duckweed.cmd" # 检查 PATH if ($env:PATH -notlike "*$binDir*") { Write-Warn "$binDir 不在 PATH 中" Write-Warn "正在添加到用户 PATH..." $userPath = [Environment]::GetEnvironmentVariable("PATH", "User") if ($userPath -notlike "*$binDir*") { [Environment]::SetEnvironmentVariable("PATH", "$binDir;$userPath", "User") $env:PATH = "$binDir;$env:PATH" Write-Ok "已添加到用户 PATH(新终端生效)" } } } # ── 步骤 6: 创建桌面快捷方式 (Windows) ── function Create-DesktopShortcut { $desktopPath = [Environment]::GetFolderPath("Desktop") if (-not $desktopPath) { return } $shortcutPath = "$desktopPath\Duckweed.lnk" # 查找 logo $iconPath = "$DuckweedHome\app\public\logo.ico" if (-not (Test-Path $iconPath)) { $iconPath = "" } try { $shell = New-Object -ComObject WScript.Shell $shortcut = $shell.CreateShortcut($shortcutPath) $shortcut.TargetPath = "$DuckweedHome\.venv\Scripts\pythonw.exe" $shortcut.Arguments = "-m scripts.cli" $shortcut.WorkingDirectory = $DuckweedHome $shortcut.Description = "Duckweed 认知记忆开发系统" if ($iconPath -and (Test-Path $iconPath)) { $shortcut.IconLocation = $iconPath } $shortcut.Save() Write-Ok "桌面快捷方式已创建: $shortcutPath" } catch { Write-Warn "桌面快捷方式创建失败: $_" } } # ── 主流程 ── function Main { Write-Host "" Write-Host "======================================" -ForegroundColor Cyan Write-Host " Duckweed 认知记忆开发系统" -ForegroundColor Cyan Write-Host " 一键安装 v$Version" -ForegroundColor Cyan Write-Host "======================================" -ForegroundColor Cyan Write-Host "" Install-Uv Download-Duckweed Install-Deps Initialize-Data Create-Wrapper Create-DesktopShortcut Write-Host "" Write-Host "======================================" -ForegroundColor Green Write-Host " 安装完成!" -ForegroundColor Green Write-Host "======================================" -ForegroundColor Green Write-Host "" Write-Host " 常用命令:" Write-Host " duckweed 启动服务 + 打开浏览器" Write-Host " duckweed status 查看状态" Write-Host " duckweed doctor 检查环境" Write-Host " duckweed update 更新版本" Write-Host " duckweed uninstall 卸载" Write-Host "" Write-Host " 安装目录: $DuckweedHome" Write-Host "" # 自动启动服务 Write-Info "正在启动 Duckweed..." & "$DuckweedHome\.venv\Scripts\python.exe" -m scripts.cli } Main