Files
bootstrap/bin/mosaic.ps1
Jason Woltje 56b644e6d3 feat: add mosaic upgrade command to clean stale per-project files
Detects and cleans up files that are now centralized:
- SOUL.md: removed (now global at ~/.config/mosaic/SOUL.md)
- CLAUDE.md: replaced with thin pointer to global AGENTS.md
- AGENTS.md: stale load-order sections stripped, project content preserved

Supports --dry-run, --all (scan ~/src/*), and per-project paths.
Creates .mosaic-bak backups before any modification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 13:33:10 -06:00

157 lines
5.4 KiB
PowerShell

# mosaic.ps1 — Unified agent launcher and management CLI (Windows)
#
# AGENTS.md is the single source of truth for all agent sessions.
# The launcher injects it into every runtime consistently.
#
# Usage:
# mosaic claude [args...] Launch Claude Code with AGENTS.md injected
# mosaic opencode [args...] Launch OpenCode with AGENTS.md injected
# mosaic codex [args...] Launch Codex with AGENTS.md injected
# mosaic init [args...] Generate SOUL.md interactively
# mosaic doctor [args...] Health audit
# mosaic sync [args...] Sync skills
$ErrorActionPreference = "Stop"
$MosaicHome = if ($env:MOSAIC_HOME) { $env:MOSAIC_HOME } else { Join-Path $env:USERPROFILE ".config\mosaic" }
$Version = "0.1.0"
function Show-Usage {
Write-Host @"
mosaic $Version - Unified agent launcher
Usage: mosaic <command> [args...]
Agent Launchers:
claude [args...] Launch Claude Code with AGENTS.md injected
opencode [args...] Launch OpenCode with AGENTS.md injected
codex [args...] Launch Codex with AGENTS.md injected
Management:
init [args...] Generate SOUL.md (agent identity contract)
doctor [args...] Audit runtime state and detect drift
sync [args...] Sync skills from canonical source
bootstrap <path> Bootstrap a repo with Mosaic standards
upgrade [path] Clean up stale SOUL.md/CLAUDE.md in a project
Options:
-h, --help Show this help
-v, --version Show version
"@
}
function Assert-MosaicHome {
if (-not (Test-Path $MosaicHome)) {
Write-Host "[mosaic] ERROR: ~/.config/mosaic not found." -ForegroundColor Red
Write-Host "[mosaic] Install with: irm https://git.mosaicstack.dev/mosaic/bootstrap/raw/branch/main/remote-install.ps1 | iex"
exit 1
}
}
function Assert-AgentsMd {
$agentsPath = Join-Path $MosaicHome "AGENTS.md"
if (-not (Test-Path $agentsPath)) {
Write-Host "[mosaic] ERROR: ~/.config/mosaic/AGENTS.md not found." -ForegroundColor Red
Write-Host "[mosaic] Re-run the installer."
exit 1
}
}
function Assert-Soul {
$soulPath = Join-Path $MosaicHome "SOUL.md"
if (-not (Test-Path $soulPath)) {
Write-Host "[mosaic] SOUL.md not found. Running mosaic init..."
& (Join-Path $MosaicHome "bin\mosaic-init.ps1")
}
}
function Assert-Runtime {
param([string]$Cmd)
if (-not (Get-Command $Cmd -ErrorAction SilentlyContinue)) {
Write-Host "[mosaic] ERROR: '$Cmd' not found in PATH." -ForegroundColor Red
Write-Host "[mosaic] Install $Cmd before launching."
exit 1
}
}
function Ensure-RuntimeConfig {
param([string]$Dst)
$src = Join-Path $MosaicHome "AGENTS.md"
$parent = Split-Path $Dst -Parent
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent -Force | Out-Null }
$srcHash = (Get-FileHash $src -Algorithm SHA256).Hash
$dstHash = if (Test-Path $Dst) { (Get-FileHash $Dst -Algorithm SHA256).Hash } else { "" }
if ($srcHash -ne $dstHash) {
Copy-Item $src $Dst -Force
}
}
if ($args.Count -eq 0) {
Show-Usage
exit 0
}
$command = $args[0]
$remaining = if ($args.Count -gt 1) { $args[1..($args.Count - 1)] } else { @() }
switch ($command) {
"claude" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "claude"
# Claude supports --append-system-prompt for direct injection
$agentsContent = Get-Content (Join-Path $MosaicHome "AGENTS.md") -Raw
Write-Host "[mosaic] Launching Claude Code..."
& claude --append-system-prompt $agentsContent @remaining
}
"opencode" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "opencode"
# OpenCode reads from ~/.config/opencode/AGENTS.md
Ensure-RuntimeConfig (Join-Path $env:USERPROFILE ".config\opencode\AGENTS.md")
Write-Host "[mosaic] Launching OpenCode..."
& opencode @remaining
}
"codex" {
Assert-MosaicHome
Assert-AgentsMd
Assert-Soul
Assert-Runtime "codex"
# Codex reads from ~/.codex/instructions.md
Ensure-RuntimeConfig (Join-Path $env:USERPROFILE ".codex\instructions.md")
Write-Host "[mosaic] Launching Codex..."
& codex @remaining
}
"init" {
Assert-MosaicHome
& (Join-Path $MosaicHome "bin\mosaic-init.ps1") @remaining
}
"doctor" {
Assert-MosaicHome
& (Join-Path $MosaicHome "bin\mosaic-doctor.ps1") @remaining
}
"sync" {
Assert-MosaicHome
& (Join-Path $MosaicHome "bin\mosaic-sync-skills.ps1") @remaining
}
"bootstrap" {
Assert-MosaicHome
Write-Host "[mosaic] NOTE: mosaic-bootstrap-repo requires bash. Use Git Bash or WSL." -ForegroundColor Yellow
& (Join-Path $MosaicHome "bin\mosaic-bootstrap-repo") @remaining
}
"upgrade" {
Assert-MosaicHome
Write-Host "[mosaic] NOTE: mosaic-upgrade requires bash. Use Git Bash or WSL." -ForegroundColor Yellow
& (Join-Path $MosaicHome "bin\mosaic-upgrade") @remaining
}
{ $_ -in "help", "-h", "--help" } { Show-Usage }
{ $_ -in "version", "-v", "--version" } { Write-Host "mosaic $Version" }
default {
Write-Host "[mosaic] Unknown command: $command" -ForegroundColor Red
Write-Host "[mosaic] Run 'mosaic --help' for usage."
exit 1
}
}