From 5bad08723d205e7e13f90b278437085fa3dad07c Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 12 Apr 2026 19:19:36 -0700 Subject: [PATCH] Replace WebSocket with SSE, move live scripts into skill (self-contained) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two architectural changes that make the live variant mode self-contained: 1. SSE replaces WebSocket: the server now uses Server-Sent Events for server→browser push and regular fetch POST for browser→server events. This eliminates the ws npm dependency entirely. The live server is now zero-dependency pure Node.js (http, crypto, fs, net). Browser: EventSource replaces WebSocket. sendEvent() uses fetch POST. Server: GET /events returns SSE stream, POST /events receives browser events. All other endpoints (poll, source, health, stop) unchanged. 2. Scripts moved to source/skills/impeccable/scripts/: live-server.mjs, live-poll.mjs, live-wrap.mjs, live-browser.js are now part of the skill itself. Users who install the skill via npx skills get the live mode without needing npm install impeccable separately. The skill reference uses {{scripts_path}}/live-server.mjs etc. The CLI (bin/cli.js) delegates to the skill scripts as a convenience. Removed ws from package.json dependencies. The old src/live/ files remain as the development copy. The build system syncs source/skills/ to all harness dirs (11 providers). Co-Authored-By: Claude Opus 4.6 (1M context) --- .agents/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .claude/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .codex/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .cursor/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .gemini/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .kiro/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .kiro/skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .kiro/skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .opencode/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .pi/skills/impeccable/reference/live.md | 18 +- .pi/skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .pi/skills/impeccable/scripts/live-poll.mjs | 123 ++ .pi/skills/impeccable/scripts/live-server.mjs | 416 ++++++ .pi/skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .rovodev/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .trae-cn/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ .trae/skills/impeccable/reference/live.md | 18 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .trae/skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .trae/skills/impeccable/scripts/live-wrap.mjs | 298 ++++ bin/cli.js | 8 +- package.json | 3 +- source/skills/impeccable/reference/live.md | 14 +- .../skills/impeccable/scripts/live-browser.js | 1220 +++++++++++++++++ .../skills/impeccable/scripts/live-poll.mjs | 123 ++ .../skills/impeccable/scripts/live-server.mjs | 416 ++++++ .../skills/impeccable/scripts/live-wrap.mjs | 298 ++++ src/live/browser.js | 47 +- 63 files changed, 24842 insertions(+), 112 deletions(-) create mode 100644 .agents/skills/impeccable/scripts/live-browser.js create mode 100644 .agents/skills/impeccable/scripts/live-poll.mjs create mode 100644 .agents/skills/impeccable/scripts/live-server.mjs create mode 100644 .agents/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .claude/skills/impeccable/scripts/live-browser.js create mode 100644 .claude/skills/impeccable/scripts/live-poll.mjs create mode 100644 .claude/skills/impeccable/scripts/live-server.mjs create mode 100644 .claude/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .codex/skills/impeccable/scripts/live-browser.js create mode 100644 .codex/skills/impeccable/scripts/live-poll.mjs create mode 100644 .codex/skills/impeccable/scripts/live-server.mjs create mode 100644 .codex/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .cursor/skills/impeccable/scripts/live-browser.js create mode 100644 .cursor/skills/impeccable/scripts/live-poll.mjs create mode 100644 .cursor/skills/impeccable/scripts/live-server.mjs create mode 100644 .cursor/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .gemini/skills/impeccable/scripts/live-browser.js create mode 100644 .gemini/skills/impeccable/scripts/live-poll.mjs create mode 100644 .gemini/skills/impeccable/scripts/live-server.mjs create mode 100644 .gemini/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .kiro/skills/impeccable/scripts/live-browser.js create mode 100644 .kiro/skills/impeccable/scripts/live-poll.mjs create mode 100644 .kiro/skills/impeccable/scripts/live-server.mjs create mode 100644 .kiro/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .opencode/skills/impeccable/scripts/live-browser.js create mode 100644 .opencode/skills/impeccable/scripts/live-poll.mjs create mode 100644 .opencode/skills/impeccable/scripts/live-server.mjs create mode 100644 .opencode/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .pi/skills/impeccable/scripts/live-browser.js create mode 100644 .pi/skills/impeccable/scripts/live-poll.mjs create mode 100644 .pi/skills/impeccable/scripts/live-server.mjs create mode 100644 .pi/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .rovodev/skills/impeccable/scripts/live-browser.js create mode 100644 .rovodev/skills/impeccable/scripts/live-poll.mjs create mode 100644 .rovodev/skills/impeccable/scripts/live-server.mjs create mode 100644 .rovodev/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .trae-cn/skills/impeccable/scripts/live-browser.js create mode 100644 .trae-cn/skills/impeccable/scripts/live-poll.mjs create mode 100644 .trae-cn/skills/impeccable/scripts/live-server.mjs create mode 100644 .trae-cn/skills/impeccable/scripts/live-wrap.mjs create mode 100644 .trae/skills/impeccable/scripts/live-browser.js create mode 100644 .trae/skills/impeccable/scripts/live-poll.mjs create mode 100644 .trae/skills/impeccable/scripts/live-server.mjs create mode 100644 .trae/skills/impeccable/scripts/live-wrap.mjs create mode 100644 source/skills/impeccable/scripts/live-browser.js create mode 100644 source/skills/impeccable/scripts/live-poll.mjs create mode 100644 source/skills/impeccable/scripts/live-server.mjs create mode 100644 source/skills/impeccable/scripts/live-wrap.mjs diff --git a/.agents/skills/impeccable/reference/live.md b/.agents/skills/impeccable/reference/live.md index 53b64a21a..ba0e9b0c5 100644 --- a/.agents/skills/impeccable/reference/live.md +++ b/.agents/skills/impeccable/reference/live.md @@ -10,7 +10,7 @@ Launch interactive live variant mode: select elements in the browser, pick a des 1. Read `.impeccable.md` if it exists. Keep the design context in mind for variant generation. 2. Start the live variant server: ```bash - npx impeccable live & + node {{scripts_path}}/live-server.mjs & ``` 3. Note the **port** and **token** printed to stdout. @@ -53,7 +53,7 @@ Run a blocking poll loop. On each iteration, wait for a browser event and respon ``` LOOP: - Run: npx impeccable poll + Run: node {{scripts_path}}/live-poll.mjs Read the JSON output. Dispatch based on the "type" field: TYPE "generate": @@ -85,7 +85,7 @@ The event contains: `{id, action, freeformPrompt, count, pageUrl, element}`. Use the `wrap` helper to find the element and create the variant container: ```bash -npx impeccable wrap --id EVENT_ID --count EVENT_COUNT --element-id "ELEMENT_ID" --classes "class1,class2" --tag "div" +node {{scripts_path}}/live-wrap.mjs --id EVENT_ID --count EVENT_COUNT --element-id "ELEMENT_ID" --classes "class1,class2" --tag "div" ``` Pass the element's id (`event.element.id`), classes (`event.element.classes` joined with commas), and tag name. The command searches in priority order: ID match first, then class names, then tag+class combo. If `event.pageUrl` hints at the file (e.g., `/` is usually `index.html`), pass `--file PATH` to skip the search. @@ -136,10 +136,14 @@ The first variant should NOT have `style="display: none"` (it should be visible ### Step 3: Signal completion +Include `--file` so the browser can fetch variants directly if the dev server lacks HMR: + ```bash -npx impeccable poll --reply EVENT_ID done +node {{scripts_path}}/live-poll.mjs --reply EVENT_ID done --file RELATIVE_PATH ``` +The file path should be relative to the project root (e.g., `public/index.html`, `src/App.tsx`). + ## Handle Accept The event contains: `{id, variantId}`. @@ -151,7 +155,7 @@ The user accepted a specific variant. For v1 (inspection mode): 4. Remove any scoped CSS blocks (between `impeccable-variants-css-start` and `impeccable-variants-css-end` markers). 5. Reply: ```bash - npx impeccable poll --reply SESSION_ID done + node {{scripts_path}}/live-poll.mjs --reply SESSION_ID done ``` ## Handle Discard @@ -163,7 +167,7 @@ The event contains: `{id}`. 3. Remove any scoped CSS blocks for this session. 4. Reply: ```bash - npx impeccable poll --reply SESSION_ID done + node {{scripts_path}}/live-poll.mjs --reply SESSION_ID done ``` ## Cleanup (on exit) @@ -174,7 +178,7 @@ When the loop ends: 2. **Remove any leftover variant wrappers** (search for `impeccable-variants-start` markers and clean up). 3. **Stop the server**: ```bash - npx impeccable live stop + node {{scripts_path}}/live-server.mjs stop ``` ## Variant Generation Guidelines diff --git a/.agents/skills/impeccable/scripts/live-browser.js b/.agents/skills/impeccable/scripts/live-browser.js new file mode 100644 index 000000000..7a26c9829 --- /dev/null +++ b/.agents/skills/impeccable/scripts/live-browser.js @@ -0,0 +1,1220 @@ +/** + * Impeccable Live Variant Mode — Browser Script + * + * Injected into the user's page via