From cfd6ec12b3016e6d2a1085fcfbb9801bd657f388 Mon Sep 17 00:00:00 2001 From: Cloverings1 Date: Tue, 9 Jun 2026 15:50:04 -0500 Subject: [PATCH] Render office-hours sketches over localhost --- office-hours/SKILL.md | 28 ++++++++++++++++++++++++---- scripts/resolvers/design.ts | 29 ++++++++++++++++++++++++----- test/skill-validation.test.ts | 6 ++++++ 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 3562f17f6..dd2df9090 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -1513,12 +1513,32 @@ SKETCH_FILE="/tmp/gstack-sketch-$(date +%s).html" **Step 3: Render and capture** ```bash -$B goto "file://$SKETCH_FILE" -$B screenshot /tmp/gstack-sketch.png +if [ -n "$B" ] && [ -x "$B" ] && command -v python3 >/dev/null 2>&1; then + SKETCH_DIR=$(dirname "$SKETCH_FILE") + SKETCH_NAME=$(basename "$SKETCH_FILE") + SKETCH_PORT=$(python3 - <<'PY' +import socket +s = socket.socket() +s.bind(("127.0.0.1", 0)) +print(s.getsockname()[1]) +s.close() +PY +) + (cd "$SKETCH_DIR" && python3 -m http.server "$SKETCH_PORT" --bind 127.0.0.1 >/tmp/gstack-sketch-http.log 2>&1) & + SKETCH_HTTP_PID=$! + sleep 1 + if ! $B goto "http://127.0.0.1:$SKETCH_PORT/$SKETCH_NAME" || ! $B screenshot /tmp/gstack-sketch.png; then + echo "Visual sketch render failed while serving $SKETCH_FILE over localhost. The HTML file is still available for manual inspection." + fi + kill "$SKETCH_HTTP_PID" 2>/dev/null || true + wait "$SKETCH_HTTP_PID" 2>/dev/null || true +else + echo "Visual sketch rendering requires the browse binary and python3 for the local HTTP server. Run setup for browse, or install python3, then retry." +fi ``` -If `$B` is not available (browse binary not set up), skip the render step. Tell the -user: "Visual sketch requires the browse binary. Run the setup script to enable it." +Do not use `file://` for the render path. The browse binary blocks local file +navigation, so serve the generated HTML over `127.0.0.1` as shown above. **Step 4: Present and iterate** diff --git a/scripts/resolvers/design.ts b/scripts/resolvers/design.ts index 9f31b3619..88146ae60 100644 --- a/scripts/resolvers/design.ts +++ b/scripts/resolvers/design.ts @@ -487,12 +487,32 @@ SKETCH_FILE="/tmp/gstack-sketch-$(date +%s).html" **Step 3: Render and capture** \`\`\`bash -$B goto "file://$SKETCH_FILE" -$B screenshot /tmp/gstack-sketch.png +if [ -n "$B" ] && [ -x "$B" ] && command -v python3 >/dev/null 2>&1; then + SKETCH_DIR=$(dirname "$SKETCH_FILE") + SKETCH_NAME=$(basename "$SKETCH_FILE") + SKETCH_PORT=$(python3 - <<'PY' +import socket +s = socket.socket() +s.bind(("127.0.0.1", 0)) +print(s.getsockname()[1]) +s.close() +PY +) + (cd "$SKETCH_DIR" && python3 -m http.server "$SKETCH_PORT" --bind 127.0.0.1 >/tmp/gstack-sketch-http.log 2>&1) & + SKETCH_HTTP_PID=$! + sleep 1 + if ! $B goto "http://127.0.0.1:$SKETCH_PORT/$SKETCH_NAME" || ! $B screenshot /tmp/gstack-sketch.png; then + echo "Visual sketch render failed while serving $SKETCH_FILE over localhost. The HTML file is still available for manual inspection." + fi + kill "$SKETCH_HTTP_PID" 2>/dev/null || true + wait "$SKETCH_HTTP_PID" 2>/dev/null || true +else + echo "Visual sketch rendering requires the browse binary and python3 for the local HTTP server. Run setup for browse, or install python3, then retry." +fi \`\`\` -If \`$B\` is not available (browse binary not set up), skip the render step. Tell the -user: "Visual sketch requires the browse binary. Run the setup script to enable it." +Do not use \`file://\` for the render path. The browse binary blocks local file +navigation, so serve the generated HTML over \`127.0.0.1\` as shown above. **Step 4: Present and iterate** @@ -1154,4 +1174,3 @@ Flat design can strip away useful visual information that signals interactivity. Prioritize ruthlessly: things needed in a hurry go close at hand, everything else a few taps away with an obvious path to get there.`; } - diff --git a/test/skill-validation.test.ts b/test/skill-validation.test.ts index fb1ec5bf4..96c3ed094 100644 --- a/test/skill-validation.test.ts +++ b/test/skill-validation.test.ts @@ -756,6 +756,12 @@ describe('office-hours skill structure', () => { expect(content).toContain('$B screenshot'); }); + test('renders sketch through localhost instead of file URLs', () => { + expect(content).toContain('python3 -m http.server'); + expect(content).toContain('http://127.0.0.1:$SKETCH_PORT/$SKETCH_NAME'); + expect(content).not.toContain('file://$SKETCH_FILE'); + }); + test('contains rough aesthetic instruction', () => { expect(content).toMatch(/rough|hand-drawn/i); });