diff --git a/.github/workflows/publish-install-script.yml b/.github/workflows/publish-install-script.yml index 6e873d3..8b6d5e8 100644 --- a/.github/workflows/publish-install-script.yml +++ b/.github/workflows/publish-install-script.yml @@ -5,7 +5,8 @@ on: branches: - main paths: - - 'install/*.sh' + - 'install/bash/*.sh' + - 'install/powershell/*.ps1' workflow_dispatch: jobs: @@ -23,17 +24,33 @@ jobs: R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }} R2_BUCKET: ${{ secrets.R2_BUCKET }} run: | - aws s3 cp install/install.sh s3://${R2_BUCKET}/install/install.sh \ + aws s3 cp install/bash/install.sh s3://${R2_BUCKET}/install/install.sh \ --endpoint-url "${R2_ENDPOINT}" \ --content-type "text/plain" echo "✓ install.sh uploaded to R2" - aws s3 cp install/walkthrough.sh s3://${R2_BUCKET}/install/walkthrough.sh \ + aws s3 cp install/bash/walkthrough.sh s3://${R2_BUCKET}/install/walkthrough.sh \ --endpoint-url "${R2_ENDPOINT}" \ --content-type "text/plain" echo "✓ walkthrough.sh uploaded to R2" - aws s3 cp install/examples.sh s3://${R2_BUCKET}/install/examples.sh \ + aws s3 cp install/bash/examples.sh s3://${R2_BUCKET}/install/examples.sh \ --endpoint-url "${R2_ENDPOINT}" \ --content-type "text/plain" echo "✓ examples.sh uploaded to R2" + + aws s3 cp install/powershell/install.ps1 s3://${R2_BUCKET}/install/install.ps1 \ + --endpoint-url "${R2_ENDPOINT}" \ + --content-type "text/plain" + echo "✓ install.ps1 uploaded to R2" + + aws s3 cp install/powershell/walkthrough.ps1 s3://${R2_BUCKET}/install/walkthrough.ps1 \ + --endpoint-url "${R2_ENDPOINT}" \ + --content-type "text/plain" + echo "✓ walkthrough.ps1 uploaded to R2" + + aws s3 cp install/powershell/examples.ps1 s3://${R2_BUCKET}/install/examples.ps1 \ + --endpoint-url "${R2_ENDPOINT}" \ + --content-type "text/plain" + echo "✓ examples.ps1 uploaded to R2" + diff --git a/install/examples.sh b/install/bash/examples.sh similarity index 100% rename from install/examples.sh rename to install/bash/examples.sh diff --git a/install/install.sh b/install/bash/install.sh similarity index 100% rename from install/install.sh rename to install/bash/install.sh diff --git a/install/walkthrough.sh b/install/bash/walkthrough.sh similarity index 100% rename from install/walkthrough.sh rename to install/bash/walkthrough.sh diff --git a/install/powershell/examples.ps1 b/install/powershell/examples.ps1 new file mode 100644 index 0000000..dba90bd --- /dev/null +++ b/install/powershell/examples.ps1 @@ -0,0 +1,99 @@ +$ErrorActionPreference = 'Stop' + +# Brand Colors (use exported colors if available, otherwise define them) +if (-not $env:YELLOW) { $YELLOW = "$([char]27)[38;2;224;255;110m" } else { $YELLOW = $env:YELLOW } +if (-not $env:GREEN) { $GREEN = "$([char]27)[38;2;121;252;150m" } else { $GREEN = $env:GREEN } +if (-not $env:RED) { $RED = "$([char]27)[38;2;239;68;68m" } else { $RED = $env:RED } +if (-not $env:GRAY) { $GRAY = "$([char]27)[38;2;128;128;128m" } else { $GRAY = $env:GRAY } +if (-not $env:BOLD) { $BOLD = "$([char]27)[1m" } else { $BOLD = $env:BOLD } +if (-not $env:NC) { $NC = "$([char]27)[0m" } else { $NC = $env:NC } + +# Examples configuration +$EXAMPLES_FOLDER_NAME = "plainlang-examples" +$EXAMPLES_DOWNLOAD_URL = "https://github.com/Codeplain-ai/plainlang-examples/archive/refs/tags/0.1.zip" + +# Show current directory and ask for extraction path +$CURRENT_DIR = Get-Location +Write-Host " current folder: ${YELLOW}${CURRENT_DIR}${NC}" +Write-Host "" +Write-Host " extract examples here, or enter a different path:" +Write-Host "" +$EXTRACT_PATH = Read-Host " [Enter for current, or type path]" +Write-Host "" + +# Use current directory if empty +if (-not $EXTRACT_PATH) { + $EXTRACT_PATH = "$CURRENT_DIR" +} + +# Expand ~ to home directory +if ($EXTRACT_PATH.StartsWith("~")) { + $EXTRACT_PATH = $EXTRACT_PATH -replace "^~", $HOME +} + +$SKIP_DOWNLOAD = $false + +# Check if directory exists, create if not +if (-not (Test-Path $EXTRACT_PATH -PathType Container)) { + Write-Host " ${GRAY}creating directory...${NC}" + try { + New-Item -ItemType Directory -Path $EXTRACT_PATH -Force | Out-Null + } catch { + Write-Host " ${RED}✗${NC} failed to create directory: ${EXTRACT_PATH}" + Write-Host " ${GRAY}skipping example download.${NC}" + $SKIP_DOWNLOAD = $true + } +} + +if (-not $SKIP_DOWNLOAD) { + Write-Host " ${GRAY}downloading examples...${NC}" + + $TEMP_ZIP = Join-Path ([System.IO.Path]::GetTempPath()) "plainlang-examples.zip" + + try { + Invoke-WebRequest -Uri $EXAMPLES_DOWNLOAD_URL -OutFile $TEMP_ZIP -UseBasicParsing + + if (Test-Path $TEMP_ZIP) { + Write-Host " ${GRAY}extracting to ${EXTRACT_PATH}...${NC}" + + try { + Expand-Archive -Path $TEMP_ZIP -DestinationPath $EXTRACT_PATH -Force + + # Find and rename extracted directory to remove version number + $EXTRACTED_DIR = Join-Path $EXTRACT_PATH $EXAMPLES_FOLDER_NAME + $VERSIONED_DIR = Get-ChildItem -Path $EXTRACT_PATH -Directory -Filter "${EXAMPLES_FOLDER_NAME}-*" | Select-Object -First 1 + + if ($VERSIONED_DIR) { + if (Test-Path $EXTRACTED_DIR) { + Remove-Item -Path $EXTRACTED_DIR -Recurse -Force -ErrorAction SilentlyContinue + } + Rename-Item -Path $VERSIONED_DIR.FullName -NewName $EXAMPLES_FOLDER_NAME + } + + # Remove the .gitignore file from the root of the extracted directory + $GITIGNORE_PATH = Join-Path $EXTRACTED_DIR ".gitignore" + if (Test-Path $GITIGNORE_PATH) { + Remove-Item -Path $GITIGNORE_PATH -Force + } + + Write-Host "" + Write-Host " ${GREEN}✓${NC} examples downloaded successfully!" + Write-Host "" + Write-Host " examples are in: ${YELLOW}${EXTRACTED_DIR}${NC}" + Write-Host "" + } catch { + Write-Host " ${RED}✗${NC} failed to extract examples." + } + + Remove-Item -Path $TEMP_ZIP -Force -ErrorAction SilentlyContinue + } else { + Write-Host " ${RED}✗${NC} failed to download examples." + } + } catch { + Write-Host " ${RED}✗${NC} failed to download examples." + Remove-Item -Path $TEMP_ZIP -Force -ErrorAction SilentlyContinue + } + + Write-Host "" + Read-Host " press [Enter] to continue..." +} diff --git a/install/powershell/install.ps1 b/install/powershell/install.ps1 new file mode 100644 index 0000000..5c0644f --- /dev/null +++ b/install/powershell/install.ps1 @@ -0,0 +1,237 @@ +$ErrorActionPreference = 'Stop' + +# Base URL for additional scripts +if (-not $env:CODEPLAIN_SCRIPTS_BASE_URL) { + $env:CODEPLAIN_SCRIPTS_BASE_URL = "https://codeplain.ai" +} + +# Brand Colors (True Color / 24-bit) +$ESC = [char]27 +$YELLOW = "$ESC[38;2;224;255;110m" # #E0FF6E +$GREEN = "$ESC[38;2;121;252;150m" # #79FC96 +$GREEN_LIGHT= "$ESC[38;2;197;220;217m" # #C5DCD9 +$GREEN_DARK = "$ESC[38;2;34;57;54m" # #223936 +$BLUE = "$ESC[38;2;10;31;212m" # #0A1FD4 +$BLACK = "$ESC[38;2;26;26;26m" # #1A1A1A +$WHITE = "$ESC[38;2;255;255;255m" # #FFFFFF +$RED = "$ESC[38;2;239;68;68m" # #EF4444 +$GRAY = "$ESC[38;2;128;128;128m" # #808080 +$GRAY_LIGHT = "$ESC[38;2;211;211;211m" # #D3D3D3 +$BOLD = "$ESC[1m" +$NC = "$ESC[0m" # No Color / Reset + +# Export colors for child scripts (as environment variables) +$env:YELLOW = $YELLOW +$env:GREEN = $GREEN +$env:GREEN_LIGHT = $GREEN_LIGHT +$env:GREEN_DARK = $GREEN_DARK +$env:BLUE = $BLUE +$env:BLACK = $BLACK +$env:WHITE = $WHITE +$env:RED = $RED +$env:GRAY = $GRAY +$env:GRAY_LIGHT = $GRAY_LIGHT +$env:BOLD = $BOLD +$env:NC = $NC + +Clear-Host +Write-Host "started ${YELLOW}${BOLD}*codeplain CLI${NC} installation..." + +# Install uv if not present +function Install-Uv { + Write-Host "installing uv package manager..." + if ($IsWindows -or ($env:OS -eq "Windows_NT")) { + irm https://astral.sh/uv/install.ps1 | iex + $env:Path = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine') + } else { + bash -c "curl -LsSf https://astral.sh/uv/install.sh | sh" + $env:PATH = "$HOME/.local/bin:$env:PATH" + } +} + +# Check if uv is installed +if (-not (Get-Command uv -ErrorAction SilentlyContinue)) { + Write-Host "${GRAY}uv is not installed.${NC}" + Install-Uv + Write-Host "${GREEN}✓${NC} uv installed successfully" + Write-Host "" +} + +Write-Host "${GREEN}✓${NC} uv detected" +Write-Host "" + +# Install or upgrade codeplain using uv tool +$codeplainLine = @(uv tool list 2>$null) | Where-Object { $_ -match '^codeplain' } | Select-Object -First 1 +if ($codeplainLine) { + $currentVersion = ($codeplainLine -replace 'codeplain v', '').Trim() + Write-Host "${GRAY}codeplain ${currentVersion} is already installed.${NC}" + Write-Host "upgrading to latest version..." + Write-Host "" + uv tool upgrade codeplain 2>&1 | Out-Null + $newLine = @(uv tool list 2>$null) | Where-Object { $_ -match '^codeplain' } | Select-Object -First 1 + $newVersion = ($newLine -replace 'codeplain v', '').Trim() + if ($currentVersion -eq $newVersion) { + Write-Host "${GREEN}✓${NC} codeplain is already up to date (${newVersion})" + } else { + Write-Host "${GREEN}✓${NC} codeplain upgraded from ${currentVersion} to ${newVersion}!" + } +} else { + Write-Host "installing codeplain...${NC}" + Write-Host "" + uv tool install codeplain + Clear-Host + Write-Host "${GREEN}✓ codeplain installed successfully!${NC}" +} + +# Check if API key already exists +$skipApiKeySetup = $false +if ($env:CODEPLAIN_API_KEY) { + Write-Host " you already have an API key configured." + Write-Host "" + Write-Host " would you like to log in and get a new one?" + Write-Host "" + $getNewKey = Read-Host " [y/N]" + Write-Host "" + + if ($getNewKey -notmatch '^[Yy]$') { + Write-Host "${GREEN}✓${NC} using existing API key." + $skipApiKeySetup = $true + } +} + +$apiKey = $null +if (-not $skipApiKeySetup) { + Write-Host "go to ${YELLOW}https://platform.codeplain.ai${NC} and sign up to get your API key." + Write-Host "" + $apiKey = Read-Host "paste your API key here" + Write-Host "" +} + +if ($skipApiKeySetup) { + # API key already set, nothing to do +} elseif (-not $apiKey) { + Write-Host "${GRAY}no API key provided. you can set it later with:${NC}" + Write-Host ' $env:CODEPLAIN_API_KEY = "your_api_key"' +} else { + # Set for current session + $env:CODEPLAIN_API_KEY = $apiKey + + # Persist as user environment variable (survives reboots) + [Environment]::SetEnvironmentVariable('CODEPLAIN_API_KEY', $apiKey, 'User') + Write-Host "${GREEN}✓ API key saved to user environment variables${NC}" +} + +# ASCII Art Welcome +Clear-Host +Write-Host "" +Write-Host "${NC}" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host @' + _ _ _ + ___ ___ __| | ___ _ __ | | __ _(_)_ __ + / __/ _ \ / _` |/ _ \ '_ \| |/ _` | | '_ \ + | (_| (_) | (_| | __/ |_) | | (_| | | | | | + \___\___/ \__,_|\___| .__/|_|\__,_|_|_| |_| + |_| +'@ +Write-Host "" +Write-Host "${GREEN}✓${NC} Sign in successful." +Write-Host "" +Write-Host " ${YELLOW}welcome to *codeplain!${NC}" +Write-Host "" +Write-Host " spec-driven, production-ready code generation" +Write-Host "" +Write-Host "" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " would you like to get a quick intro to ***plain specification language?" +Write-Host "" +$walkthroughChoice = Read-Host " [Y/n]" +Write-Host "" + +# Determine script directory for local execution +$ScriptDir = "" +if ($PSScriptRoot) { + $ScriptDir = $PSScriptRoot +} + +# Helper function to run a script (local or remote) +function Invoke-SubScript { + param([string]$ScriptName) + + $scriptPath = "" + + # Check possible local paths + if ($ScriptDir -and (Test-Path (Join-Path $ScriptDir $ScriptName))) { + $scriptPath = Join-Path $ScriptDir $ScriptName + } elseif (Test-Path (Join-Path ".\install" $ScriptName)) { + $scriptPath = Join-Path ".\install" $ScriptName + } elseif (Test-Path ".\$ScriptName") { + $scriptPath = ".\$ScriptName" + } + + if ($scriptPath) { + # Run locally + & $scriptPath + } else { + # Download and run + $tempFile = Join-Path ([System.IO.Path]::GetTempPath()) $ScriptName + Invoke-WebRequest -Uri "${env:CODEPLAIN_SCRIPTS_BASE_URL}/${ScriptName}" -OutFile $tempFile -UseBasicParsing + try { + & $tempFile + } finally { + Remove-Item $tempFile -ErrorAction SilentlyContinue + } + } +} + +# Run walkthrough if user agrees +if ($walkthroughChoice -notmatch '^[Nn]$') { + Invoke-SubScript "walkthrough.ps1" +} + +# Download examples step +Clear-Host +Write-Host "" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}Example Projects${NC}" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " we've prepared some example Plain projects for you" +Write-Host " to explore and experiment with." +Write-Host "" +Write-Host " would you like to download them?" +Write-Host "" +$downloadExamples = Read-Host " [Y/n]" +Write-Host "" + +# Run examples download if user agrees +if ($downloadExamples -notmatch '^[Nn]$') { + Invoke-SubScript "examples.ps1" +} + +# Final message +Clear-Host +Write-Host "" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}You're all set!${NC}" +Write-Host "${GRAY}────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " thank you for using ${YELLOW}*codeplain!${NC}" +Write-Host "" +Write-Host " ${BOLD}next steps:${NC}" +Write-Host "" +Write-Host " join our Discord community: ${YELLOW}https://discord.gg/4qQJaMu7Y${NC}" +Write-Host "" +Write-Host " learn more about ${YELLOW}***plain${NC} at ${YELLOW}https://plainlang.org/${NC}" +Write-Host "" +Write-Host " ${GREEN}happy development!${NC} 🚀" +Write-Host "" + +# Refresh environment for this session +# Unlike bash's exec "$SHELL", PowerShell doesn't need to restart the shell. +# The API key is already set in $env:CODEPLAIN_API_KEY for this session, +# and persisted via [Environment]::SetEnvironmentVariable for new sessions. +# Refresh PATH to pick up uv tool installations. +$env:Path = [Environment]::GetEnvironmentVariable('Path', 'User') + ';' + [Environment]::GetEnvironmentVariable('Path', 'Machine') diff --git a/install/powershell/walkthrough.ps1 b/install/powershell/walkthrough.ps1 new file mode 100644 index 0000000..8c5472a --- /dev/null +++ b/install/powershell/walkthrough.ps1 @@ -0,0 +1,173 @@ +$ErrorActionPreference = 'Stop' + +# Brand Colors (use exported colors if available, otherwise define them) +if (-not $env:YELLOW) { $YELLOW = "$([char]27)[38;2;224;255;110m" } else { $YELLOW = $env:YELLOW } +if (-not $env:GREEN) { $GREEN = "$([char]27)[38;2;121;252;150m" } else { $GREEN = $env:GREEN } +if (-not $env:WHITE) { $WHITE = "$([char]27)[38;2;255;255;255m" } else { $WHITE = $env:WHITE } +if (-not $env:GRAY) { $GRAY = "$([char]27)[38;2;128;128;128m" } else { $GRAY = $env:GRAY } +if (-not $env:BOLD) { $BOLD = "$([char]27)[1m" } else { $BOLD = $env:BOLD } +if (-not $env:NC) { $NC = "$([char]27)[0m" } else { $NC = $env:NC } + +# Onboarding Step 1: Introduction to Plain +Clear-Host +Write-Host "" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 1 of 5" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " ***plain is a language of spec-driven development that allows developers to express intent at any level of detail." +Write-Host "" +Write-Host " write specs in natural language extended with additional syntax based on markdown." +Write-Host "" +Write-Host " render production-ready code with *codeplain." +Write-Host "" +Write-Host " A ***plain file has these key sections:" +Write-Host "" +Write-Host "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}***definitions***${NC} - key concepts in your app ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}***implementation reqs***${NC} - implementation details ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}***test reqs***${NC} - testing requirements ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}***functional specs***${NC} - what the app should do ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} └────────────────────────────────────────────────────────┘${NC}" +Write-Host "" +Write-Host " Let's see each section in a `"hello, world`" example." +Write-Host "" +Read-Host " press [Enter] to continue..." + +# Onboarding Step 2: Functional Specification +Clear-Host +Write-Host "" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 2 of 5" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " ${WHITE}${BOLD}FUNCTIONAL SPECS${NC} - what should the app do?" +Write-Host "" +Write-Host " This is where you describe ${GREEN}what your app should do${NC}," +Write-Host " written in natural language. No code, just requirements." +Write-Host "" +Write-Host "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}${BOLD}***functional specs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GREEN}${BOLD}- :App: should display `"hello, world`".${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} └────────────────────────────────────────────────────────┘${NC}" +Write-Host "" +Write-Host " ${GREEN}▲${NC} The ${YELLOW}functional spec${NC} describes ${GREEN}what${NC} the app does." +Write-Host " Here, it simply displays `"hello, world`"." +Write-Host "" +Read-Host " press [Enter] to continue..." + +# Onboarding Step 3: Definitions +Clear-Host +Write-Host "" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 3 of 5" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " ${WHITE}${BOLD}DEFINITIONS${NC} - definitions and descriptions of key concepts" +Write-Host "" +Write-Host " Define ${GREEN}reusable concepts${NC} using the ${YELLOW}:Concept:${NC} notation." +Write-Host " These become building blocks you can reference anywhere." +Write-Host "" +Write-Host "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}${BOLD}***definitions***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GREEN}${BOLD}- :App: is a console application.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***implementation reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***test reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :App: should display `"hello, world`".${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} └────────────────────────────────────────────────────────┘${NC}" +Write-Host "" +Write-Host " ${GREEN}▲${NC} The ${YELLOW}:App:${NC} concept is defined once and used throughout the specs." +Write-Host " Concepts help keep your specs consistent and clear." +Write-Host "" +Read-Host " press [Enter] to continue..." + +# Onboarding Step 4: Implementation & Test Reqs +Clear-Host +Write-Host "" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 4 of 5" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " ${WHITE}${BOLD}IMPLEMENTATION & TEST REQS${NC} - how to implement and test" +Write-Host "" +Write-Host " Specify ${GREEN}implementation details${NC} and ${GREEN}testing requirements${NC}." +Write-Host " This guides how the code should be generated and verified." +Write-Host "" +Write-Host "${GRAY} ┌────────────────────────────────────────────────────────┐${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***definitions***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :App: is a console application.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}${BOLD}***implementation reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GREEN}${BOLD}- :Implementation: should be in Python.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${YELLOW}${BOLD}***test reqs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GREEN}${BOLD}- :ConformanceTests: should use pytest.${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}***functional specs***${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}- :App: should display `"hello, world`".${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} │${NC} ${GRAY}│${NC}" +Write-Host "${GRAY} └────────────────────────────────────────────────────────┘${NC}" +Write-Host "" +Write-Host " ${GREEN}▲${NC} ${YELLOW}Implementation reqs${NC} define the language and frameworks." +Write-Host " ${YELLOW}Test reqs${NC} ensure the generated code is verified." +Write-Host "" +Read-Host " press [Enter] to continue..." + +# Onboarding Step 5: Rendering Code +Clear-Host +Write-Host "" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host " ${YELLOW}${BOLD}***plain specification language intro${NC} - Step 5 of 5" +Write-Host "${GRAY}─────────────────────────────────────────────────────────${NC}" +Write-Host "" +Write-Host " ${WHITE}${BOLD}RENDERING CODE${NC} - generate your app" +Write-Host "" +Write-Host " Once you have a Plain file, generate code with:" +Write-Host "" +Write-Host " ${YELLOW}${BOLD}codeplain hello_world.plain${NC}" +Write-Host "" +Write-Host " *codeplain will:" +Write-Host "" +Write-Host " ${GREEN}1.${NC} Read your specification" +Write-Host " ${GREEN}2.${NC} Generate implementation code" +Write-Host " ${GREEN}3.${NC} Create and run tests to verify correctness" +Write-Host " ${GREEN}4.${NC} Output production-ready code" +Write-Host "" +Write-Host " The generated code is guaranteed to match your specs" +Write-Host " and pass all defined tests." +Write-Host "" +Read-Host " press [Enter] to finish..."