Files
factory/bootstrap.ps1
vitya dcf4077e82 feat(skills): bundle minimum skill set from claude-skills into factory/skills/
Copies 8 standalone skills (active-platform, caveman, project-discipline,
pulling-before-work, setup-tasks, setup-wiki, using-tasks, using-wiki) from
~/projects/claude-skills/skills/ and all 14 superpowers sub-skills from the
installed plugin cache into factory/skills/superpowers/.

Adds skills install step to bootstrap.ps1: copies all factory/skills/
directories to ~/.claude/skills/ so users get the skill set automatically
without manual plugin install for the baseline set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 13:24:55 +03:00

268 lines
8.9 KiB
PowerShell

#!/usr/bin/env pwsh
# L0b Factory Bootstrap — Windows
# Auto-generated from install-log.md field-test 2026-05-06
$ErrorActionPreference = "Stop"
$PSVersionTable.PSVersion.Major -ge 7 -or (Write-Error "Bootstrap requires PowerShell 7+. Install: winget install Microsoft.PowerShell"; exit 1)
$GITEA_DEFAULT = "https://git.kzntsv.site"
$ORG_DEFAULT = "OpeItcLoc03"
$FACTORY_REPO_DEFAULT = "factory"
$HOME_TOML = "$env:USERPROFILE\.config\factory\home.toml"
$PROJECTS_DIR_DEFAULT = "C:\Users\$env:USERNAME\projects"
function Test-Command {
param([string]$Name)
$null = Get-Command $Name -ErrorAction SilentlyContinue
}
function Write-Step {
param([string]$Msg)
Write-Host "`n$Msg" -ForegroundColor Cyan
}
function Write-Ok {
param([string]$Msg)
Write-Host "$Msg" -ForegroundColor Green
}
function Write-Skip {
param([string]$Msg)
Write-Host "$Msg" -ForegroundColor Yellow
}
function Write-Gap {
param([string]$Msg)
Write-Host "$Msg" -ForegroundColor Red
}
# Pre-checks
Write-Step "L0b Pre-checks"
$missed = @()
if (-not (Test-Command git)) { $missed += "git (install: winget install Git.Git)" }
if (-not (Test-Command curl)) { $missed += "curl (install: winget install curl.curl)" }
if (-not (Test-Command mise)) { $missed += "mise (install: winget install jdx.mise)" }
if (-not (Test-Command claude)) { $missed += "claude (install: irm https://claude.ai/install.ps1 | iex)" }
if ($missed) {
Write-Gap "Missing dependencies:"
$missed | ForEach-Object { Write-Host " - $_" }
Write-Host "`nInstall missing tools and re-run bootstrap."
exit 1
}
Write-Ok "Pre-checks passed"
# Check if already bootstrapped
if (Test-Path $HOME_TOML) {
Write-Skip "Already bootstrapped. Re-run mode: verify only."
$toml = Get-Content $HOME_TOML -Raw
if ($toml -match 'projects_dir\s*=\s*''([^'']+)''') {
$existing_dir = $matches[1]
Write-Host " projects_dir: $existing_dir"
if (Test-Path "$existing_dir\.factory") {
Write-Ok ".factory exists"
} else {
Write-Gap ".factory missing at $existing_dir\.factory"
exit 1
}
}
Write-Ok "Bootstrap verified. Exiting (no-op)."
exit 0
}
# Interactive: ask for configuration
Write-Step "Configuration"
$gitea = Read-Host "Gitea URL [$GITEA_DEFAULT]"
$gitea = if ($gitea) { $gitea } else { $GITEA_DEFAULT }
$org = Read-Host "Gitea org/user [$ORG_DEFAULT]"
$org = if ($org) { $org } else { $ORG_DEFAULT }
$factoryRepo = Read-Host "Factory repo name [$FACTORY_REPO_DEFAULT]"
$factoryRepo = if ($factoryRepo) { $factoryRepo } else { $FACTORY_REPO_DEFAULT }
$projectsDir = Read-Host "Projects directory [$PROJECTS_DIR_DEFAULT]"
$projectsDir = if ($projectsDir) { $projectsDir } else { $PROJECTS_DIR_DEFAULT }
$client = Read-Host "AI client [claude-code/copilot-cli/gemini-cli] (default: claude-code)"
$client = if ($client) { $client } else { "claude-code" }
# Validate projects_dir
if (-not (Test-Path $projectsDir)) {
$create = Read-Host "Directory '$projectsDir' does not exist. Create? [Y/n]"
if ($create -ne "n") {
New-Item -ItemType Directory -Force -Path $projectsDir | Out-Null
Write-Ok "Created $projectsDir"
} else {
Write-Gap "Cannot continue without projects_dir"
exit 1
}
}
# Clone .factory
Write-Step "Cloning .factory repo"
$factoryLocal = "$projectsDir\.factory"
$factoryUrl = "$gitea/$org/$factoryRepo.git"
if (Test-Path $factoryLocal) {
Write-Skip ".factory already exists, skipping clone"
# Verify it's a git repo
if (-not (Test-Path "$factoryLocal\.git")) {
Write-Gap "$factoryLocal exists but is not a git repo. Remove it and re-run."
exit 1
}
} else {
Write-Host "Cloning from: $factoryUrl"
# Check if we have credentials for gitea
$needAuth = $false
try {
$null = git ls-remote "$factoryUrl" 2>&1
} catch {
$needAuth = $true
}
if ($needAuth) {
Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
Write-Host " PAT REQUIRED" -ForegroundColor Yellow
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
Write-Host "`n1. Open in browser: $gitea/user/settings/applications"
Write-Host "2. Generate PAT with scopes: read:repository, write:repository, read:user"
Write-Host "3. Press Enter when ready...`n"
Read-Host
Write-Host "Cloning with Git Credential Manager prompt..."
}
git clone "$factoryUrl" "$factoryLocal"
if (-not $?) {
Write-Gap "Clone failed. Check URL and credentials."
exit 1
}
Write-Ok "Cloned to $factoryLocal"
}
# Write home.toml
Write-Step "Writing ~/.config/factory/home.toml"
$configDir = "$env:USERPROFILE\.config\factory"
New-Item -ItemType Directory -Force -Path $configDir | Out-Null
$installedAt = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
$lines = @(
"# factory home — single source of machine-level state",
"# auto-generated by L0b bootstrap; safe to edit by hand",
"",
"projects_dir = '$projectsDir'",
"client = '$client'",
"installed_at = '$installedAt'"
)
[System.IO.File]::WriteAllLines(
"$configDir\home.toml",
$lines,
[System.Text.UTF8Encoding]::new($false)
)
Write-Ok "Wrote $HOME_TOML"
# Build MCP servers from lib/
Write-Step "Building MCP servers"
$libPath = "$factoryLocal\lib"
if (Test-Path $libPath) {
# TypeScript servers (npm install + npm run build)
foreach ($server in @("projects-meta-mcp", "wiki-graph")) {
$serverPath = "$libPath\$server"
if (Test-Path $serverPath) {
Write-Host " Building $server..."
Push-Location $serverPath
try {
npm install --silent 2>&1 | Out-Null
npm run build 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Gap "$server: build failed (npm run build exited $LASTEXITCODE)"
} else {
Write-Ok "$server built"
}
} finally {
Pop-Location
}
}
}
# Python server (interns-mcp) — venv + pip install
$internsMcpPath = "$libPath\interns-mcp"
if (Test-Path $internsMcpPath) {
Write-Host " Setting up interns-mcp..."
Push-Location $internsMcpPath
try {
python -m venv .venv 2>&1 | Out-Null
& ".venv\Scripts\pip.exe" install -e . --quiet
if ($LASTEXITCODE -ne 0) {
Write-Gap "interns-mcp: pip install failed"
} else {
Write-Ok "interns-mcp installed"
}
} finally {
Pop-Location
}
}
} else {
Write-Skip "lib/ not found — skipping MCP server build"
}
# Install skills to ~/.claude/skills/
Write-Step "Installing skills to ~/.claude/skills/"
$skillsPath = "$factoryLocal\skills"
$claudeSkillsPath = "$env:USERPROFILE\.claude\skills"
if (Test-Path $skillsPath) {
New-Item -ItemType Directory -Force -Path $claudeSkillsPath | Out-Null
Get-ChildItem $skillsPath -Directory | ForEach-Object {
Copy-Item $_.FullName "$claudeSkillsPath\$($_.Name)" -Recurse -Force
}
$count = (Get-ChildItem $skillsPath -Directory).Count
Write-Ok "Installed $count skill directories to $claudeSkillsPath"
} else {
Write-Skip "skills/ not found in factory — skipping skill install"
}
# Print next steps
Write-Host "`n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host " L0b COMPLETE" -ForegroundColor Green
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Green
Write-Host "`nFactory bootstrapped. Next steps (manual):`n"
Write-Host "1. Start Claude Code:" -ForegroundColor Cyan
Write-Host " cd $factoryLocal"
Write-Host " claude`n"
Write-Host "2. In Claude, run:" -ForegroundColor Cyan
Write-Host " /login"
Write-Host " /plugin install superpowers@claude-plugins-official"
Write-Host " /plugin install context7@claude-plugins-official"
Write-Host " /reload-plugins"
Write-Host " /exit`n"
Write-Host "3. Run setup skills:" -ForegroundColor Cyan
Write-Host " cd $projectsDir"
Write-Host " claude"
Write-Host " /setup-projects-meta"
Write-Host " /setup-interns"
Write-Host " /setup-tasks"
Write-Host " /setup-wiki`n"
Write-Host "See .wiki/concepts/factory-bootstrap.md for full design."
Write-Host "`nRe-run this script anytime — it's idempotent."