From dbfc969c2b831f83e7c183ce5d6aeb37a762d5de Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Dec 2025 08:44:26 +0000 Subject: [PATCH 1/3] Add web playground for interactive EigenScript execution - Flask-based web UI with code editor and output panel - 7 example programs demonstrating language features - Deployment configs for Railway, Render, Fly.io - Keyboard shortcut (Ctrl+Enter) to run code - 30-second execution timeout for safety --- web/Procfile | 1 + web/README.md | 66 ++++++ web/app.py | 215 +++++++++++++++++++ web/requirements.txt | 3 + web/templates/index.html | 441 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 726 insertions(+) create mode 100644 web/Procfile create mode 100644 web/README.md create mode 100644 web/app.py create mode 100644 web/requirements.txt create mode 100644 web/templates/index.html diff --git a/web/Procfile b/web/Procfile new file mode 100644 index 0000000..6d4991b --- /dev/null +++ b/web/Procfile @@ -0,0 +1 @@ +web: gunicorn app:app --bind 0.0.0.0:$PORT diff --git a/web/README.md b/web/README.md new file mode 100644 index 0000000..3a2037a --- /dev/null +++ b/web/README.md @@ -0,0 +1,66 @@ +# EigenScript Web Playground + +Interactive web interface for running EigenScript code in the browser. + +## Quick Start (Local) + +```bash +cd web +pip install -r requirements.txt +python app.py +``` + +Visit http://localhost:5000 + +## Deploy to Railway + +1. Connect your GitHub repo to [Railway](https://railway.app) +2. Set the root directory to `web/` +3. Railway auto-detects the Procfile and deploys + +## Deploy to Render + +1. Connect your GitHub repo to [Render](https://render.com) +2. Create a new Web Service +3. Set: + - Root Directory: `web` + - Build Command: `pip install -r requirements.txt` + - Start Command: `gunicorn app:app` + +## Deploy to Fly.io + +```bash +cd web +fly launch +fly deploy +``` + +## Features + +- **Code Editor**: Write and edit EigenScript code +- **Example Gallery**: Pre-loaded examples demonstrating language features +- **Live Execution**: Run code with 30-second timeout +- **Keyboard Shortcuts**: Ctrl/Cmd + Enter to run + +## Examples Included + +| Example | Description | +|---------|-------------| +| Hello World | Basic syntax introduction | +| Convergence | The "Inaugural Algorithm" - damped oscillation | +| Factorial | Recursive function demo | +| XOR Demo | Neural network-style computation | +| Matrix Operations | Linear algebra with matrices | +| Higher-Order Functions | map, filter, reduce | +| Geometric Introspection | Self-aware predicates | + +## API Endpoints + +- `GET /` - Playground UI +- `POST /run` - Execute code (JSON: `{code: "..."}`) +- `GET /examples/` - Get example code + +## Environment + +The playground requires EigenScript to be installed. For cloud deployment, +the `requirements.txt` includes eigenscript as a dependency. diff --git a/web/app.py b/web/app.py new file mode 100644 index 0000000..ee2d5e8 --- /dev/null +++ b/web/app.py @@ -0,0 +1,215 @@ +""" +EigenScript Web Playground +Interactive web interface for running EigenScript code +""" + +from flask import Flask, render_template, request, jsonify +import subprocess +import tempfile +import os + +app = Flask(__name__) + +# Example code snippets +EXAMPLES = { + "hello": """# Hello World +print of "Hello from EigenScript!" +x is 5 +y is 3 +print of "Sum:" +print of x + y +""", + "convergence": """# Convergence Demo - The Inaugural Algorithm +x is 0 +target is 10 +velocity is 0 + +loop while x < 20: + error is target - x + velocity is velocity + (error * 0.1) + velocity is velocity * 0.9 + x is x + velocity + print of x + + if converged: + print of "Converged!" + break +""", + "factorial": """# Recursive Factorial +define factorial as: + if n < 2: + return 1 + prev is n - 1 + sub_result is factorial of prev + return n * sub_result + +print of "5! =" +result is factorial of 5 +print of result + +print of "10! =" +result is factorial of 10 +print of result +""", + "xor": """# XOR Neural Network Demo +define threshold as: + x is arg + if x > 0: + return 1 + return 0 + +define compute_xor as: + a is arg[0] + b is arg[1] + or_val is threshold of (a + b - 0.5) + and_val is threshold of (a + b - 1.5) + nand_val is 1 - and_val + result is threshold of (or_val + nand_val - 1.5) + return result + +print of "XOR Truth Table:" +print of "XOR(0,0) =" +print of compute_xor of [0, 0] +print of "XOR(0,1) =" +print of compute_xor of [0, 1] +print of "XOR(1,0) =" +print of compute_xor of [1, 0] +print of "XOR(1,1) =" +print of compute_xor of [1, 1] +""", + "matrix": """# Matrix Operations +A is matrix of [[1, 2], [3, 4]] +B is matrix of [[5, 6], [7, 8]] + +print of "Matrix A:" +A_list is matrix_to_list of A +print of A_list + +print of "Matrix B:" +B_list is matrix_to_list of B +print of B_list + +print of "A * B:" +C is matmul of [A, B] +C_list is matrix_to_list of C +print of C_list + +print of "A transposed:" +At is transpose of A +At_list is matrix_to_list of At +print of At_list +""", + "geometric": """# Geometric Introspection +print of "=== Geometric Predicates ===" + +counter is 0 +limit is 20 + +loop while counter < limit: + counter is counter + 1 + + if converged: + print of "Converged at iteration:" + print of counter + break + + if stable: + print of "Stable at:" + print of counter + +print of "" +print of "=== Final Metrics ===" +print of "Framework strength:" +fs is framework_strength +print of fs +""", + "higher_order": """# Higher-Order Functions +numbers is [1, 2, 3, 4, 5] + +define square as: + return n * n + +define is_even as: + return (n % 2) is 0 + +print of "Original list:" +print of numbers + +print of "Squared:" +squared is map of [square, numbers] +print of squared + +print of "Even numbers:" +evens is filter of [is_even, numbers] +print of evens + +print of "Sum (reduce):" +define add as: + return a + b +total is reduce of [add, numbers, 0] +print of total +""" +} + + +@app.route('/') +def index(): + return render_template('index.html', examples=EXAMPLES) + + +@app.route('/run', methods=['POST']) +def run_code(): + code = request.json.get('code', '') + + if not code.strip(): + return jsonify({'error': 'No code provided', 'output': ''}) + + with tempfile.NamedTemporaryFile(mode='w', suffix='.eigs', delete=False) as f: + f.write(code) + temp_path = f.name + + try: + result = subprocess.run( + ['eigenscript', temp_path], + capture_output=True, + text=True, + timeout=30 + ) + + output = result.stdout + error = result.stderr + + if result.returncode != 0: + return jsonify({ + 'error': error or 'Execution failed', + 'output': output + }) + + return jsonify({ + 'output': output, + 'error': '' + }) + + except subprocess.TimeoutExpired: + return jsonify({ + 'error': 'Execution timed out (30s limit)', + 'output': '' + }) + except Exception as e: + return jsonify({ + 'error': str(e), + 'output': '' + }) + finally: + os.unlink(temp_path) + + +@app.route('/examples/') +def get_example(name): + if name in EXAMPLES: + return jsonify({'code': EXAMPLES[name]}) + return jsonify({'error': 'Example not found'}), 404 + + +if __name__ == '__main__': + app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/web/requirements.txt b/web/requirements.txt new file mode 100644 index 0000000..560e9e3 --- /dev/null +++ b/web/requirements.txt @@ -0,0 +1,3 @@ +flask>=2.0.0 +gunicorn>=21.0.0 +eigenscript>=0.4.1 diff --git a/web/templates/index.html b/web/templates/index.html new file mode 100644 index 0000000..5204026 --- /dev/null +++ b/web/templates/index.html @@ -0,0 +1,441 @@ + + + + + + EigenScript Playground + + + +
+ +
+
+ Ready +
+
+ +
+
+
+ Editor +
+ + + +
+
+
+ +
+
+ +
+
+ Output + +
+
+
Output will appear here...
+
+
+
+ +
+
+
+ Lines: + 0 +
+
+ Execution: + - +
+
+
+ GitHub +  |  + Docs +
+
+ + + + From 20abc54a896301d5116167eeacd9f767f843a2b2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Dec 2025 08:50:50 +0000 Subject: [PATCH 2/3] Update web playground with full EigenScript support and Replit config - Add Dockerfile with LLVM toolchain for compiler support - Add Replit config files (.replit, replit.nix) - Update app.py with 10 comprehensive examples - Add support for compile mode alongside interpret mode - Update UI with EigenScript branding (v0.4.1 Fixpoint Bootstrap) - Add examples: attention mechanism, interrogatives, meta-circular eval - Add health check endpoint - Tab key support for indentation --- web/.replit | 13 +++ web/Dockerfile | 24 +++++ web/README.md | 83 ++++++++------ web/app.py | 226 +++++++++++++++++++++++++++++++++------ web/replit.nix | 12 +++ web/requirements.txt | 4 +- web/templates/index.html | 134 +++++++++++++++++------ 7 files changed, 399 insertions(+), 97 deletions(-) create mode 100644 web/.replit create mode 100644 web/Dockerfile create mode 100644 web/replit.nix diff --git a/web/.replit b/web/.replit new file mode 100644 index 0000000..f99ee50 --- /dev/null +++ b/web/.replit @@ -0,0 +1,13 @@ +run = "pip install -e .. && python app.py" +entrypoint = "app.py" + +[nix] +channel = "stable-23_11" + +[deployment] +run = ["sh", "-c", "pip install -e .. && gunicorn app:app --bind 0.0.0.0:5000"] +deploymentTarget = "cloudrun" + +[[ports]] +localPort = 5000 +externalPort = 80 diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..ed1caa1 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,24 @@ +FROM python:3.11-slim + +# Install LLVM toolchain for full compiler support +RUN apt-get update && apt-get install -y \ + llvm \ + clang \ + gcc \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /app + +# Copy requirements first for caching +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application +COPY . . + +# Expose port +EXPOSE 5000 + +# Run with gunicorn +CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:5000", "--workers", "2", "--timeout", "60"] diff --git a/web/README.md b/web/README.md index 3a2037a..77a4168 100644 --- a/web/README.md +++ b/web/README.md @@ -1,8 +1,16 @@ # EigenScript Web Playground -Interactive web interface for running EigenScript code in the browser. +Interactive web interface for running EigenScript code with full language support. -## Quick Start (Local) +## Deploy to Replit (Recommended) + +1. Import this repo to Replit +2. Set the run directory to `web/` +3. Click **Run** - Replit auto-detects the config + +The `replit.nix` includes LLVM toolchain for full compiler support. + +## Local Development ```bash cd web @@ -12,55 +20,62 @@ python app.py Visit http://localhost:5000 -## Deploy to Railway - -1. Connect your GitHub repo to [Railway](https://railway.app) -2. Set the root directory to `web/` -3. Railway auto-detects the Procfile and deploys - -## Deploy to Render - -1. Connect your GitHub repo to [Render](https://render.com) -2. Create a new Web Service -3. Set: - - Root Directory: `web` - - Build Command: `pip install -r requirements.txt` - - Start Command: `gunicorn app:app` - -## Deploy to Fly.io +## Deploy with Docker ```bash cd web -fly launch -fly deploy +docker build -t eigenscript-playground . +docker run -p 5000:5000 eigenscript-playground ``` +## Deploy to Railway/Render + +1. Connect your GitHub repo +2. Set root directory to `web/` +3. Auto-deploys from Dockerfile + ## Features -- **Code Editor**: Write and edit EigenScript code -- **Example Gallery**: Pre-loaded examples demonstrating language features -- **Live Execution**: Run code with 30-second timeout -- **Keyboard Shortcuts**: Ctrl/Cmd + Enter to run +- **Full EigenScript v0.4.1** - Complete language support +- **10 Example Programs** - Demonstrating all major features +- **Geometric Introspection** - Self-aware predicates (converged, stable, etc.) +- **Matrix Operations** - Linear algebra support +- **Higher-Order Functions** - map, filter, reduce +- **Meta-Circular Evaluation** - Self-reference demos +- **Keyboard Shortcuts** - Ctrl+Enter to run, Tab for indent ## Examples Included | Example | Description | |---------|-------------| -| Hello World | Basic syntax introduction | -| Convergence | The "Inaugural Algorithm" - damped oscillation | -| Factorial | Recursive function demo | -| XOR Demo | Neural network-style computation | -| Matrix Operations | Linear algebra with matrices | -| Higher-Order Functions | map, filter, reduce | +| Hello World | Basic syntax | +| Convergence | The Inaugural Algorithm | +| Factorial | Recursive functions | +| XOR Neural Net | Threshold activation | +| Matrix Operations | Linear algebra | +| Attention Mechanism | Transformer core | +| Higher-Order Functions | map/filter/reduce | | Geometric Introspection | Self-aware predicates | +| Interrogatives | WHO/WHAT/WHERE queries | +| Meta-Circular Eval | Self-reference stability | ## API Endpoints - `GET /` - Playground UI -- `POST /run` - Execute code (JSON: `{code: "..."}`) +- `POST /run` - Execute code `{code: "...", mode: "interpret"}` - `GET /examples/` - Get example code +- `GET /health` - Health check -## Environment +## Files -The playground requires EigenScript to be installed. For cloud deployment, -the `requirements.txt` includes eigenscript as a dependency. +``` +web/ +├── app.py # Flask server +├── templates/ +│ └── index.html # Playground UI +├── requirements.txt # Python dependencies +├── Dockerfile # Container deployment +├── Procfile # Heroku/Railway +├── .replit # Replit config +└── replit.nix # Nix dependencies +``` diff --git a/web/app.py b/web/app.py index ee2d5e8..bfa170e 100644 --- a/web/app.py +++ b/web/app.py @@ -1,6 +1,6 @@ """ EigenScript Web Playground -Interactive web interface for running EigenScript code +Interactive web interface for running EigenScript code with full compiler support """ from flask import Flask, render_template, request, jsonify @@ -10,20 +10,25 @@ app = Flask(__name__) -# Example code snippets +# Example code snippets - comprehensive demos of all features EXAMPLES = { "hello": """# Hello World print of "Hello from EigenScript!" + x is 5 y is 3 print of "Sum:" print of x + y """, "convergence": """# Convergence Demo - The Inaugural Algorithm +# Watch a value converge to a target using damped oscillation + x is 0 target is 10 velocity is 0 +print of "Converging to target..." + loop while x < 20: error is target - x velocity is velocity + (error * 0.1) @@ -32,8 +37,11 @@ print of x if converged: - print of "Converged!" + print of "System converged!" break + +print of "Final value:" +print of x """, "factorial": """# Recursive Factorial define factorial as: @@ -43,6 +51,7 @@ sub_result is factorial of prev return n * sub_result +print of "Factorial calculations:" print of "5! =" result is factorial of 5 print of result @@ -50,8 +59,14 @@ print of "10! =" result is factorial of 10 print of result + +print of "12! =" +result is factorial of 12 +print of result """, "xor": """# XOR Neural Network Demo +# Implements XOR using threshold activation functions + define threshold as: x is arg if x > 0: @@ -61,13 +76,18 @@ define compute_xor as: a is arg[0] b is arg[1] + # OR gate or_val is threshold of (a + b - 0.5) + # AND gate and_val is threshold of (a + b - 1.5) + # NAND of the AND result nand_val is 1 - and_val + # Final XOR = OR AND NAND result is threshold of (or_val + nand_val - 1.5) return result print of "XOR Truth Table:" +print of "===============" print of "XOR(0,0) =" print of compute_xor of [0, 0] print of "XOR(0,1) =" @@ -78,6 +98,8 @@ print of compute_xor of [1, 1] """, "matrix": """# Matrix Operations +# Linear algebra with EigenScript matrices + A is matrix of [[1, 2], [3, 4]] B is matrix of [[5, 6], [7, 8]] @@ -89,7 +111,7 @@ B_list is matrix_to_list of B print of B_list -print of "A * B:" +print of "A * B (matrix multiply):" C is matmul of [A, B] C_list is matrix_to_list of C print of C_list @@ -98,33 +120,48 @@ At is transpose of A At_list is matrix_to_list of At print of At_list + +print of "Determinant of A:" +det is determinant of A +print of det """, - "geometric": """# Geometric Introspection -print of "=== Geometric Predicates ===" + "attention": """# Scaled Dot-Product Attention +# Core mechanism of transformer models -counter is 0 -limit is 20 +Q is matrix of [[1.0, 0.0], [0.0, 1.0]] +K is matrix of [[1.0, 0.0], [0.0, 1.0]] +V is matrix of [[1.0, 2.0], [3.0, 4.0]] -loop while counter < limit: - counter is counter + 1 +print of "Query matrix Q:" +print of matrix_to_list of Q - if converged: - print of "Converged at iteration:" - print of counter - break +print of "Key matrix K:" +print of matrix_to_list of K - if stable: - print of "Stable at:" - print of counter +print of "Value matrix V:" +print of matrix_to_list of V + +print of "Computing attention..." + +# Attention(Q, K, V) = softmax(QK^T / sqrt(d_k)) * V +K_t is transpose of K +scores is matmul of [Q, K_t] +scaled is matrix_scale of [scores, 0.707] +weights is softmax_matrix of scaled +output is matmul of [weights, V] + +print of "Attention output:" +out_list is matrix_to_list of output +print of out_list -print of "" -print of "=== Final Metrics ===" print of "Framework strength:" fs is framework_strength print of fs """, "higher_order": """# Higher-Order Functions -numbers is [1, 2, 3, 4, 5] +# map, filter, reduce with custom functions + +numbers is [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] define square as: return n * n @@ -132,22 +169,123 @@ define is_even as: return (n % 2) is 0 +define add as: + return a + b + print of "Original list:" print of numbers -print of "Squared:" +print of "Squared (map):" squared is map of [square, numbers] print of squared -print of "Even numbers:" +print of "Even numbers (filter):" evens is filter of [is_even, numbers] print of evens print of "Sum (reduce):" -define add as: - return a + b total is reduce of [add, numbers, 0] print of total + +print of "List comprehension - squares of evens:" +result is [square of x for x in numbers if is_even of x] +print of result +""", + "geometric": """# Geometric Introspection +# EigenScript's self-aware predicates + +print of "=== Geometric Predicates ===" +print of "Tracking computational state..." + +counter is 0 +limit is 25 +prev_value is 0 + +loop while counter < limit: + counter is counter + 1 + + # Oscillating computation + value is prev_value + (10 - prev_value) * 0.3 + prev_value is value + + if converged: + print of "Converged at iteration:" + print of counter + break + + if stable: + print of "Stable at iteration:" + print of counter + +print of "" +print of "=== Final Metrics ===" +print of "Framework strength:" +fs is framework_strength +print of fs + +print of "Signature:" +sig is signature +print of sig + +print of "System stable:" +print of stable +""", + "interrogatives": """# Interrogatives Demo +# Self-aware code that can query its own execution + +define analyze as: + print of "WHO am I?" + print of WHO + + print of "WHAT is being computed?" + print of WHAT + + print of "WHERE in execution?" + print of WHERE + + return n * 2 + +print of "Running analysis..." +result is analyze of 21 + +print of "Result:" +print of result + +print of "Final framework strength:" +print of framework_strength +""", + "meta_eval": """# Meta-Circular Evaluation +# EigenScript can evaluate itself! + +define identity as: + return n + +define apply_twice as: + first is identity of n + second is identity of first + return second + +print of "Testing self-reference stability..." + +val is 42 +r1 is identity of val +r2 is identity of r1 +r3 is identity of r2 + +print of "Original:" +print of val +print of "After 3 identity applications:" +print of r3 + +print of "Apply twice:" +result is apply_twice of 21 +print of result + +print of "System remains stable:" +print of stable + +print of "Converged (fixed point):" +print of converged """ } @@ -160,6 +298,7 @@ def index(): @app.route('/run', methods=['POST']) def run_code(): code = request.json.get('code', '') + mode = request.json.get('mode', 'interpret') # 'interpret' or 'compile' if not code.strip(): return jsonify({'error': 'No code provided', 'output': ''}) @@ -169,12 +308,22 @@ def run_code(): temp_path = f.name try: - result = subprocess.run( - ['eigenscript', temp_path], - capture_output=True, - text=True, - timeout=30 - ) + if mode == 'compile': + # Use the compiler to generate LLVM IR + result = subprocess.run( + ['eigenscript-compile', temp_path, '-o', '-'], + capture_output=True, + text=True, + timeout=60 + ) + else: + # Use the interpreter + result = subprocess.run( + ['eigenscript', temp_path], + capture_output=True, + text=True, + timeout=30 + ) output = result.stdout error = result.stderr @@ -191,8 +340,14 @@ def run_code(): }) except subprocess.TimeoutExpired: + timeout = 60 if mode == 'compile' else 30 return jsonify({ - 'error': 'Execution timed out (30s limit)', + 'error': f'Execution timed out ({timeout}s limit)', + 'output': '' + }) + except FileNotFoundError as e: + return jsonify({ + 'error': f'Command not found: {str(e)}. Is EigenScript installed?', 'output': '' }) except Exception as e: @@ -201,7 +356,8 @@ def run_code(): 'output': '' }) finally: - os.unlink(temp_path) + if os.path.exists(temp_path): + os.unlink(temp_path) @app.route('/examples/') @@ -211,5 +367,11 @@ def get_example(name): return jsonify({'error': 'Example not found'}), 404 +@app.route('/health') +def health(): + """Health check endpoint for deployment platforms""" + return jsonify({'status': 'ok', 'version': '0.4.1'}) + + if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000) diff --git a/web/replit.nix b/web/replit.nix new file mode 100644 index 0000000..75d331e --- /dev/null +++ b/web/replit.nix @@ -0,0 +1,12 @@ +{ pkgs }: { + deps = [ + pkgs.python311 + pkgs.python311Packages.pip + pkgs.python311Packages.flask + pkgs.python311Packages.gunicorn + pkgs.python311Packages.numpy + pkgs.llvmPackages_15.llvm + pkgs.clang_15 + pkgs.gcc + ]; +} diff --git a/web/requirements.txt b/web/requirements.txt index 560e9e3..278a572 100644 --- a/web/requirements.txt +++ b/web/requirements.txt @@ -1,3 +1,5 @@ flask>=2.0.0 gunicorn>=21.0.0 -eigenscript>=0.4.1 +numpy>=1.24.0 +llvmlite>=0.41.0 +eigenscript[compiler]>=0.4.1 diff --git a/web/templates/index.html b/web/templates/index.html index 5204026..225563e 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -9,8 +9,9 @@ --bg-dark: #1a1a2e; --bg-panel: #16213e; --bg-editor: #0f0f23; - --accent: #e94560; - --accent-hover: #ff6b6b; + --accent: #00d9ff; + --accent-hover: #00fff7; + --accent-secondary: #e94560; --text: #eee; --text-dim: #888; --success: #4ade80; @@ -49,15 +50,16 @@ } .logo-icon { - width: 32px; - height: 32px; - background: linear-gradient(135deg, var(--accent), #ff9a56); + width: 36px; + height: 36px; + background: linear-gradient(135deg, var(--accent), var(--accent-secondary)); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; - font-size: 18px; + font-size: 20px; + color: #fff; } .logo h1 { @@ -65,16 +67,27 @@ font-weight: 600; } - .logo span { + .logo h1 span { color: var(--accent); } - .version { + .header-right { + display: flex; + align-items: center; + gap: 1.5rem; + } + + .version-badge { font-size: 0.75rem; color: var(--text-dim); background: var(--bg-dark); - padding: 0.25rem 0.5rem; - border-radius: 4px; + padding: 0.25rem 0.75rem; + border-radius: 12px; + border: 1px solid var(--border); + } + + .version-badge strong { + color: var(--success); } .status { @@ -93,6 +106,11 @@ animation: pulse 2s infinite; } + .status-dot.running { + background: var(--accent); + animation: pulse 0.5s infinite; + } + @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } @@ -100,15 +118,16 @@ main { flex: 1; - display: flex; + display: grid; + grid-template-columns: 1fr 1fr; overflow: hidden; } .panel { - flex: 1; display: flex; flex-direction: column; border-right: 1px solid var(--border); + overflow: hidden; } .panel:last-child { @@ -122,6 +141,7 @@ justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); + flex-shrink: 0; } .panel-title { @@ -135,6 +155,7 @@ .toolbar { display: flex; gap: 0.5rem; + flex-wrap: wrap; } select, button { @@ -152,14 +173,21 @@ border-color: var(--accent); } + select:focus, button:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 2px rgba(0, 217, 255, 0.2); + } + button.primary { - background: var(--accent); + background: linear-gradient(135deg, var(--accent), #0099cc); border-color: var(--accent); font-weight: 600; + color: #000; } button.primary:hover { - background: var(--accent-hover); + background: linear-gradient(135deg, var(--accent-hover), var(--accent)); } button:disabled { @@ -170,6 +198,7 @@ .editor-container { flex: 1; position: relative; + overflow: hidden; } #code { @@ -184,6 +213,7 @@ line-height: 1.6; resize: none; outline: none; + tab-size: 4; } #code::placeholder { @@ -202,6 +232,7 @@ font-size: 14px; line-height: 1.6; white-space: pre-wrap; + word-wrap: break-word; min-height: 100%; } @@ -227,6 +258,7 @@ border-top: 1px solid var(--border); font-size: 0.75rem; color: var(--text-dim); + flex-shrink: 0; } .stats { @@ -247,24 +279,37 @@ color: var(--text); } - a { + .links a { color: var(--accent); text-decoration: none; + margin-left: 1rem; } - a:hover { + .links a:hover { text-decoration: underline; } - @media (max-width: 768px) { + @media (max-width: 900px) { main { - flex-direction: column; + grid-template-columns: 1fr; + grid-template-rows: 1fr 1fr; } .panel { border-right: none; border-bottom: 1px solid var(--border); } + + header { + padding: 0.75rem 1rem; + flex-wrap: wrap; + gap: 0.5rem; + } + + .toolbar { + width: 100%; + justify-content: flex-start; + } } @@ -272,12 +317,14 @@
-
-
- Ready +
+ v0.4.1 — Fixpoint Bootstrap +
+
+ Ready +
@@ -291,10 +338,13 @@

EigenScript Playground

- + + + + @@ -319,7 +369,9 @@

EigenScript Playground

-
Output will appear here...
+
Output will appear here... + +Press Ctrl+Enter or click Run to execute your code.
@@ -335,10 +387,9 @@

EigenScript Playground

- -
+ @@ -348,6 +399,8 @@

EigenScript Playground

const runBtn = document.getElementById('runBtn'); const lineCount = document.getElementById('lineCount'); const execTime = document.getElementById('execTime'); + const statusDot = document.getElementById('statusDot'); + const statusText = document.getElementById('statusText'); // Update line count on input codeEditor.addEventListener('input', updateLineCount); @@ -358,6 +411,16 @@

EigenScript Playground

lineCount.textContent = lines; } + function setStatus(status) { + if (status === 'running') { + statusDot.classList.add('running'); + statusText.textContent = 'Running...'; + } else { + statusDot.classList.remove('running'); + statusText.textContent = 'Ready'; + } + } + async function runCode() { const code = codeEditor.value; if (!code.trim()) { @@ -367,6 +430,7 @@

EigenScript Playground

runBtn.disabled = true; runBtn.textContent = 'Running...'; + setStatus('running'); outputDiv.className = ''; outputDiv.textContent = 'Executing...'; @@ -381,7 +445,7 @@

EigenScript Playground

const result = await response.json(); const elapsed = performance.now() - startTime; - execTime.textContent = `${elapsed.toFixed(0)}ms`; + execTime.textContent = `${(elapsed / 1000).toFixed(2)}s`; if (result.error) { showOutput(result.error + (result.output ? '\n\n' + result.output : ''), true); @@ -393,6 +457,7 @@

EigenScript Playground

} finally { runBtn.disabled = false; runBtn.innerHTML = '▶ Run'; + setStatus('ready'); } } @@ -410,6 +475,7 @@

EigenScript Playground

if (result.code) { codeEditor.value = result.code; updateLineCount(); + clearOutput(); } } catch (err) { console.error('Failed to load example:', err); @@ -424,7 +490,7 @@

EigenScript Playground

} function clearOutput() { - outputDiv.innerHTML = 'Output will appear here...'; + outputDiv.innerHTML = 'Output will appear here...\n\nPress Ctrl+Enter or click Run to execute your code.'; outputDiv.className = ''; execTime.textContent = '-'; } @@ -435,6 +501,14 @@

EigenScript Playground

e.preventDefault(); runCode(); } + // Tab handling for indentation + if (e.key === 'Tab') { + e.preventDefault(); + const start = codeEditor.selectionStart; + const end = codeEditor.selectionEnd; + codeEditor.value = codeEditor.value.substring(0, start) + ' ' + codeEditor.value.substring(end); + codeEditor.selectionStart = codeEditor.selectionEnd = start + 4; + } }); From f5241d4a58c5a24b0d19eda52084b964521fdb6b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 5 Dec 2025 09:59:53 +0000 Subject: [PATCH 3/3] Fix CodeQL security warnings in web playground - Remove hardcoded debug=True, use FLASK_DEBUG env var instead - Sanitize exception messages to prevent information exposure --- web/app.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/app.py b/web/app.py index bfa170e..fad11c7 100644 --- a/web/app.py +++ b/web/app.py @@ -345,14 +345,14 @@ def run_code(): 'error': f'Execution timed out ({timeout}s limit)', 'output': '' }) - except FileNotFoundError as e: + except FileNotFoundError: return jsonify({ - 'error': f'Command not found: {str(e)}. Is EigenScript installed?', + 'error': 'EigenScript interpreter not found. Please check installation.', 'output': '' }) - except Exception as e: + except Exception: return jsonify({ - 'error': str(e), + 'error': 'An unexpected error occurred during execution.', 'output': '' }) finally: @@ -374,4 +374,5 @@ def health(): if __name__ == '__main__': - app.run(debug=True, host='0.0.0.0', port=5000) + debug_mode = os.environ.get('FLASK_DEBUG', 'false').lower() == 'true' + app.run(debug=debug_mode, host='0.0.0.0', port=5000)