Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ A social simulation scenario engine. Feed it documents describing any scenario,

### Setup

One-command bootstrap (installs uv if missing, creates `.env`, syncs
dependencies, checks your LLM provider CLI and runs `mirofish doctor`):

```bash
# macOS / Linux
./scripts/setup.sh # or: --provider codex-cli, --yes

# Windows (PowerShell)
.\scripts\setup.ps1 # or: -Provider codex-cli, -Yes
# If script execution is disabled (stock Windows default):
powershell -ExecutionPolicy Bypass -File scripts\setup.ps1
```

Or manually:

```bash
cp .env.example .env
# Default: claude-cli (uses your Claude Code subscription)
Expand Down
116 changes: 116 additions & 0 deletions scripts/setup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# One-command bootstrap for MiroFish on Windows (PowerShell 5.1+).
#
# Usage:
# .\scripts\setup.ps1 # sensible defaults
# .\scripts\setup.ps1 -Provider codex-cli # pick LLM provider (default: claude-cli)
# .\scripts\setup.ps1 -Yes # non-interactive (auto-install uv)
#
# If script execution is disabled on your machine (stock Windows defaults to
# an ExecutionPolicy of Restricted), run it as:
# powershell -ExecutionPolicy Bypass -File scripts\setup.ps1
#
# What it does:
# 1. Verifies (or installs) uv
# 2. Creates .env from .env.example and sets LLM_PROVIDER
# 3. Installs dependencies with `uv sync`
# 4. Verifies the provider CLI is available and hints at login if needed
# 5. Runs `mirofish doctor` for a final health check
#
# Note: full Windows runtime support for the claude-cli provider also needs
# the fixes in PR #26 (POSIX cwd, argv length limit, cp1252 decoding).

param(
[ValidateSet("claude-cli", "codex-cli")]
[string]$Provider = "claude-cli",
[switch]$Yes
)

$ErrorActionPreference = "Stop"
$RepoDir = Split-Path -Parent $PSScriptRoot
Set-Location $RepoDir

function Say($msg) { Write-Host "==> $msg" -ForegroundColor Cyan }
function Warn($msg) { Write-Host "WARN $msg" -ForegroundColor Yellow }

# --- 1. uv ------------------------------------------------------------------
if (Get-Command uv -ErrorAction SilentlyContinue) {
Say "uv found: $(uv --version)"
} else {
if (-not $Yes) {
if ([Console]::IsInputRedirected) {
Write-Host "uv is not installed and stdin is not interactive; re-run with -Yes to auto-install."
exit 1
}
$ans = Read-Host "uv is not installed. Install it now from https://astral.sh/uv? [y/N]"
if ($ans -notmatch '^(y|yes)$') { Write-Host "Aborted: uv is required."; exit 1 }
}
Say "Installing uv..."
# Download to a file first: avoids executing a partial stream and iex
# scope pollution (vs irm | iex)
$uvInstaller = Join-Path $env:TEMP "uv-install-$PID.ps1"
Invoke-RestMethod https://astral.sh/uv/install.ps1 -OutFile $uvInstaller
& $uvInstaller
Remove-Item $uvInstaller -ErrorAction SilentlyContinue
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
Write-Host "uv installed but not on PATH; open a new terminal and re-run."
exit 1
}
}

# --- 2. .env ----------------------------------------------------------------
if (-not (Test-Path ".env")) {
Copy-Item ".env.example" ".env"
Say "Created .env from .env.example"
}
# Symmetric UTF-8 read (Get-Content on PS 5.1 decodes BOM-less files as ANSI,
# which would corrupt non-ASCII values on the read-modify-write cycle)
$envText = [IO.File]::ReadAllText((Join-Path $RepoDir ".env"), (New-Object System.Text.UTF8Encoding($false)))
if ($envText -match "(?m)^LLM_PROVIDER=") {
$envText = $envText -replace "(?m)^LLM_PROVIDER=.*$", "LLM_PROVIDER=$Provider"
} else {
$envText = $envText.TrimEnd() + "`nLLM_PROVIDER=$Provider`n"
}
[IO.File]::WriteAllText((Join-Path $RepoDir ".env"), $envText, (New-Object System.Text.UTF8Encoding($false)))
Say "LLM_PROVIDER=$Provider"

# --- 3. UTF-8 (Windows defaults to a legacy code page like cp1252) ----------
$env:PYTHONUTF8 = "1"
$env:PYTHONIOENCODING = "utf-8"
Say "PYTHONUTF8=1 set for this session (add it to your user environment variables for permanence)"

# --- 4. dependencies --------------------------------------------------------
Say "Installing dependencies (uv sync)..."
uv sync
if ($LASTEXITCODE -ne 0) {
Write-Host "uv sync failed."
Warn "On Windows with Python 3.12 this is typically rapidfuzz >=3.14 shipping no cp312 wheels (fix proposed in PR #26)."
Warn "Workaround until that lands: 'uv python pin 3.11' and re-run this script."
exit 1
}

# --- 5. provider CLI --------------------------------------------------------
if ($Provider -eq "claude-cli") {
if (Get-Command claude -ErrorAction SilentlyContinue) {
$claudeVer = ""
try { $claudeVer = (claude --version 2>$null | Select-Object -First 1) } catch {}
if ($claudeVer) { Say "claude CLI found: $claudeVer" } else { Say "claude CLI found." }
Warn "If you have never logged in, run 'claude' once and use /login (headless '-p' calls fail otherwise)."
} else {
Warn "claude CLI not found on PATH. Install Claude Code (https://claude.com/claude-code) and log in before running simulations."
}
} else {
if (Get-Command codex -ErrorAction SilentlyContinue) {
Say "codex CLI found."
} else {
Warn "codex CLI not found on PATH. Install and authenticate it before running simulations."
}
}

# --- 6. health check --------------------------------------------------------
Say "Running mirofish doctor..."
uv run mirofish doctor
if ($LASTEXITCODE -ne 0) { Warn "doctor reported issues (see above) - fix them before your first run." }

Say "Done. Try:"
Write-Host ' uv run mirofish run --files <your-docs> --requirement "Predict public reaction over 30 days" --platform parallel --max-rounds 15'
127 changes: 127 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env bash
# One-command bootstrap for MiroFish on macOS / Linux.
#
# Usage:
# ./scripts/setup.sh # interactive-ish, sensible defaults
# ./scripts/setup.sh --provider codex-cli # pick LLM provider (default: claude-cli)
# ./scripts/setup.sh --yes # non-interactive (auto-install uv)
#
# What it does:
# 1. Verifies (or installs) uv
# 2. Creates .env from .env.example and sets LLM_PROVIDER
# 3. Installs dependencies with `uv sync`
# 4. Verifies the provider CLI is available and hints at login if needed
# 5. Runs `mirofish doctor` for a final health check

set -euo pipefail

usage() {
cat <<'USAGE'
One-command bootstrap for MiroFish on macOS / Linux.

Usage:
./scripts/setup.sh # sensible defaults
./scripts/setup.sh --provider codex-cli # pick LLM provider (default: claude-cli)
./scripts/setup.sh --yes # non-interactive (auto-install uv)

Steps: verify/install uv -> create .env -> uv sync -> check provider CLI
-> run `mirofish doctor`.
USAGE
}

PROVIDER="claude-cli"
ASSUME_YES=0

while [ $# -gt 0 ]; do
case "$1" in
--provider) PROVIDER="${2:?--provider requires a value}"; shift 2 ;;
--yes|-y) ASSUME_YES=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1 (see --help)"; exit 2 ;;
esac
done

case "$PROVIDER" in
claude-cli|codex-cli) ;;
*) echo "Unsupported provider '$PROVIDER' (expected: claude-cli | codex-cli)"; exit 2 ;;
esac

REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_DIR"

# Colors only on a real terminal, and never when NO_COLOR is set.
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
C_SAY='\033[1;36m'; C_WARN='\033[1;33m'; C_OFF='\033[0m'
else
C_SAY=''; C_WARN=''; C_OFF=''
fi
say() { printf '%b==>%b %s\n' "$C_SAY" "$C_OFF" "$*"; }
warn() { printf '%bWARN%b %s\n' "$C_WARN" "$C_OFF" "$*"; }

# --- 1. uv ------------------------------------------------------------------
if command -v uv >/dev/null 2>&1; then
say "uv found: $(uv --version)"
else
if [ "$ASSUME_YES" -ne 1 ]; then
if [ ! -t 0 ]; then
echo "uv is not installed and stdin is not a terminal; re-run with --yes to auto-install."
exit 1
fi
printf 'uv is not installed. Install it now from https://astral.sh/uv? [y/N] '
read -r ans
case "$ans" in y|Y|yes|YES) ;; *) echo "Aborted: uv is required."; exit 1 ;; esac
fi
say "Installing uv..."
# Download to a file first: avoids executing a partially-received stream
# and leaves an inspectable artifact (vs curl | sh)
uv_installer="$(mktemp)"
trap 'rm -f "$uv_installer"' EXIT
curl -LsSf https://astral.sh/uv/install.sh -o "$uv_installer"
sh "$uv_installer"
# The installer drops uv into ~/.local/bin (or ~/.cargo/bin on older setups)
export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
command -v uv >/dev/null 2>&1 || { echo "uv installed but not on PATH; open a new shell and re-run."; exit 1; }
fi

# --- 2. .env ----------------------------------------------------------------
if [ ! -f .env ]; then
cp .env.example .env
say "Created .env from .env.example"
fi
if grep -q '^LLM_PROVIDER=' .env; then
# portable in-place edit (BSD sed on macOS needs the '' argument)
sed -i.bak "s/^LLM_PROVIDER=.*/LLM_PROVIDER=${PROVIDER}/" .env && rm -f .env.bak
else
printf '\nLLM_PROVIDER=%s\n' "$PROVIDER" >> .env
fi
say "LLM_PROVIDER=${PROVIDER}"

# --- 3. dependencies --------------------------------------------------------
say "Installing dependencies (uv sync)..."
uv sync

# --- 4. provider CLI --------------------------------------------------------
case "$PROVIDER" in
claude-cli)
if command -v claude >/dev/null 2>&1; then
say "claude CLI found: $(claude --version 2>/dev/null || echo 'version unknown')"
warn "If you have never logged in, run 'claude' once and use /login (headless '-p' calls fail otherwise)."
else
warn "claude CLI not found on PATH. Install Claude Code (https://claude.com/claude-code) and log in before running simulations."
fi
;;
codex-cli)
if command -v codex >/dev/null 2>&1; then
say "codex CLI found."
else
warn "codex CLI not found on PATH. Install and authenticate it before running simulations."
fi
;;
esac

# --- 5. health check --------------------------------------------------------
say "Running mirofish doctor..."
uv run mirofish doctor || warn "doctor reported issues (see above) — fix them before your first run."

say "Done. Try:"
printf ' uv run mirofish run --files <your-docs> --requirement "Predict public reaction over 30 days" --platform parallel --max-rounds 15\n'