diff --git a/tools/ralph/DEPLOY.md b/tools/ralph/DEPLOY.md new file mode 100644 index 000000000..8cc621ba4 --- /dev/null +++ b/tools/ralph/DEPLOY.md @@ -0,0 +1,91 @@ +# Deploying and Testing a Charm + +This guide provides step-by-step instructions for deploying a charm locally and +testing it with Playwright. + +## Step 1: Create an Identity Key + +First, create an identity key if one doesn't exist: + +```bash +NO_COLOR=1 deno task ct id new > my.key +``` + +**Important:** Do NOT add `2>&1` to this command - it will corrupt the key file +by mixing error output with the actual key. + +This creates a new identity key file named `my.key` in the current directory. + +## Step 2: Deploy the Charm + +Deploy a charm to localhost using the `ct charm new` command: + +```bash +deno task ct charm new --identity ./my.key --api-url http://127.0.0.1:8000 --space +``` + +Example: + +```bash +deno task ct charm new --identity ./my.key --api-url http://127.0.0.1:8000 --space ellyse ./packages/patterns/counter.tsx +``` + +The command will output a charm ID (e.g., +`baedreidon464mghox4uar46bbym5t6bnmlvn6wwzby5vvdmsw24oxaalp4`). + +## Step 3: Construct the URL + +The URL format for localhost is: + +``` +http://localhost:5173// +``` + +Example: + +``` +http://localhost:5173/ellyse/baedreidon464mghox4uar46bbym5t6bnmlvn6wwzby5vvdmsw24oxaalp4 +``` + +## Step 4: Test with Playwright + +### 4.1 Navigate to the Charm URL + +```javascript +await page.goto("http://localhost:5173//"); +``` + +### 4.2 Register/Login (First Time Only) + +When you first visit, you'll see a login page. Register with a passphrase: + +1. Click the "➕ Register" button +2. Click the "🔑 Generate Passphrase" button +3. Click the "🔒 I've Saved It - Continue" button + +This will log you in and load the charm. + +### 4.3 Test the Charm + +Once logged in, you can interact with the charm using Playwright commands. + +## Complete Example + +```bash +# 1. Create identity key (if needed) +deno task ct id new > my.key + +# 2. Deploy charm +deno task ct charm new --identity ./my.key --api-url http://127.0.0.1:8000 --space ellyse ./packages/patterns/counter.tsx + +# Output: baedreidon464mghox4uar46bbym5t6bnmlvn6wwzby5vvdmsw24oxaalp4 + +# 3. URL will be: +# http://localhost:5173/ellyse/baedreidon464mghox4uar46bbym5t6bnmlvn6wwzby5vvdmsw24oxaalp4 +``` + +Then use Playwright to: + +1. Navigate to the URL +2. Complete registration (first time) +3. Test the charm functionality diff --git a/tools/ralph/Dockerfile b/tools/ralph/Dockerfile new file mode 100644 index 000000000..9a1d137ba --- /dev/null +++ b/tools/ralph/Dockerfile @@ -0,0 +1,84 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# Base tools +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + wget \ + git \ + ripgrep \ + build-essential \ + ca-certificates \ + gnupg \ + lsb-release \ + unzip \ + sudo \ + software-properties-common + +# GitHub CLI +RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \ + gpg --dearmor -o /usr/share/keyrings/githubcli-archive-keyring.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \ + tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \ + apt-get update && apt-get install -y gh + +# Node.js 24 (via Nodesource) +RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && \ + apt-get install -y nodejs + +# Deno (install globally to /usr/local with pinned version) +RUN curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s v2.5.2 + +# Helix editor (requires software-properties-common from base tools) +RUN add-apt-repository -y ppa:maveonair/helix-editor && \ + apt-get update && \ + apt-get install -y helix + +# MyST Markdown (via npm to avoid Python PEP 668 issues) +RUN npm install -g mystmd + +# Install Playwright browser and dependencies +RUN npx playwright install chrome && \ + npx playwright install-deps chrome + +# Create ralph user (with sudo privileges for development) +RUN useradd -m -s /bin/bash ralph && \ + echo "ralph ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Set up working directory with proper ownership +RUN mkdir -p /app && chown ralph:ralph /app +WORKDIR /app + +# Clone the Common Tools repository into labs subdirectory +RUN git clone https://github.com/commontoolsinc/labs.git /app/labs && \ + chown -R ralph:ralph /app/labs + +# Copy and append DEPLOY.md to AGENTS.md +COPY --chown=ralph:ralph DEPLOY.md /tmp/DEPLOY.md +RUN cat /tmp/DEPLOY.md >> /app/labs/AGENTS.md && \ + rm /tmp/DEPLOY.md + +# Copy the startup script from local directory +COPY --chown=ralph:ralph start-servers.sh /app/start-servers.sh +RUN chmod +x /app/start-servers.sh + +# Switch to ralph user +USER ralph + +# Configure npm to install global packages in user directory +RUN npm config set prefix ~/.npm-global + +# Add npm-global bin to PATH +ENV PATH="/home/ralph/.npm-global/bin:$PATH" + +# Install Claude CLI and Codex as ralph user (can auto-update) +RUN npm install -g @anthropic-ai/claude-code && \ + npm install -g @openai/codex + +# Configure Claude MCP server for ralph user +# --no-sandbox is required because Docker containers restrict namespace creation +RUN claude mcp add --scope user playwright npx "@playwright/mcp@latest" -- --headless --isolated --no-sandbox + +# Start Common Tool servers +CMD ["/app/start-servers.sh"] diff --git a/tools/ralph/README.md b/tools/ralph/README.md new file mode 100644 index 000000000..584746ac8 --- /dev/null +++ b/tools/ralph/README.md @@ -0,0 +1,95 @@ +# README + +Docker container to run the Common Tools servers + +Ability to run [Ralph](https://ghuntley.com/ralph/) + +Claude CLI and Codex are installed + +## How to run Ralph + +### Using pre-built image from Docker Hub (recommended) + +```bash +$ docker pull ellyxir/ralph +$ docker run -d --name ralph -p 8000:8000 -p 5173:5173 ellyxir/ralph +``` + +To connect to the container (connecting as ralph user is recommended): + +```bash +$ docker exec -it -u ralph ralph bash # Connect as ralph user (recommended) +# OR +$ docker exec -it ralph bash # Connect as root (if needed for admin tasks) +``` + +### Building locally + +If you want to build the image yourself with local modifications: + +```bash +$ cd ./tools/ralph +$ docker build -t /ralph . +$ docker run -d --name ralph -p 8000:8000 -p 5173:5173 /ralph +``` + +Note for `docker build`: + +- -t is for the tag, we use _ralph_ here + +Note for `docker run`: + +- -d is for detached mode +- --name gives it an easier name to use for connecting to it later +- the last _/ralph_ referes to the build tag we used earlier + +Connecting to the running container: + +```bash +$ docker exec -it -u ralph ralph bash # Connect as ralph user (recommended) +$ docker exec -it ralph bash +``` + +We are using the `--name ralph` we specified earlier to connect. + +Running Claude Code with all permissions: + +```bash +$ claude --dangerously-skip-permissions +``` + +## Removing ralph + +You must remove the existing version if you want to run a newer build: + +```bash +$ docker stop ralph +$ docker rm ralph +``` + +## Pushing new image to Dockerhub + +``` +$ docker login +$ docker push /ralph +``` + +## TODO + +- add playwright to codex +- push a working image to a docker hub +- update README to use image from dockerhub +- figure out how LLM tokens should be set for toolshed +- sandbox the container (network config) +- make ralph easy to run +- DONE - change permissions so claude auto updater will work +- DONE - move ralph script into ./tools/ralph +- DONE - Add codex and claude packages +- DONE - write section how to run ralph in this file +- DONE - git clone the common tools repositories +- DONE - start up toolshed server +- DONE - start up shell server +- DONE - add playwright mcp to claude + - created ralph user since chrome doesnt like to run as root, probably better + this way anyway + - made ralph sudoer diff --git a/tools/ralph/start-servers.sh b/tools/ralph/start-servers.sh new file mode 100755 index 000000000..ab024905b --- /dev/null +++ b/tools/ralph/start-servers.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# Start toolshed server in background +echo "Starting toolshed server..." +cd /app/labs/packages/toolshed && deno task dev & +TOOLSHED_PID=$! + +# Start shell server in background +echo "Starting shell server..." +cd /app/labs/packages/shell && deno task dev-local & +SHELL_PID=$! + +# Function to handle shutdown +cleanup() { + echo "Shutting down servers..." + kill $TOOLSHED_PID $SHELL_PID 2>/dev/null + exit 0 +} + +# Set up signal handlers +trap cleanup SIGTERM SIGINT + +# Keep the script running and show logs +echo "Servers started. Press Ctrl+C to stop." +echo "Toolshed PID: $TOOLSHED_PID" +echo "Shell PID: $SHELL_PID" + +# Wait for both processes and capture their exit statuses +wait $TOOLSHED_PID +TOOLSHED_EXIT=$? +wait $SHELL_PID +SHELL_EXIT=$? + +# Exit with error if either server failed +if [ $TOOLSHED_EXIT -ne 0 ] || [ $SHELL_EXIT -ne 0 ]; then + echo "Server exited with error (toolshed: $TOOLSHED_EXIT, shell: $SHELL_EXIT)" + exit 1 +fi