155 lines
5.1 KiB
PowerShell
155 lines
5.1 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Downloads the AI workspace ZIP from Ka-Note and extracts it to work/.
|
|
|
|
.PARAMETER Prod
|
|
Target production server instead of dev (localhost:3001).
|
|
|
|
.PARAMETER Token
|
|
Bearer token for prod auth. Falls back to $env:KA_NOTE_TOKEN.
|
|
|
|
.PARAMETER Force
|
|
Skip the work-directory cleanup confirmation prompt.
|
|
|
|
.EXAMPLE
|
|
.\download.ps1
|
|
.\download.ps1 -Prod -Token eyJ...
|
|
.\download.ps1 -Force
|
|
#>
|
|
param(
|
|
[switch]$Prod,
|
|
[string]$Token,
|
|
[switch]$Force
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# --- Helpers -----------------------------------------------------------------
|
|
|
|
function Write-Header([string]$Text) {
|
|
Write-Host ""
|
|
Write-Host " $Text" -ForegroundColor White
|
|
Write-Host (" " + ("-" * $Text.Length)) -ForegroundColor DarkGray
|
|
}
|
|
|
|
function Write-KV([string]$Key, [string]$Value, [string]$Color = "Gray") {
|
|
Write-Host (" {0,-14} " -f $Key) -NoNewline -ForegroundColor DarkGray
|
|
Write-Host $Value -ForegroundColor $Color
|
|
}
|
|
|
|
function Write-Ok([string]$Msg) { Write-Host " [OK] $Msg" -ForegroundColor Green }
|
|
function Write-Err([string]$Msg) { Write-Host " [!!] $Msg" -ForegroundColor Red }
|
|
function Write-Hint([string]$Msg) { Write-Host " -> $Msg" -ForegroundColor DarkCyan }
|
|
|
|
# --- Paths -------------------------------------------------------------------
|
|
|
|
$RepoRoot = Resolve-Path "$PSScriptRoot\..\.."
|
|
$WorkDir = Join-Path $RepoRoot "work"
|
|
$ZipPath = Join-Path $WorkDir "workspace.zip"
|
|
|
|
# --- Clean work directory ----------------------------------------------------
|
|
|
|
Write-Header "Ka-Note AI Download"
|
|
|
|
if (Test-Path $WorkDir) {
|
|
$ExistingItems = @(Get-ChildItem -Path $WorkDir)
|
|
if ($ExistingItems.Count -gt 0) {
|
|
Write-KV "work dir" $WorkDir
|
|
Write-Host ""
|
|
Write-Host " The work directory contains $($ExistingItems.Count) item(s)." -ForegroundColor DarkGray
|
|
Write-Host ""
|
|
|
|
if (-not $Force) {
|
|
$Answer = Read-Host " Delete all contents and proceed? [y/N]"
|
|
if ($Answer -notmatch '^[yY]$') {
|
|
Write-Host " Aborted." -ForegroundColor Yellow
|
|
Write-Host ""
|
|
exit 0
|
|
}
|
|
}
|
|
|
|
Remove-Item -Path "$WorkDir\*" -Recurse -Force
|
|
Write-Ok "Work directory cleared."
|
|
}
|
|
} else {
|
|
New-Item -ItemType Directory -Path $WorkDir | Out-Null
|
|
Write-Ok "Created work directory: $WorkDir"
|
|
}
|
|
|
|
# --- Server ------------------------------------------------------------------
|
|
|
|
if ($Prod) {
|
|
$BaseUrl = "https://ka-note.azurewebsites.net"
|
|
$BearerToken = if ($Token) { $Token } elseif ($env:KA_NOTE_TOKEN) { $env:KA_NOTE_TOKEN } else {
|
|
Write-Host " Acquiring token via MSAL..." -ForegroundColor DarkGray
|
|
& "$PSScriptRoot\get-token.ps1"
|
|
}
|
|
if (-not $BearerToken) {
|
|
Write-Err "Failed to acquire a Bearer token."
|
|
exit 1
|
|
}
|
|
$Headers = @{ Authorization = "Bearer $BearerToken" }
|
|
$Env = "prod"
|
|
} else {
|
|
$BaseUrl = "http://localhost:3001"
|
|
$Headers = @{}
|
|
$Env = "dev"
|
|
}
|
|
|
|
Write-KV "server" $BaseUrl $(if ($Prod) { "Yellow" } else { "Cyan" })
|
|
Write-KV "mode" $Env
|
|
Write-KV "work" $WorkDir
|
|
Write-Host ""
|
|
Write-Host " Downloading workspace.zip..." -ForegroundColor DarkGray
|
|
|
|
# --- Download ----------------------------------------------------------------
|
|
|
|
try {
|
|
Invoke-WebRequest -Uri "$BaseUrl/api/ai/download" `
|
|
-Method GET -Headers $Headers -OutFile $ZipPath -UseBasicParsing
|
|
} catch {
|
|
$Code = $_.Exception.Response.StatusCode.value__
|
|
Write-Err "HTTP $Code - $($_.Exception.Message)"
|
|
exit 1
|
|
}
|
|
|
|
$LockToken = $null
|
|
# Lock token also in ZIP manifest (read after extract)
|
|
|
|
# --- Extract -----------------------------------------------------------------
|
|
|
|
Write-Host " Extracting..." -ForegroundColor DarkGray
|
|
Expand-Archive -Path $ZipPath -DestinationPath $WorkDir -Force
|
|
Remove-Item -Path $ZipPath -Force
|
|
|
|
# --- Stats -------------------------------------------------------------------
|
|
|
|
$ManifestPath = Join-Path $WorkDir "manifest.json"
|
|
$Manifest = Get-Content $ManifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$LockToken = $Manifest.lockToken
|
|
|
|
$HistoryCount = @(Get-ChildItem -Path (Join-Path $WorkDir "history") -Filter "*.md" -ErrorAction SilentlyContinue).Count
|
|
$ImageCount = @(Get-ChildItem -Path (Join-Path $WorkDir "images") -ErrorAction SilentlyContinue).Count
|
|
|
|
$CtxJson = Get-Content (Join-Path $WorkDir "contexts.json") -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$TopJson = Get-Content (Join-Path $WorkDir "topics.json") -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$RatJson = Get-Content (Join-Path $WorkDir "ratings.json") -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
|
|
Write-Header "Result"
|
|
Write-KV "contexts" @($CtxJson).Count
|
|
Write-KV "topics" @($TopJson).Count
|
|
Write-KV "history" $HistoryCount
|
|
Write-KV "ratings" @($RatJson).Count
|
|
Write-KV "images" $ImageCount
|
|
Write-KV "lock" $LockToken "Yellow"
|
|
Write-KV "expires" $Manifest.expiresAt
|
|
|
|
Write-Host ""
|
|
Write-Ok "Workspace extracted to work/. Lock acquired - sync is paused."
|
|
Write-Host ""
|
|
Write-Host " Next steps:" -ForegroundColor DarkGray
|
|
Write-Hint "Edit work/history/*.md with your AI tool"
|
|
Write-Hint ".\upload.ps1$(if ($Prod) { ' -Prod' }) - upload changes + release lock"
|
|
Write-Hint ".\unlock.ps1$(if ($Prod) { ' -Prod' }) - discard changes, release lock only"
|
|
Write-Host ""
|