Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. Setup (non-optional) Before any design work or file edits, pass these gates. Skipping them produces generic output that ignores the project. | Gate | Required check | If fail | |---|---|---| | Context | The PRODUCT.md / DESIGN.md loader result is known from . | Run the loader before continuing. | | Product | PRODUCT.md exists and is not empty or placeholder ( markers, <200 chars). | Run , refresh context, then resume. Never synthesize PRODUCT.md from the user's original p…

);\n}\n\n// ---------------------------------------------------------------------------\n// Core operations\n// ---------------------------------------------------------------------------\n\nfunction validateConfig(cfg) {\n if (!cfg || typeof cfg !== 'object') throw new Error('config.json must be an object');\n if (!Array.isArray(cfg.files) || cfg.files.length === 0) {\n throw new Error('config.files (non-empty string array) required');\n }\n if (!cfg.files.every((f) => typeof f === 'string' && f.length > 0)) {\n throw new Error('config.files must contain only non-empty strings');\n }\n if (cfg.exclude !== undefined) {\n if (!Array.isArray(cfg.exclude)) {\n throw new Error('config.exclude, if present, must be a string array');\n }\n if (!cfg.exclude.every((f) => typeof f === 'string' && f.length > 0)) {\n throw new Error('config.exclude must contain only non-empty strings');\n }\n }\n if (typeof cfg.insertBefore !== 'string' && typeof cfg.insertAfter !== 'string') {\n throw new Error('config.insertBefore or config.insertAfter (string) required');\n }\n if (cfg.commentSyntax !== 'html' && cfg.commentSyntax !== 'jsx') {\n throw new Error(\"config.commentSyntax must be 'html' or 'jsx'\");\n }\n if (cfg.cspChecked !== undefined && typeof cfg.cspChecked !== 'boolean') {\n throw new Error(\"config.cspChecked, if present, must be a boolean\");\n }\n}\n\nfunction commentOpen(syntax) { return syntax === 'jsx' ? '{/*' : '\u003c!--'; }\nfunction commentClose(syntax) { return syntax === 'jsx' ? '*/}' : '-->'; }\n\nfunction buildTagBlock(syntax, port) {\n const open = commentOpen(syntax);\n const close = commentClose(syntax);\n return (\n open + ' ' + MARKER_OPEN_TEXT + ' ' + close + '\\n' +\n '\u003cscript src=\"http://localhost:' + port + '/live.js\">\u003c/script>\\n' +\n open + ' ' + MARKER_CLOSE_TEXT + ' ' + close + '\\n'\n );\n}\n\nfunction insertTag(content, config, port) {\n const block = buildTagBlock(config.commentSyntax, port);\n // insertBefore: match the LAST occurrence. Anchors like `\u003c/body>` naturally\n // belong at the end, and the same literal can appear earlier in code blocks\n // within rendered documentation pages.\n if (config.insertBefore) {\n const idx = content.lastIndexOf(config.insertBefore);\n if (idx === -1) return content;\n return content.slice(0, idx) + block + content.slice(idx);\n }\n // insertAfter: match the FIRST occurrence — typical anchors like `\u003chead>` or\n // `\u003cbody>` open near the top of the document.\n const idx = content.indexOf(config.insertAfter);\n if (idx === -1) return content;\n const after = idx + config.insertAfter.length;\n // Preserve a single trailing newline if the anchor didn't end with one\n const prefix = content[after] === '\\n' ? content.slice(0, after + 1) : content.slice(0, after) + '\\n';\n return prefix + block + content.slice(prefix.length);\n}\n\n/**\n * Remove the live script block. Matches either HTML or JSX comment markers\n * regardless of config (so stale tags from a wrong config can still be cleaned).\n *\n * Indent-preserving: captures any whitespace immediately preceding the opener\n * marker and re-emits it in place of the removed block. `insertTag` inserted\n * the block *after* the original line's indent and *before* the anchor (e.g.\n * `\u003c/body>`), which moved the indent onto the opener line and left the anchor\n * unindented. Replacing the whole block (plus its trailing newline) with just\n * the captured indent hands the indent back to the anchor that follows.\n */\nfunction removeTag(content, _syntax) {\n const patterns = [\n /([ \\t]*)\u003c!--\\s*impeccable-live-start\\s*-->[\\s\\S]*?\u003c!--\\s*impeccable-live-end\\s*-->[ \\t]*\\n/,\n /([ \\t]*)\\{\\/\\*\\s*impeccable-live-start\\s*\\*\\/\\}[\\s\\S]*?\\{\\/\\*\\s*impeccable-live-end\\s*\\*\\/\\}[ \\t]*\\n/,\n ];\n for (const pat of patterns) {\n const next = content.replace(pat, '$1');\n if (next !== content) return next;\n }\n return content;\n}\n\n// ---------------------------------------------------------------------------\n// Content-Security-Policy meta-tag patcher\n//\n// When the user's HTML carries `\u003cmeta http-equiv=\"Content-Security-Policy\">`,\n// the cross-origin load of /live.js (and the SSE/POST connection back to\n// localhost:PORT) is blocked unless the CSP explicitly allows that origin.\n//\n// On insert: append `http://localhost:PORT` to `script-src` and `connect-src`,\n// and stash the original `content` value in a `data-impeccable-csp-original`\n// attribute (base64) so revert is exact.\n//\n// On remove: detect the marker attribute, decode it, restore the original\n// content value verbatim, drop the marker.\n//\n// Header-based CSP (Next.js headers, Nuxt routeRules, SvelteKit kit.csp,\n// shared helpers) is NOT patched here — those need framework-specific config\n// edits and are handled via the existing detect-csp.mjs reference output.\n// Only the in-source meta-tag form gets the auto-patch.\n// ---------------------------------------------------------------------------\n\nconst CSP_MARKER_ATTR = 'data-impeccable-csp-original';\n\nfunction findCspMetaTags(content) {\n const out = [];\n const tagRe = /\u003cmeta\\s+([^>]*?)\\/?>/gis;\n let m;\n while ((m = tagRe.exec(content)) !== null) {\n const attrs = m[1];\n if (!/(http-equiv|httpEquiv)\\s*=\\s*(['\"])Content-Security-Policy\\2/i.test(attrs)) continue;\n out.push({ start: m.index, end: m.index + m[0].length, full: m[0], attrs });\n }\n return out;\n}\n\nfunction getAttr(attrs, name) {\n const re = new RegExp(`\\\\b${name}\\\\s*=\\\\s*(['\"])([\\\\s\\\\S]*?)\\\\1`, 'i');\n const m = attrs.match(re);\n return m ? { quote: m[1], value: m[2], full: m[0] } : null;\n}\n\nfunction appendOriginToDirective(csp, directive, origin) {\n const re = new RegExp(`(^|;)(\\\\s*)(${directive})\\\\s+([^;]*)`, 'i');\n const m = csp.match(re);\n if (m) {\n const tokens = m[4].trim().split(/\\s+/);\n if (tokens.includes(origin)) return csp;\n return csp.replace(re, `${m[1]}${m[2]}${m[3]} ${[...tokens, origin].join(' ')}`);\n }\n // Directive missing — add it. Use 'self' + origin so we don't inadvertently\n // narrow the policy compared to the default-src fallback (most users with\n // an explicit CSP have 'self' there).\n return csp.trim().replace(/;?\\s*$/, '') + `; ${directive} 'self' ${origin}`;\n}\n\nexport function patchCspMeta(content, port) {\n const tags = findCspMetaTags(content);\n if (tags.length === 0) return content;\n const origin = `http://localhost:${port}`;\n\n // Walk last-to-first so prior splices don't invalidate later indices.\n let result = content;\n for (let i = tags.length - 1; i >= 0; i--) {\n const tag = tags[i];\n const attrs = tag.attrs;\n if (getAttr(attrs, CSP_MARKER_ATTR)) continue; // already patched\n const contentAttr = getAttr(attrs, 'content');\n if (!contentAttr) continue;\n\n const original = contentAttr.value;\n let patched = original;\n patched = appendOriginToDirective(patched, 'script-src', origin);\n patched = appendOriginToDirective(patched, 'connect-src', origin);\n // The shader overlay during 'generating' creates a screenshot via\n // URL.createObjectURL, producing a `blob:` URL — img-src 'self' rejects\n // those. Add `blob:` so the overlay doesn't throw a CSP violation.\n patched = appendOriginToDirective(patched, 'img-src', 'blob:');\n if (patched === original) continue;\n\n const newContentAttr = `content=${contentAttr.quote}${patched}${contentAttr.quote}`;\n const marker = `${CSP_MARKER_ATTR}=\"${Buffer.from(original, 'utf-8').toString('base64')}\"`;\n // The tagRe captures any whitespace between the last attribute and the\n // closing `/>` as part of `attrs`. Naively appending ` ${marker}` after\n // a replace would land it BEFORE that trailing space, leaving a double\n // space inside attrs and clobbering the space before `/>`. Split off\n // the trailing whitespace, splice the marker into the attribute body,\n // and re-append the original trailing whitespace so a self-closing\n // `\u003cmeta … />` round-trips byte-for-byte.\n const trailingWs = (attrs.match(/[ \\t]*$/) || [''])[0];\n const attrsBody = attrs.slice(0, attrs.length - trailingWs.length);\n const newAttrs = attrsBody.replace(contentAttr.full, newContentAttr) + ' ' + marker + trailingWs;\n const newTag = tag.full.replace(attrs, newAttrs);\n\n result = result.slice(0, tag.start) + newTag + result.slice(tag.end);\n }\n return result;\n}\n\nexport function revertCspMeta(content) {\n const tags = findCspMetaTags(content);\n if (tags.length === 0) return content;\n\n let result = content;\n for (let i = tags.length - 1; i >= 0; i--) {\n const tag = tags[i];\n const origAttr = getAttr(tag.attrs, CSP_MARKER_ATTR);\n if (!origAttr) continue;\n const contentAttr = getAttr(tag.attrs, 'content');\n if (!contentAttr) continue;\n\n let originalValue;\n try { originalValue = Buffer.from(origAttr.value, 'base64').toString('utf-8'); }\n catch { continue; }\n\n const newContentAttr = `content=${contentAttr.quote}${originalValue}${contentAttr.quote}`;\n let newAttrs = tag.attrs.replace(contentAttr.full, newContentAttr);\n // Drop the marker attribute and any single space immediately preceding it.\n newAttrs = newAttrs.replace(new RegExp(`\\\\s*${origAttr.full}`), '');\n const newTag = tag.full.replace(tag.attrs, newAttrs);\n\n result = result.slice(0, tag.start) + newTag + result.slice(tag.end);\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Auto-execute\n// ---------------------------------------------------------------------------\n\nconst _running = process.argv[1];\nif (_running?.endsWith('live-inject.mjs') || _running?.endsWith('live-inject.mjs/')) {\n injectCli();\n}\n\nexport { insertTag, removeTag, validateConfig, buildTagBlock };\n// patchCspMeta + revertCspMeta are exported above where they're defined.\n","content_type":"text/javascript","language":"javascript","size":17402,"content_sha256":"f4d9dfba7cb9350b5e298c8ed6cb4ee46473483644f873fb87181ea07babf06c"},{"filename":"scripts/live-poll.mjs","content":"/**\n * CLI client for the live variant mode poll/reply protocol.\n *\n * Usage:\n * npx impeccable poll # Block until browser event, print JSON\n * npx impeccable poll --timeout=600000 # Custom timeout (ms); default is long-poll friendly\n * npx impeccable poll --reply \u003cid> done # Reply \"done\" to event \u003cid>\n * npx impeccable poll --reply \u003cid> error \"msg\" # Reply with error\n */\n\nimport { execFileSync } from 'node:child_process';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { completionAckForAcceptResult, completionTypeForAcceptResult } from './live-completion.mjs';\nimport { readLiveServerInfo } from './impeccable-paths.mjs';\n\n// Node's built-in fetch (undici under the hood) enforces a 300s headers\n// timeout that can't be lowered per-request. We cap each request below\n// that ceiling and loop in `pollOnce` to synthesize a long poll without\n// depending on the standalone undici package.\nconst PER_REQUEST_TIMEOUT_MS = 270_000;\n\nfunction readServerInfo() {\n const record = readLiveServerInfo(process.cwd());\n if (!record) {\n console.error('No running live server found. Start one with: npx impeccable live');\n process.exit(1);\n }\n return record.info;\n}\n\nexport function buildPollReplyPayload(token, { id, type, message, file, data }) {\n return { token, id, type, message, file, data };\n}\n\nasync function postReply(base, token, reply) {\n const res = await fetch(`${base}/poll`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(buildPollReplyPayload(token, reply)),\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(body.error || res.statusText);\n }\n}\n\nexport async function pollCli() {\n const args = process.argv.slice(2);\n\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: impeccable poll [options]\n\nWait for a browser event from the live variant server, or reply to one.\n\nModes:\n poll Block until a browser event arrives, print JSON\n poll --reply \u003cid> done Reply \"done\" to event \u003cid>\n poll --reply \u003cid> error \"msg\" Reply with an error message\n\nOptions:\n --timeout=MS Long-poll timeout in ms (default: 600000). Use the default unless the user asked to pause live; never use a short timeout to end the chat turn\n --help Show this help message`);\n process.exit(0);\n }\n\n const info = readServerInfo();\n const base = `http://localhost:${info.port}`;\n\n // Reply mode: npx impeccable poll --reply \u003cid> \u003cstatus> [--file path] [message]\n const replyIdx = args.indexOf('--reply');\n if (replyIdx !== -1) {\n const id = args[replyIdx + 1];\n const status = args[replyIdx + 2] || 'done';\n const fileIdx = args.indexOf('--file');\n const filePath = fileIdx !== -1 && fileIdx + 1 \u003c args.length ? args[fileIdx + 1] : undefined;\n // Message is any remaining positional arg that isn't a flag\n const message = args.find((a, i) => i > replyIdx + 2 && !a.startsWith('--') && i !== fileIdx + 1) || undefined;\n\n if (!id) {\n console.error('Usage: npx impeccable poll --reply \u003cid> \u003cstatus> [--file path] [message]');\n process.exit(1);\n }\n\n try {\n await postReply(base, info.token, { id, type: status, message, file: filePath });\n\n // Success — silent exit (agent doesn't need output for replies)\n } catch (err) {\n if (err.cause?.code === 'ECONNREFUSED') {\n console.error('Live server not running. Start one with: npx impeccable live');\n } else {\n console.error('Reply failed:', err.message);\n }\n process.exit(1);\n }\n return;\n }\n\n // Poll mode: block until browser event. Default 10 min. Node's built-in\n // fetch enforces a 300s headers timeout, so we loop in slices under that\n // ceiling and keep re-polling until we get a real event or the user's\n // total timeout runs out.\n const timeoutArg = args.find(a => a.startsWith('--timeout='));\n const totalTimeout = timeoutArg ? parseInt(timeoutArg.split('=')[1], 10) : 600000;\n\n const deadline = Date.now() + totalTimeout;\n let event;\n try {\n while (true) {\n const remaining = deadline - Date.now();\n if (remaining \u003c= 0) {\n event = { type: 'timeout' };\n break;\n }\n const slice = Math.min(remaining, PER_REQUEST_TIMEOUT_MS);\n const res = await fetch(`${base}/poll?token=${info.token}&timeout=${slice}`);\n\n if (res.status === 401) {\n console.error('Authentication failed. The server token may have changed.');\n console.error('Try restarting: npx impeccable live stop && npx impeccable live');\n process.exit(1);\n }\n\n if (!res.ok) {\n console.error(`Poll failed: ${res.status} ${res.statusText}`);\n process.exit(1);\n }\n\n const next = await res.json();\n // Server-side timeout means no browser event arrived in this slice.\n // Loop and re-poll until we get a real event or we hit the user's\n // total deadline.\n if (next?.type === 'timeout' && Date.now() \u003c deadline) continue;\n event = next;\n break;\n }\n\n // Auto-handle accept/discard via deterministic script\n if (event.type === 'accept' || event.type === 'discard') {\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const acceptScript = path.join(__dirname, 'live-accept.mjs');\n const scriptArgs = event.type === 'discard'\n ? ['--id', event.id, '--discard']\n : ['--id', event.id, '--variant', event.variantId];\n if (event.type === 'accept' && event.paramValues && Object.keys(event.paramValues).length > 0) {\n scriptArgs.push('--param-values', JSON.stringify(event.paramValues));\n }\n try {\n const out = execFileSync(\n 'node',\n [acceptScript, ...scriptArgs],\n { encoding: 'utf-8', cwd: process.cwd(), timeout: 30_000 }\n );\n event._acceptResult = JSON.parse(out.trim());\n } catch (err) {\n event._acceptResult = { handled: false, mode: 'error', error: err.message };\n }\n\n const completionType = completionTypeForAcceptResult(event.type, event._acceptResult);\n try {\n await postReply(base, info.token, {\n id: event.id,\n type: completionType,\n message: event._acceptResult?.error,\n file: event._acceptResult?.file,\n data: event._acceptResult?.carbonize === true ? { carbonize: true } : undefined,\n });\n } catch (err) {\n event._completionAck = { ok: false, error: err.message };\n }\n if (!event._completionAck) {\n event._completionAck = completionAckForAcceptResult(event.id, completionType, event._acceptResult);\n }\n }\n\n // Second signal path: stderr banner in case the agent parses stdout\n // JSON but skips nested fields. One line is enough — the full checklist\n // is in reference/live.md.\n if (event._acceptResult?.carbonize === true) {\n process.stderr.write('\\n⚠ Carbonize cleanup REQUIRED before next poll. After cleanup, run live-complete.mjs --id ' + event.id + '. See reference/live.md \"Required after accept\".\\n\\n');\n }\n\n // Print the event as JSON — the agent reads this from stdout\n console.log(JSON.stringify(event));\n } catch (err) {\n if (err.cause?.code === 'ECONNREFUSED') {\n console.error('Live server not running. Start one with: npx impeccable live');\n } else {\n console.error('Poll failed:', err.message);\n }\n process.exit(1);\n }\n}\n\n// Auto-execute when run directly\nconst _running = process.argv[1];\nif (_running?.endsWith('live-poll.mjs') || _running?.endsWith('live-poll.mjs/')) {\n pollCli();\n}\n","content_type":"text/javascript","language":"javascript","size":7710,"content_sha256":"02910a4d3547ca685198df4940f08f6b69efbcdb7633206c16f256ff54ae478e"},{"filename":"scripts/live-resume.mjs","content":"#!/usr/bin/env node\n/**\n * Recover the next agent action from the durable live-session journal.\n */\n\nimport { createLiveSessionStore } from './live-session-store.mjs';\n\nfunction parseArgs(argv) {\n const out = { id: null };\n for (let i = 0; i \u003c argv.length; i++) {\n const arg = argv[i];\n if (arg === '--id') out.id = argv[++i];\n else if (arg.startsWith('--id=')) out.id = arg.slice('--id='.length);\n else if (arg === '--help' || arg === '-h') out.help = true;\n }\n return out;\n}\n\nexport async function resumeCli() {\n const args = parseArgs(process.argv.slice(2));\n if (args.help) {\n console.log(`Usage: node live-resume.mjs [--id SESSION_ID]\\n\\nPrint the active durable session checkpoint and the next safe agent action.`);\n return;\n }\n\n const store = createLiveSessionStore({ cwd: process.cwd(), sessionId: args.id || undefined });\n const snapshot = args.id ? store.getSnapshot(args.id) : store.listActiveSessions()[0] || null;\n if (!snapshot) {\n console.log(JSON.stringify({ active: false, nextAction: 'No active durable live session found.' }, null, 2));\n return;\n }\n\n const pending = snapshot.pendingEvent || null;\n const nextAction = pending\n ? `Run live-poll.mjs, handle ${pending.type} ${pending.id}, then acknowledge with live-poll.mjs --reply ${pending.id} done.`\n : snapshot.phase === 'carbonize_required'\n ? `Finish carbonize cleanup${snapshot.sourceFile ? ` in ${snapshot.sourceFile}` : ''}, then run live-complete.mjs --id ${snapshot.id}.`\n : snapshot.phase === 'accept_requested'\n ? `Run live-complete.mjs --id ${snapshot.id} after verifying the accepted variant is written.`\n : `Inspect ${snapshot.id}; no pending agent event is currently queued.`;\n\n console.log(JSON.stringify({ active: true, snapshot, pendingEvent: pending, nextAction }, null, 2));\n}\n\nconst _running = process.argv[1];\nif (_running?.endsWith('live-resume.mjs') || _running?.endsWith('live-resume.mjs/')) {\n resumeCli();\n}\n","content_type":"text/javascript","language":"javascript","size":1974,"content_sha256":"741b6799a406b835ccaffb396d6c12109ee596659eb751d2e8865b4fc5a08e3f"},{"filename":"scripts/live-server.mjs","content":"#!/usr/bin/env node\n/**\n * Live variant mode server (self-contained, zero dependencies).\n *\n * Serves the browser script (/live.js), the detection overlay (/detect.js),\n * uses Server-Sent Events (SSE) for server→browser push, and HTTP POST for\n * browser→server events. Agent communicates via HTTP long-poll (/poll).\n *\n * Usage:\n * node \u003cscripts_path>/live-server.mjs # start\n * node \u003cscripts_path>/live-server.mjs stop # stop + remove injected live.js tag\n * node \u003cscripts_path>/live-server.mjs stop --keep-inject # stop only\n * node \u003cscripts_path>/live-server.mjs --help\n */\n\nimport http from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { spawn, execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport net from 'node:net';\nimport { fileURLToPath } from 'node:url';\nimport { parseDesignMd } from './design-parser.mjs';\nimport { resolveContextDir } from './load-context.mjs';\nimport { createLiveSessionStore } from './live-session-store.mjs';\nimport {\n getDesignSidecarPath,\n getLiveAnnotationsDir,\n readLiveServerInfo,\n removeLiveServerInfo,\n resolveDesignSidecarPath,\n writeLiveServerInfo,\n} from './impeccable-paths.mjs';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n// PRODUCT.md / DESIGN.md live wherever load-context.mjs resolves. The generated\n// DESIGN sidecar is project-local at .impeccable/design.json, with legacy\n// DESIGN.json fallback for existing projects.\nconst CONTEXT_DIR = resolveContextDir(process.cwd());\nconst DEFAULT_POLL_TIMEOUT = 600_000; // 10 min — agent re-polls on timeout anyway\nconst SSE_HEARTBEAT_INTERVAL = 30_000; // keepalive ping every 30s\n\n// ---------------------------------------------------------------------------\n// Port detection\n// ---------------------------------------------------------------------------\n\nasync function findOpenPort(start = 8400) {\n return new Promise((resolve) => {\n const srv = net.createServer();\n srv.listen(start, '127.0.0.1', () => {\n const port = srv.address().port;\n srv.close(() => resolve(port));\n });\n srv.on('error', () => resolve(findOpenPort(start + 1)));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Session state\n// ---------------------------------------------------------------------------\n\nconst state = {\n token: null,\n port: null,\n sseClients: new Set(), // SSE response objects (server→browser push)\n pendingEvents: [], // browser events waiting for agent ack ({ event, leaseUntil })\n pendingPolls: [], // agent poll callbacks waiting for browser events\n exitTimer: null,\n sessionDir: null, // per-session tmp dir for annotation screenshots\n sessionStore: null,\n leaseTimer: null,\n};\n\n// Cap per-annotation upload size. A full 1920×1080 PNG is typically \u003c1 MB;\n// cap at 10 MB to guard against runaway writes from a misbehaving client.\nconst MAX_ANNOTATION_BYTES = 10 * 1024 * 1024;\n\nfunction enqueueEvent(event) {\n if (!event || (event.id && state.pendingEvents.some((entry) => entry.event?.id === event.id && entry.event?.type === event.type))) return;\n state.pendingEvents.push({ event, leaseUntil: 0 });\n flushPendingPolls();\n}\n\nfunction restorePendingEventsFromStore() {\n if (!state.sessionStore) return;\n for (const snapshot of state.sessionStore.listActiveSessions()) {\n if (snapshot.pendingEvent) enqueueEvent(snapshot.pendingEvent);\n }\n}\n\nfunction findAvailablePendingEvent(now = Date.now()) {\n return state.pendingEvents.find((entry) => !entry.leaseUntil || entry.leaseUntil \u003c= now);\n}\n\nfunction leaseEvent(entry, leaseMs) {\n if (!entry.event?.id) {\n const idx = state.pendingEvents.indexOf(entry);\n if (idx !== -1) state.pendingEvents.splice(idx, 1);\n return entry.event;\n }\n entry.leaseUntil = Date.now() + leaseMs;\n return entry.event;\n}\n\nfunction acknowledgePendingEvent(id) {\n if (!id) return false;\n const idx = state.pendingEvents.findIndex((entry) => entry.event?.id === id);\n if (idx === -1) return false;\n state.pendingEvents.splice(idx, 1);\n scheduleLeaseFlush();\n return true;\n}\n\nfunction scheduleLeaseFlush() {\n if (state.leaseTimer) {\n clearTimeout(state.leaseTimer);\n state.leaseTimer = null;\n }\n if (state.pendingPolls.length === 0) return;\n const now = Date.now();\n const nextLeaseUntil = state.pendingEvents\n .map((entry) => entry.leaseUntil || 0)\n .filter((leaseUntil) => leaseUntil > now)\n .sort((a, b) => a - b)[0];\n if (!nextLeaseUntil) return;\n state.leaseTimer = setTimeout(() => {\n state.leaseTimer = null;\n flushPendingPolls();\n }, Math.max(0, nextLeaseUntil - now));\n}\n\nfunction flushPendingPolls() {\n while (state.pendingPolls.length > 0) {\n const entry = findAvailablePendingEvent();\n if (!entry) {\n scheduleLeaseFlush();\n return;\n }\n const poll = state.pendingPolls.shift();\n poll.resolve(leaseEvent(entry, poll.leaseMs));\n }\n scheduleLeaseFlush();\n}\n\n/** Push a message to all connected SSE clients. */\nfunction broadcast(msg) {\n const data = 'data: ' + JSON.stringify(msg) + '\\n\\n';\n for (const res of state.sseClients) {\n try { res.write(data); } catch { /* client gone */ }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Load scripts\n// ---------------------------------------------------------------------------\n\nfunction loadBrowserScripts() {\n // Detection script: look relative to the skill scripts dir, then fall back\n // to the npm package location (cli/engine/detect-antipatterns-browser.js).\n // This one IS cached — detect.js rarely changes during a session.\n const detectPaths = [\n path.join(__dirname, '..', '..', '..', '..', 'cli', 'engine', 'detect-antipatterns-browser.js'),\n path.join(process.cwd(), 'node_modules', 'impeccable', 'cli', 'engine', 'detect-antipatterns-browser.js'),\n ];\n let detectScript = '';\n for (const p of detectPaths) {\n try { detectScript = fs.readFileSync(p, 'utf-8'); break; } catch { /* try next */ }\n }\n\n // live-browser.js: DO NOT cache. Return the path so the /live.js handler\n // can re-read on every request. Editing the browser script during iteration\n // should land on the next tab reload, not require a server restart.\n const sessionPath = path.join(__dirname, 'live-browser-session.js');\n const livePath = path.join(__dirname, 'live-browser.js');\n for (const p of [sessionPath, livePath]) {\n if (!fs.existsSync(p)) {\n process.stderr.write('Error: live browser script not found at ' + p + '\\n');\n process.exit(1);\n }\n }\n\n return { detectScript, sessionPath, livePath };\n}\n\nfunction hasProjectContext() {\n // PRODUCT.md carries brand voice / anti-references — that's what determines\n // whether variants are brand-aware. DESIGN.md (visual tokens) is a separate\n // concern, surfaced by the design panel's own empty state. Legacy\n // .impeccable.md is auto-migrated to PRODUCT.md by load-context.mjs.\n try {\n fs.accessSync(path.join(CONTEXT_DIR, 'PRODUCT.md'), fs.constants.R_OK);\n return true;\n } catch { return false; }\n}\n\nfunction statOrNull(filePath) {\n try { return fs.statSync(filePath); } catch { return null; }\n}\n\n// ---------------------------------------------------------------------------\n// Validation (inline — no external import needed for self-contained script)\n// ---------------------------------------------------------------------------\n\nconst VISUAL_ACTIONS = [\n 'impeccable', 'bolder', 'quieter', 'distill', 'polish', 'typeset',\n 'colorize', 'layout', 'adapt', 'animate', 'delight', 'overdrive',\n];\n\n// Browser generates ids via crypto.randomUUID().slice(0, 8) (8 hex chars)\n// and variantIds via String(small integer). Restrict to those shapes so\n// any value that reaches a downstream child_process or DOM selector is\n// inert by construction.\nconst ID_PATTERN = /^[0-9a-f]{8}$/;\nconst VARIANT_ID_PATTERN = /^[0-9]{1,3}$/;\n\nfunction isValidId(v) { return typeof v === 'string' && ID_PATTERN.test(v); }\nfunction isValidVariantId(v) { return typeof v === 'string' && VARIANT_ID_PATTERN.test(v); }\n\nfunction validateEvent(msg) {\n if (!msg || typeof msg !== 'object' || !msg.type) return 'Missing or invalid message';\n switch (msg.type) {\n case 'generate':\n if (!isValidId(msg.id)) return 'generate: missing or malformed id';\n if (!msg.action || !VISUAL_ACTIONS.includes(msg.action)) return 'generate: invalid action';\n if (!Number.isInteger(msg.count) || msg.count \u003c 1 || msg.count > 8) return 'generate: count must be 1-8';\n if (!msg.element || !msg.element.outerHTML) return 'generate: missing element context';\n // Optional annotation fields (all-or-nothing: if any present, all must be well-formed).\n if (msg.screenshotPath !== undefined && typeof msg.screenshotPath !== 'string') return 'generate: screenshotPath must be string';\n if (msg.comments !== undefined && !Array.isArray(msg.comments)) return 'generate: comments must be array';\n if (msg.strokes !== undefined && !Array.isArray(msg.strokes)) return 'generate: strokes must be array';\n return null;\n case 'accept':\n if (!isValidId(msg.id)) return 'accept: missing or malformed id';\n if (!isValidVariantId(msg.variantId)) return 'accept: missing or malformed variantId';\n if (msg.paramValues !== undefined) {\n if (typeof msg.paramValues !== 'object' || msg.paramValues === null || Array.isArray(msg.paramValues)) {\n return 'accept: paramValues must be an object';\n }\n }\n return null;\n case 'discard':\n return isValidId(msg.id) ? null : 'discard: missing or malformed id';\n case 'checkpoint':\n if (!isValidId(msg.id)) return 'checkpoint: missing or malformed id';\n if (!Number.isInteger(msg.revision) || msg.revision \u003c 0) return 'checkpoint: revision must be a non-negative integer';\n if (msg.paramValues !== undefined && (typeof msg.paramValues !== 'object' || msg.paramValues === null || Array.isArray(msg.paramValues))) {\n return 'checkpoint: paramValues must be an object';\n }\n return null;\n case 'exit':\n return null;\n case 'prefetch':\n if (!msg.pageUrl || typeof msg.pageUrl !== 'string') return 'prefetch: missing pageUrl';\n return null;\n default:\n return 'Unknown event type: ' + msg.type;\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP request handler\n// ---------------------------------------------------------------------------\n\nfunction createRequestHandler({ detectScript, sessionPath, livePath }) {\n return (req, res) => {\n const url = new URL(req.url, `http://localhost:${state.port}`);\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; }\n\n const p = url.pathname;\n\n // --- Scripts ---\n if (p === '/live.js') {\n // Re-read from disk each request so edits to live-browser.js land on\n // the next tab reload. No-store headers prevent browser caching across\n // sessions — during iteration, a cached old script silently breaks\n // every subsequent session.\n let sessionScript;\n let liveScript;\n try {\n sessionScript = fs.readFileSync(sessionPath, 'utf-8');\n liveScript = fs.readFileSync(livePath, 'utf-8');\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'text/plain' });\n res.end('Error reading live browser scripts: ' + err.message);\n return;\n }\n const body =\n `window.__IMPECCABLE_TOKEN__ = '${state.token}';\\n` +\n `window.__IMPECCABLE_PORT__ = ${state.port};\\n` +\n sessionScript + '\\n' +\n liveScript;\n res.writeHead(200, {\n 'Content-Type': 'application/javascript',\n 'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',\n 'Pragma': 'no-cache',\n });\n res.end(body);\n return;\n }\n if (p === '/detect.js' || p === '/') {\n if (!detectScript) { res.writeHead(404); res.end('Not available'); return; }\n res.writeHead(200, { 'Content-Type': 'application/javascript' });\n res.end(detectScript);\n return;\n }\n\n // --- Vendored modern-screenshot (UMD build) ---\n // Lazy-loaded by live.js when the user clicks Go; exposes\n // window.modernScreenshot.domToBlob(...) for capture.\n if (p === '/modern-screenshot.js') {\n const vendorPath = path.join(__dirname, 'modern-screenshot.umd.js');\n try {\n res.writeHead(200, {\n 'Content-Type': 'application/javascript',\n 'Cache-Control': 'public, max-age=31536000, immutable',\n });\n res.end(fs.readFileSync(vendorPath));\n } catch {\n res.writeHead(404); res.end('Vendor script not found');\n }\n return;\n }\n\n // --- Annotation upload (browser → server, raw PNG body) ---\n // Client generates the eventId, POSTs the PNG, then POSTs the generate\n // event with screenshotPath already set. Keeps bytes out of the SSE/poll\n // bridge and preserves the \"one shot from the user's POV\" UX.\n if (p === '/annotation' && req.method === 'POST') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401); res.end('Unauthorized'); return; }\n const eventId = url.searchParams.get('eventId');\n if (!eventId || !/^[A-Za-z0-9_-]{1,64}$/.test(eventId)) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid eventId' }));\n return;\n }\n if ((req.headers['content-type'] || '').toLowerCase() !== 'image/png') {\n res.writeHead(415, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Content-Type must be image/png' }));\n return;\n }\n if (!state.sessionDir) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session dir unavailable' }));\n return;\n }\n const chunks = [];\n let total = 0;\n let aborted = false;\n req.on('data', (c) => {\n if (aborted) return;\n total += c.length;\n if (total > MAX_ANNOTATION_BYTES) {\n aborted = true;\n res.writeHead(413, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Payload too large' }));\n req.destroy();\n return;\n }\n chunks.push(c);\n });\n req.on('end', () => {\n if (aborted) return;\n const absPath = path.join(state.sessionDir, eventId + '.png');\n try {\n fs.writeFileSync(absPath, Buffer.concat(chunks));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Write failed: ' + err.message }));\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, path: absPath }));\n });\n req.on('error', () => {\n if (!aborted) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Upload failed' }));\n }\n });\n return;\n }\n\n // --- Health ---\n if (p === '/status') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Unauthorized' })); return; }\n const sessions = state.sessionStore ? state.sessionStore.listActiveSessions() : [];\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n status: 'ok',\n port: state.port,\n connectedClients: state.sseClients.size,\n pendingEvents: state.pendingEvents.map((entry) => ({\n id: entry.event?.id,\n type: entry.event?.type,\n leased: !!(entry.leaseUntil && entry.leaseUntil > Date.now()),\n leaseUntil: entry.leaseUntil || null,\n })),\n activeSessions: sessions,\n }));\n return;\n }\n\n if (p === '/health') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n status: 'ok', port: state.port, mode: 'variant',\n hasProjectContext: hasProjectContext(),\n connectedClients: state.sseClients.size,\n }));\n return;\n }\n\n // --- Design system (unified v2 response) + raw ---\n // /design-system.json returns both parsed DESIGN.md and .impeccable/design.json\n // sidecar when present. Panel merges them:\n // { present, parsed, sidecar, hasMd, hasSidecar,\n // mdNewerThanJson, parseError?, sidecarError? }\n // - parsed: output of parseDesignMd (frontmatter\n // + six canonical sections) when DESIGN.md exists.\n // - sidecar: .impeccable/design.json contents when present.\n // Expected shape: schemaVersion 2, carrying\n // extensions + components + narrative.\n // /design-system/raw returns DESIGN.md markdown verbatim\n if (p === '/design-system.json' || p === '/design-system/raw') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401); res.end('Unauthorized'); return; }\n\n const mdPath = path.join(CONTEXT_DIR, 'DESIGN.md');\n const jsonPath = resolveDesignSidecarPath(process.cwd(), CONTEXT_DIR) || getDesignSidecarPath(process.cwd());\n const mdStat = statOrNull(mdPath);\n const jsonStat = statOrNull(jsonPath);\n\n if (p === '/design-system/raw') {\n if (!mdStat) { res.writeHead(404); res.end('Not found'); return; }\n res.writeHead(200, { 'Content-Type': 'text/markdown; charset=utf-8' });\n res.end(fs.readFileSync(mdPath, 'utf-8'));\n return;\n }\n\n if (!mdStat && !jsonStat) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ present: false }));\n return;\n }\n\n const response = {\n present: true,\n hasMd: !!mdStat,\n hasSidecar: !!jsonStat,\n mdNewerThanJson: !!(mdStat && jsonStat && mdStat.mtimeMs > jsonStat.mtimeMs + 1000),\n };\n\n if (mdStat) {\n try {\n response.parsed = parseDesignMd(fs.readFileSync(mdPath, 'utf-8'));\n } catch (err) {\n response.parseError = err.message;\n }\n }\n\n if (jsonStat) {\n try {\n response.sidecar = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));\n } catch (err) {\n response.sidecarError = 'Failed to parse .impeccable/design.json: ' + err.message;\n }\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(response));\n return;\n }\n\n // --- Source file (no-HMR fallback) ---\n if (p === '/source') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401); res.end('Unauthorized'); return; }\n const filePath = url.searchParams.get('path');\n if (!filePath || filePath.includes('..')) { res.writeHead(400); res.end('Bad path'); return; }\n const absPath = path.resolve(process.cwd(), filePath);\n if (!absPath.startsWith(process.cwd())) { res.writeHead(403); res.end('Forbidden'); return; }\n let content;\n try { content = fs.readFileSync(absPath, 'utf-8'); }\n catch { res.writeHead(404); res.end('File not found'); return; }\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(content);\n return;\n }\n\n // --- SSE: server→browser push (replaces WebSocket) ---\n if (p === '/events' && req.method === 'GET') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401); res.end('Unauthorized'); return; }\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n res.write('data: ' + JSON.stringify({\n type: 'connected',\n hasProjectContext: hasProjectContext(),\n }) + '\\n\\n');\n\n state.sseClients.add(res);\n clearTimeout(state.exitTimer);\n\n // Keepalive: SSE comment every 30s prevents silent connection drops.\n const heartbeat = setInterval(() => {\n try { res.write(': keepalive\\n\\n'); } catch { clearInterval(heartbeat); }\n }, SSE_HEARTBEAT_INTERVAL);\n\n req.on('close', () => {\n clearInterval(heartbeat);\n state.sseClients.delete(res);\n if (state.sseClients.size === 0) {\n clearTimeout(state.exitTimer);\n state.exitTimer = setTimeout(() => {\n if (state.sseClients.size === 0) enqueueEvent({ type: 'exit' });\n }, 8000);\n }\n });\n return;\n }\n\n // --- Browser→server events (replaces WebSocket messages) ---\n if (p === '/events' && req.method === 'POST') {\n let body = '';\n req.on('data', (c) => { body += c; });\n req.on('end', () => {\n let msg;\n try { msg = JSON.parse(body); } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid JSON' }));\n return;\n }\n if (msg.token !== state.token) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n const error = validateEvent(msg);\n if (error) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error }));\n return;\n }\n if (state.sessionStore && msg.id) {\n try {\n state.sessionStore.appendEvent(msg);\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'session_store_append_failed', message: err.message }));\n return;\n }\n }\n if (msg.type !== 'checkpoint') enqueueEvent(msg);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n });\n return;\n }\n\n // --- Stop ---\n if (p === '/stop') {\n const token = url.searchParams.get('token');\n if (token !== state.token) { res.writeHead(401); res.end('Unauthorized'); return; }\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end('stopping');\n shutdown();\n return;\n }\n\n // --- Agent poll ---\n if (p === '/poll' && req.method === 'GET') {\n handlePollGet(req, res, url);\n return;\n }\n if (p === '/poll' && req.method === 'POST') {\n handlePollPost(req, res);\n return;\n }\n\n res.writeHead(404); res.end('Not found');\n };\n}\n\n// ---------------------------------------------------------------------------\n// Agent poll endpoints (unchanged from WS version)\n// ---------------------------------------------------------------------------\n\nfunction handlePollGet(req, res, url) {\n const token = url.searchParams.get('token');\n if (token !== state.token) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n const timeout = parseInt(url.searchParams.get('timeout') || DEFAULT_POLL_TIMEOUT, 10);\n const leaseMs = parseInt(url.searchParams.get('leaseMs') || '30000', 10);\n const available = findAvailablePendingEvent();\n if (available) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(leaseEvent(available, leaseMs)));\n return;\n }\n const poll = { resolve, leaseMs };\n const timer = setTimeout(() => {\n const idx = state.pendingPolls.indexOf(poll);\n if (idx !== -1) state.pendingPolls.splice(idx, 1);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ type: 'timeout' }));\n }, timeout);\n function resolve(event) {\n clearTimeout(timer);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(event));\n }\n state.pendingPolls.push(poll);\n scheduleLeaseFlush();\n req.on('close', () => {\n clearTimeout(timer);\n const idx = state.pendingPolls.indexOf(poll);\n if (idx !== -1) state.pendingPolls.splice(idx, 1);\n });\n}\n\nfunction handlePollPost(req, res) {\n let body = '';\n req.on('data', (c) => { body += c; });\n req.on('end', () => {\n let msg;\n try { msg = JSON.parse(body); } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid JSON' }));\n return;\n }\n if (msg.token !== state.token) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n acknowledgePendingEvent(msg.id);\n if (state.sessionStore && msg.id) {\n try {\n const eventType = msg.type === 'discard' || msg.type === 'discarded'\n ? 'discarded'\n : msg.type === 'complete'\n ? 'complete'\n : msg.type === 'error'\n ? 'agent_error'\n : 'agent_done';\n state.sessionStore.appendEvent({\n type: eventType,\n id: msg.id,\n file: msg.file,\n message: msg.message,\n carbonize: msg.data?.carbonize === true,\n });\n } catch { /* keep reply path best-effort; browser still needs SSE */ }\n }\n flushPendingPolls();\n // Forward the reply to the browser via SSE\n broadcast({ type: msg.type || 'done', id: msg.id, message: msg.message, file: msg.file, data: msg.data });\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true }));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Lifecycle\n// ---------------------------------------------------------------------------\n\nlet httpServer = null;\n\nfunction shutdown() {\n removeLiveServerInfo(process.cwd());\n if (state.leaseTimer) clearTimeout(state.leaseTimer);\n state.leaseTimer = null;\n if (state.sessionDir) {\n try { fs.rmSync(state.sessionDir, { recursive: true, force: true }); } catch {}\n }\n for (const res of state.sseClients) { try { res.end(); } catch {} }\n state.sseClients.clear();\n for (const poll of state.pendingPolls) poll.resolve({ type: 'exit' });\n state.pendingPolls.length = 0;\n if (httpServer) httpServer.close();\n process.exit(0);\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nconst args = process.argv.slice(2);\n\nif (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: node live-server.mjs [options]\n\nStart the live variant mode server (zero dependencies).\n\nCommands:\n (default) Start the server (foreground)\n stop Stop the server and remove the injected live.js script tag\n stop --keep-inject Stop the server only (leave the script tag in the HTML entry)\n\nOptions:\n --background Start detached, print connection JSON to stdout, then exit\n --port=PORT Use a specific port (default: auto-detect starting at 8400)\n --keep-inject Only with stop: skip live-inject.mjs --remove\n --help Show this help\n\nEndpoints:\n /live.js Browser script (element picker + variant cycling)\n /detect.js Detection overlay (backwards compatible)\n /modern-screenshot.js Vendored modern-screenshot UMD build (lazy-loaded by live.js)\n /annotation POST raw image/png to stage a variant screenshot\n /events SSE stream (server→browser) + POST (browser→server)\n /poll Long-poll for agent CLI\n /source Raw source file reader (no-HMR fallback)\n /status Durable recovery status (token-protected)\n /health Health check`);\n process.exit(0);\n}\n\nif (args.includes('stop')) {\n const keepInject = args.includes('--keep-inject');\n try {\n const { info } = readLiveServerInfo(process.cwd()) || {};\n const res = await fetch(`http://localhost:${info.port}/stop?token=${info.token}`);\n if (res.ok) console.log(`Stopped live server on port ${info.port}.`);\n } catch {\n console.log('No running live server found.');\n }\n if (!keepInject) {\n const injectPath = path.join(__dirname, 'live-inject.mjs');\n try {\n const out = execFileSync(process.execPath, [injectPath, '--remove'], {\n encoding: 'utf-8',\n cwd: process.cwd(),\n });\n const line = out.trim().split('\\n').filter(Boolean).pop();\n if (line) {\n try {\n const j = JSON.parse(line);\n if (j.removed === true) {\n console.log(`Removed live script tag from ${j.file}.`);\n }\n } catch {\n /* ignore non-JSON lines */\n }\n }\n } catch (err) {\n const detail = err.stderr?.toString?.().trim?.()\n || err.stdout?.toString?.().trim?.()\n || err.message\n || String(err);\n console.warn(`Note: could not remove live script tag (${detail.split('\\n')[0]})`);\n }\n }\n process.exit(0);\n}\n\n// --background: spawn a detached child server, wait for it to be ready,\n// print the connection JSON, then exit. This keeps the startup command\n// simple (no shell backgrounding or chained commands).\nif (args.includes('--background')) {\n const childArgs = args.filter(a => a !== '--background');\n const child = spawn(process.execPath, [fileURLToPath(import.meta.url), ...childArgs], {\n detached: true,\n stdio: 'ignore',\n cwd: process.cwd(),\n });\n child.unref();\n\n // Poll for the PID file (the child writes it once the HTTP server is listening).\n const deadline = Date.now() + 10_000;\n while (Date.now() \u003c deadline) {\n try {\n const { info } = readLiveServerInfo(process.cwd()) || {};\n if (info.pid !== process.pid) {\n // Output JSON so the agent can read port + token from stdout.\n console.log(JSON.stringify(info));\n process.exit(0);\n }\n } catch { /* not ready yet */ }\n await new Promise(r => setTimeout(r, 200));\n }\n console.error('Timed out waiting for live server to start.');\n process.exit(1);\n}\n\n// Check for existing session\nconst existingRecord = readLiveServerInfo(process.cwd());\nif (existingRecord?.info) {\n const existing = existingRecord.info;\n try {\n process.kill(existing.pid, 0);\n console.error(`Live server already running on port ${existing.port} (pid ${existing.pid}).`);\n console.error('Stop it first with: node ' + path.basename(fileURLToPath(import.meta.url)) + ' stop');\n process.exit(1);\n } catch {\n try { fs.unlinkSync(existingRecord.path); } catch {}\n }\n}\n\nstate.token = randomUUID();\nstate.sessionStore = createLiveSessionStore({ cwd: process.cwd() });\nrestorePendingEventsFromStore();\nconst portArg = args.find(a => a.startsWith('--port='));\nstate.port = portArg ? parseInt(portArg.split('=')[1], 10) : await findOpenPort();\n// Annotation screenshots live in the project root so the agent's Read tool\n// doesn't trip a per-file permission prompt. Sessioned by token so concurrent\n// projects (or quick restarts) don't collide.\nconst annotRoot = getLiveAnnotationsDir(process.cwd());\nfs.mkdirSync(annotRoot, { recursive: true });\nstate.sessionDir = fs.mkdtempSync(path.join(annotRoot, 'session-'));\n\nconst { detectScript, sessionPath, livePath } = loadBrowserScripts();\nhttpServer = http.createServer(createRequestHandler({ detectScript, sessionPath, livePath }));\n\nhttpServer.listen(state.port, '127.0.0.1', () => {\n writeLiveServerInfo(process.cwd(), { pid: process.pid, port: state.port, token: state.token });\n const url = `http://localhost:${state.port}`;\n console.log(`\\nImpeccable live server running on ${url}`);\n console.log(`Token: ${state.token}\\n`);\n console.log(`Inject: \u003cscript src=\"${url}/live.js\">\u003c\\/script>`);\n console.log(`Stop: node ${path.basename(fileURLToPath(import.meta.url))} stop`);\n});\n\nprocess.on('SIGINT', shutdown);\nprocess.on('SIGTERM', shutdown);\n","content_type":"text/javascript","language":"javascript","size":32452,"content_sha256":"8db37f313b421f1a167e682fba8a64c49dd383bf8fac43da8d9db650efe89c27"},{"filename":"scripts/live-session-store.mjs","content":"import fs from 'node:fs';\nimport path from 'node:path';\nimport { getLegacyLiveSessionsDir, getLiveSessionsDir } from './impeccable-paths.mjs';\n\nconst COMPLETED_PHASES = new Set(['completed', 'discarded']);\n\nexport function createLiveSessionStore({ cwd = process.cwd(), sessionId } = {}) {\n const rootDir = getLiveSessionsDir(cwd);\n const legacyRootDir = getLegacyLiveSessionsDir(cwd);\n fs.mkdirSync(rootDir, { recursive: true });\n const snapshotCache = new Map();\n\n function loadCachedOrRebuild(id) {\n const cached = snapshotCache.get(id);\n if (cached) return cached;\n const journalPath = getReadableJournalPath(id);\n const rebuilt = rebuildSnapshotFromJournal(journalPath, id);\n snapshotCache.set(id, rebuilt);\n return rebuilt;\n }\n\n function getReadableJournalPath(id) {\n const primary = getJournalPath(rootDir, id);\n if (fs.existsSync(primary)) return primary;\n const legacy = getJournalPath(legacyRootDir, id);\n if (fs.existsSync(legacy)) return legacy;\n return primary;\n }\n\n return {\n rootDir,\n legacyRootDir,\n appendEvent(event) {\n const normalized = normalizeEvent(event, sessionId);\n const journalPath = getJournalPath(rootDir, normalized.id);\n const snapshotPath = getSnapshotPath(rootDir, normalized.id);\n const legacyJournalPath = getJournalPath(legacyRootDir, normalized.id);\n if (!fs.existsSync(journalPath) && fs.existsSync(legacyJournalPath)) {\n fs.copyFileSync(legacyJournalPath, journalPath);\n }\n const prior = loadCachedOrRebuild(normalized.id);\n const seq = prior.nextSeq;\n const entry = {\n seq,\n id: normalized.id,\n type: normalized.type,\n ts: new Date().toISOString(),\n event: normalized,\n };\n fs.appendFileSync(journalPath, JSON.stringify(entry) + '\\n');\n const next = applyEvent(prior.snapshot, entry, prior.diagnostics);\n snapshotCache.set(normalized.id, { snapshot: next, diagnostics: next.diagnostics || [], nextSeq: seq + 1 });\n writeSnapshot(snapshotPath, next);\n return next;\n },\n getSnapshot(id = sessionId, opts = {}) {\n if (!id) throw new Error('session id required');\n const journalPath = getReadableJournalPath(id);\n const snapshotPath = getSnapshotPath(rootDir, id);\n const rebuilt = rebuildSnapshotFromJournal(journalPath, id);\n snapshotCache.set(id, rebuilt);\n writeSnapshot(snapshotPath, rebuilt.snapshot);\n if (!opts.includeCompleted && COMPLETED_PHASES.has(rebuilt.snapshot.phase)) return null;\n return rebuilt.snapshot;\n },\n listActiveSessions() {\n const ids = new Set();\n for (const dir of [legacyRootDir, rootDir]) {\n if (!fs.existsSync(dir)) continue;\n for (const name of fs.readdirSync(dir)) {\n if (name.endsWith('.jsonl')) ids.add(name.slice(0, -'.jsonl'.length));\n }\n }\n return [...ids]\n .sort()\n .map((id) => this.getSnapshot(id))\n .filter(Boolean);\n },\n };\n}\n\nfunction normalizeEvent(event, fallbackId) {\n if (!event || typeof event !== 'object') throw new Error('event object required');\n const id = event.id || fallbackId;\n if (!id || typeof id !== 'string') throw new Error('event id required');\n if (!event.type || typeof event.type !== 'string') throw new Error('event type required');\n return { ...event, id };\n}\n\nfunction getJournalPath(rootDir, id) {\n return path.join(rootDir, safeSessionId(id) + '.jsonl');\n}\n\nfunction getSnapshotPath(rootDir, id) {\n return path.join(rootDir, safeSessionId(id) + '.snapshot.json');\n}\n\nfunction safeSessionId(id) {\n if (!/^[A-Za-z0-9_-]{1,128}$/.test(id)) throw new Error('invalid session id: ' + id);\n return id;\n}\n\nfunction baseSnapshot(id) {\n return {\n id,\n phase: 'new',\n pageUrl: null,\n sourceFile: null,\n expectedVariants: 0,\n arrivedVariants: 0,\n visibleVariant: null,\n paramValues: {},\n pendingEventSeq: null,\n pendingEvent: null,\n deliveryLease: null,\n checkpointRevision: 0,\n activeOwner: null,\n sourceMarkers: {},\n fallbackMode: null,\n annotationArtifacts: [],\n diagnostics: [],\n updatedAt: null,\n };\n}\n\nfunction rebuildSnapshotFromJournal(journalPath, id) {\n let snapshot = baseSnapshot(id);\n const diagnostics = [];\n let nextSeq = 1;\n if (!fs.existsSync(journalPath)) return { snapshot, diagnostics, nextSeq };\n\n const lines = fs.readFileSync(journalPath, 'utf-8').split('\\n');\n for (let i = 0; i \u003c lines.length; i++) {\n const line = lines[i];\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line);\n if (!entry || typeof entry !== 'object') throw new Error('entry is not object');\n if (Number.isInteger(entry.seq)) nextSeq = Math.max(nextSeq, entry.seq + 1);\n snapshot = applyEvent(snapshot, entry);\n } catch (err) {\n diagnostics.push({\n error: 'journal_parse_failed',\n line: i + 1,\n message: err.message,\n });\n }\n }\n snapshot.diagnostics = [...snapshot.diagnostics, ...diagnostics];\n return { snapshot, diagnostics, nextSeq };\n}\n\nfunction applyEvent(snapshot, entry, inheritedDiagnostics = []) {\n const event = entry.event || entry;\n const next = {\n ...snapshot,\n paramValues: { ...(snapshot.paramValues || {}) },\n sourceMarkers: { ...(snapshot.sourceMarkers || {}) },\n annotationArtifacts: [...(snapshot.annotationArtifacts || [])],\n diagnostics: [...(snapshot.diagnostics || [])],\n updatedAt: entry.ts || new Date().toISOString(),\n };\n\n if (inheritedDiagnostics.length && next.diagnostics.length === 0) {\n next.diagnostics = [...inheritedDiagnostics];\n }\n\n switch (event.type) {\n case 'generate':\n next.phase = 'generate_requested';\n next.pageUrl = event.pageUrl ?? next.pageUrl;\n next.expectedVariants = event.count ?? next.expectedVariants;\n next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;\n next.pendingEvent = toPendingEvent(event);\n if (event.screenshotPath) upsertArtifact(next.annotationArtifacts, { type: 'screenshot', path: event.screenshotPath });\n break;\n case 'variants_ready':\n case 'agent_done':\n next.phase = event.carbonize === true ? 'carbonize_required' : 'variants_ready';\n next.sourceFile = event.file ?? next.sourceFile;\n next.arrivedVariants = event.arrivedVariants ?? (next.arrivedVariants ?? next.expectedVariants);\n next.pendingEventSeq = null;\n next.pendingEvent = null;\n if (event.carbonize === true) {\n next.diagnostics.push({\n error: 'carbonize_cleanup_required',\n file: event.file || null,\n message: 'Accepted variant still has carbonize markers that must be folded into source CSS.',\n });\n }\n break;\n case 'checkpoint':\n if ((event.revision ?? 0) >= (next.checkpointRevision ?? 0)) {\n next.phase = event.phase ?? next.phase;\n next.checkpointRevision = event.revision ?? next.checkpointRevision;\n next.activeOwner = event.owner ?? next.activeOwner;\n next.arrivedVariants = event.arrivedVariants ?? next.arrivedVariants;\n next.visibleVariant = event.visibleVariant ?? next.visibleVariant;\n if (event.paramValues) next.paramValues = { ...event.paramValues };\n } else {\n next.diagnostics.push({ error: 'stale_checkpoint_ignored', revision: event.revision });\n }\n break;\n case 'accept':\n case 'accept_intent':\n next.phase = 'accept_requested';\n next.visibleVariant = Number(event.variantId ?? next.visibleVariant);\n if (event.paramValues) next.paramValues = { ...event.paramValues };\n next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;\n next.pendingEvent = toPendingEvent(event);\n break;\n case 'discard':\n next.phase = 'discard_requested';\n next.pendingEventSeq = entry.seq ?? next.pendingEventSeq;\n next.pendingEvent = toPendingEvent(event);\n break;\n case 'discarded':\n next.phase = 'discarded';\n next.pendingEventSeq = null;\n next.pendingEvent = null;\n break;\n case 'complete':\n next.phase = 'completed';\n next.pendingEventSeq = null;\n next.pendingEvent = null;\n break;\n case 'agent_error':\n next.phase = 'agent_error';\n next.pendingEventSeq = null;\n next.pendingEvent = null;\n next.diagnostics.push({ error: 'agent_error', message: event.message || 'unknown agent error' });\n break;\n default:\n next.diagnostics.push({ error: 'unknown_event_type', type: event.type });\n break;\n }\n return next;\n}\n\nfunction toPendingEvent(event) {\n const pending = { ...event };\n delete pending.token;\n return pending;\n}\n\nfunction upsertArtifact(artifacts, artifact) {\n if (!artifacts.some((existing) => existing.path === artifact.path && existing.type === artifact.type)) {\n artifacts.push(artifact);\n }\n}\n\nfunction writeSnapshot(snapshotPath, snapshot) {\n fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2) + '\\n');\n}\n","content_type":"text/javascript","language":"javascript","size":8997,"content_sha256":"f3146096b4dfb95ca36a7a669ae9904db83d327da06b9f532ee056d0076fdbac"},{"filename":"scripts/live-status.mjs","content":"#!/usr/bin/env node\n/**\n * Print durable recovery status for Impeccable live sessions.\n */\n\nimport { createLiveSessionStore } from './live-session-store.mjs';\nimport { readLiveServerInfo } from './impeccable-paths.mjs';\n\nfunction readServerInfo() {\n return readLiveServerInfo(process.cwd())?.info || null;\n}\n\nasync function fetchServerStatus(info) {\n if (!info) return null;\n try {\n const res = await fetch(`http://localhost:${info.port}/status?token=${info.token}`);\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n }\n}\n\nexport async function statusCli() {\n const info = readServerInfo();\n const server = await fetchServerStatus(info);\n const store = createLiveSessionStore({ cwd: process.cwd() });\n const activeSessions = store.listActiveSessions();\n const payload = {\n liveServer: server ? {\n status: server.status,\n port: server.port,\n connectedClients: server.connectedClients,\n pendingEvents: server.pendingEvents,\n } : null,\n activeSessions: server?.activeSessions || activeSessions,\n recoveryHint: server\n ? 'Run live-poll.mjs to continue pending work, or live-complete.mjs --id \u003csession> after manual cleanup.'\n : 'Start live-server.mjs to requeue pending durable events, then run live-poll.mjs.',\n };\n console.log(JSON.stringify(payload, null, 2));\n}\n\nconst _running = process.argv[1];\nif (_running?.endsWith('live-status.mjs') || _running?.endsWith('live-status.mjs/')) {\n statusCli();\n}\n","content_type":"text/javascript","language":"javascript","size":1496,"content_sha256":"bb8a936387a53a6c8eee0c5848b5fda9a6ab60098011e110379d2db47529fbc6"},{"filename":"scripts/live-wrap.mjs","content":"/**\n * CLI helper: find an element in source and wrap it in a variant container.\n *\n * Usage:\n * npx impeccable wrap --id SESSION_ID --count N --query \"hero-combined-left\" [--file path]\n *\n * Searches project files for the element matching the query (class name, ID, or\n * text snippet), wraps it with the variant scaffolding, and prints the file path\n * + line range where the agent should insert variant HTML.\n *\n * This replaces 3-4 agent tool calls (grep + read + edit) with a single CLI call.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { isGeneratedFile } from './is-generated.mjs';\n\nconst EXTENSIONS = ['.html', '.jsx', '.tsx', '.vue', '.svelte', '.astro'];\n\nexport async function wrapCli() {\n const args = process.argv.slice(2);\n\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: impeccable wrap [options]\n\nFind an element in source and wrap it in a variant container.\n\nRequired:\n --id ID Session ID for the variant wrapper\n --count N Number of expected variants (1-8)\n\nElement identification (at least one required):\n --element-id ID HTML id attribute of the element\n --classes A,B,C Comma-separated CSS class names\n --tag TAG Tag name (div, section, etc.)\n --query TEXT Fallback: raw text to search for\n\nOptional:\n --file PATH Source file to search in (skips auto-detection)\n --text TEXT Picked element's textContent. Used to disambiguate when\n classes/tag match multiple sibling elements (e.g. a list\n of \u003cCard>s with the same className). Pass the first ~80\n chars of event.element.textContent.\n --help Show this help message\n\nOutput (JSON):\n { file, startLine, endLine, insertLine, commentSyntax }\n\nThe agent should insert variant HTML at insertLine.`);\n process.exit(0);\n }\n\n const id = argVal(args, '--id');\n const count = parseInt(argVal(args, '--count') || '3');\n const elementId = argVal(args, '--element-id');\n const classes = argVal(args, '--classes');\n const tag = argVal(args, '--tag');\n const query = argVal(args, '--query');\n const filePath = argVal(args, '--file');\n const text = argVal(args, '--text');\n\n if (!id) { console.error('Missing --id'); process.exit(1); }\n if (!elementId && !classes && !query) {\n console.error('Need at least one of: --element-id, --classes, --query');\n process.exit(1);\n }\n\n // Build search queries in priority order (most specific first)\n const queries = buildSearchQueries(elementId, classes, tag, query);\n\n const genOpts = { cwd: process.cwd() };\n\n // Find the source file. Generated files are excluded from auto-search so we\n // don't silently write variants into a file the next build will wipe.\n let targetFile = filePath;\n let matchedQuery = null;\n if (!targetFile) {\n for (const q of queries) {\n targetFile = findFileWithQuery(q, process.cwd(), genOpts);\n if (targetFile) { matchedQuery = q; break; }\n }\n if (!targetFile) {\n // Nothing in source. Did the element show up in a generated file? That\n // tells the agent \"fall back to the agent-driven flow\" vs \"element just\n // doesn't exist in this project.\"\n let generatedHit = null;\n for (const q of queries) {\n generatedHit = findFileWithQuery(q, process.cwd(), { ...genOpts, includeGenerated: true });\n if (generatedHit) break;\n }\n if (generatedHit) {\n console.error(JSON.stringify({\n error: 'element_not_in_source',\n fallback: 'agent-driven',\n generatedMatch: path.relative(process.cwd(), generatedHit),\n hint: 'Element found only in a generated file. See \"Handle fallback\" in live.md.',\n }));\n } else {\n console.error(JSON.stringify({\n error: 'element_not_found',\n fallback: 'agent-driven',\n hint: 'Element not found in any project file. It may be runtime-injected (JS component, etc.). See \"Handle fallback\" in live.md.',\n }));\n }\n process.exit(1);\n }\n } else {\n if (isGeneratedFile(targetFile, genOpts)) {\n console.error(JSON.stringify({\n error: 'file_is_generated',\n fallback: 'agent-driven',\n file: path.relative(process.cwd(), path.resolve(process.cwd(), targetFile)),\n hint: 'Explicit --file points at a generated file. Writing here gets wiped by the next build. See \"Handle fallback\" in live.md.',\n }));\n process.exit(1);\n }\n matchedQuery = queries[0];\n }\n\n const content = fs.readFileSync(targetFile, 'utf-8');\n const lines = content.split('\\n');\n\n // Find the element, trying each query in priority order. When `--text` is\n // supplied, collect every candidate the queries surface and disambiguate\n // by the picked element's textContent. Without `--text`, fall back to the\n // legacy first-match behavior so unmodified callers keep working.\n let match = null;\n if (text) {\n const candidates = [];\n for (const q of queries) {\n const all = findAllElements(lines, q, tag);\n for (const c of all) {\n if (!candidates.some((x) => x.startLine === c.startLine)) {\n candidates.push(c);\n }\n }\n // Once a more-specific query (ID, full className combo) yielded a unique\n // result, stop — falling through to the loose tag+single-class query\n // would readmit the siblings we just disambiguated past.\n if (candidates.length === 1) break;\n }\n if (candidates.length === 0) {\n console.error(JSON.stringify({ error: 'Found file but could not locate element in ' + targetFile + '. Searched for: ' + queries.join(', ') }));\n process.exit(1);\n }\n if (candidates.length === 1) {\n match = candidates[0];\n } else {\n const filtered = filterByText(candidates, lines, text);\n if (filtered.length === 1) {\n match = filtered[0];\n } else if (filtered.length === 0) {\n // Source uses dynamic content (`\u003ch1>{title}\u003c/h1>` etc.) so the\n // browser-side textContent doesn't appear literally in source. Fall\n // back to first-match rather than refusing — this is the same\n // behavior unmodified callers see, just preserved.\n match = candidates[0];\n } else {\n // Multiple candidates ALSO match the text. Truly ambiguous — refuse\n // rather than pick wrong, and hand the agent the candidate locations\n // so it can disambiguate by reading the file.\n console.error(JSON.stringify({\n error: 'element_ambiguous',\n fallback: 'agent-driven',\n file: path.relative(process.cwd(), targetFile),\n candidates: filtered.map((c) => ({\n startLine: c.startLine + 1,\n endLine: c.endLine + 1,\n })),\n hint: 'Multiple source elements match both classes/tag and textContent. Pass --element-id, a more specific --text, or write the wrapper manually. See \"Handle fallback\" in live.md.',\n }));\n process.exit(1);\n }\n }\n } else {\n for (const q of queries) {\n match = findElement(lines, q, tag);\n if (match) break;\n }\n if (!match) {\n console.error(JSON.stringify({ error: 'Found file but could not locate element in ' + targetFile + '. Searched for: ' + queries.join(', ') }));\n process.exit(1);\n }\n }\n\n const { startLine, endLine } = match;\n const commentSyntax = detectCommentSyntax(targetFile);\n const styleMode = detectStyleMode(targetFile);\n const isJsx = commentSyntax.open === '{/*';\n const indent = lines[startLine].match(/^(\\s*)/)[1];\n\n // Extract the original element. Reindent under the wrapper while preserving\n // the relative depth between lines — `l.trimStart()` would strip ALL leading\n // whitespace and collapse e.g. `\u003caside>`/` \u003ch1>`/`\u003c/aside>` (6/8/6 spaces)\n // to a single uniform indent, so on accept/discard the round-trip restores\n // the inner element at its parent's depth instead of nested inside it.\n // Strip only the COMMON minimum leading whitespace across the picked lines;\n // `deindentContent` on the accept side already mirrors this convention.\n const originalLines = lines.slice(startLine, endLine + 1);\n const originalBaseIndent = minLeadingSpaces(originalLines);\n const reindentOriginal = (extra) => originalLines\n .map((l) => (l.trim() === '' ? '' : indent + extra + l.slice(originalBaseIndent)))\n .join('\\n');\n const originalIndented = reindentOriginal(' ');\n\n // Wrapper attributes differ by syntax. HTML allows plain string attrs;\n // JSX requires object-literal style and parses string attrs as HTML (which\n // either type-errors or renders a literal CSS string).\n const styleContents = isJsx ? 'style={{ display: \"contents\" }}' : 'style=\"display: contents\"';\n\n // JSX/TSX guard: the picked element occupies a single JSX child slot\n // (inside `return (...)`, an array `.map(...)`, an `asChild` branch, or\n // any other expression position). Replacing it with `comment + \u003cdiv> +\n // comment` yields three adjacent siblings — invalid JSX. We can't use a\n // Fragment `\u003c>\u003c/>` either: parents that clone children (Radix `asChild`,\n // Headless UI, etc.) hit \"Invalid prop supplied to React.Fragment\" when\n // they try to pass an `id` through.\n //\n // Solution: keep the wrapper `\u003cdiv>` as the single JSX-slot child and\n // tuck both marker comments INSIDE it. accept/discard then expands its\n // replacement range to include the wrapper's `\u003cdiv>` open / close lines\n // so the entire scaffold gets removed cleanly.\n const wrapperLines = isJsx ? [\n indent + '\u003cdiv data-impeccable-variants=\"' + id + '\" data-impeccable-variant-count=\"' + count + '\" ' + styleContents + '>',\n indent + ' ' + commentSyntax.open + ' impeccable-variants-start ' + id + ' ' + commentSyntax.close,\n indent + ' ' + commentSyntax.open + ' Original ' + commentSyntax.close,\n indent + ' \u003cdiv data-impeccable-variant=\"original\">',\n reindentOriginal(' '),\n indent + ' \u003c/div>',\n indent + ' ' + commentSyntax.open + ' Variants: insert below this line ' + commentSyntax.close,\n indent + ' ' + commentSyntax.open + ' impeccable-variants-end ' + id + ' ' + commentSyntax.close,\n indent + '\u003c/div>',\n ] : [\n indent + commentSyntax.open + ' impeccable-variants-start ' + id + ' ' + commentSyntax.close,\n indent + '\u003cdiv data-impeccable-variants=\"' + id + '\" data-impeccable-variant-count=\"' + count + '\" ' + styleContents + '>',\n indent + ' ' + commentSyntax.open + ' Original ' + commentSyntax.close,\n indent + ' \u003cdiv data-impeccable-variant=\"original\">',\n originalIndented,\n indent + ' \u003c/div>',\n indent + ' ' + commentSyntax.open + ' Variants: insert below this line ' + commentSyntax.close,\n indent + '\u003c/div>',\n indent + commentSyntax.open + ' impeccable-variants-end ' + id + ' ' + commentSyntax.close,\n ];\n\n // Replace the original element with the wrapper\n const newLines = [\n ...lines.slice(0, startLine),\n ...wrapperLines,\n ...lines.slice(endLine + 1),\n ];\n fs.writeFileSync(targetFile, newLines.join('\\n'), 'utf-8');\n\n // Calculate insert line (the \"insert below this line\" comment).\n // 0-indexed file position. Both HTML and JSX wrappers have 6 lines above\n // the insert marker (HTML: start-comment + outer-div + Original-comment +\n // original-div + content + close-original-div; JSX: outer-div +\n // start-comment + Original-comment + original-div + content +\n // close-original-div). Multi-line originals push the marker by their\n // extra line count.\n const insertLine = startLine + 6 + (originalLines.length - 1);\n\n console.log(JSON.stringify({\n file: path.relative(process.cwd(), targetFile),\n startLine: startLine + 1, // 1-indexed for the agent\n // wrapperLines is an array but one element (the original-content slot)\n // is a `\\n`-joined multi-line string, so the actual file-row count is\n // wrapperLines.length + (originalLines.length - 1). Without the offset,\n // endLine pointed inside the wrapper for any picked element that\n // spanned more than one source line.\n endLine: startLine + wrapperLines.length + (originalLines.length - 1), // 1-indexed\n insertLine: insertLine + 1, // 1-indexed: where variants go\n commentSyntax: commentSyntax,\n styleMode: styleMode.mode,\n styleTag: styleMode.styleTag,\n cssSelectorPrefixExamples: buildCssSelectorPrefixExamples(styleMode.mode, count),\n cssAuthoring: buildCssAuthoring(styleMode, count),\n originalLineCount: originalLines.length,\n }));\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction argVal(args, flag) {\n const idx = args.indexOf(flag);\n return idx !== -1 && idx + 1 \u003c args.length ? args[idx + 1] : null;\n}\n\n/**\n * Build search query strings in priority order (most specific first).\n * ID is most reliable, then specific class combos, then single classes, then raw query.\n */\nfunction buildSearchQueries(elementId, classes, tag, query) {\n const queries = [];\n\n // 1. ID is the most specific\n if (elementId) {\n queries.push('id=\"' + elementId + '\"');\n }\n\n // 2. Full class attribute match (for elements with distinctive multi-class combos).\n // Emit both class=\"...\" (HTML) and className=\"...\" (React/JSX) so whichever\n // convention the file uses will match.\n if (classes) {\n const classList = classes.split(',').map(c => c.trim()).filter(Boolean);\n if (classList.length > 1) {\n const joined = classList.join(' ');\n const sorted = [...classList].sort((a, b) => b.length - a.length);\n queries.push('class=\"' + joined + '\"');\n queries.push('className=\"' + joined + '\"');\n queries.push(sorted[0]); // most distinctive single class, fallback\n } else if (classList.length === 1) {\n queries.push(classList[0]);\n }\n }\n\n // 3. Tag + class combo (e.g., \u003csection class=\"hero\">).\n // Same dual-emit for JSX compatibility.\n if (tag && classes) {\n const firstClass = classes.split(',')[0].trim();\n queries.push('\u003c' + tag + ' class=\"' + firstClass);\n queries.push('\u003c' + tag + ' className=\"' + firstClass);\n }\n\n // 4. Raw fallback query\n if (query) {\n queries.push(query);\n }\n\n return queries;\n}\n\nfunction detectCommentSyntax(filePath) {\n const ext = path.extname(filePath).toLowerCase();\n if (ext === '.jsx' || ext === '.tsx') {\n return { open: '{/*', close: '*/}' };\n }\n // HTML, Vue, Svelte, Astro all use HTML comments\n return { open: '\u003c!--', close: '-->' };\n}\n\nfunction detectStyleMode(filePath) {\n const ext = path.extname(filePath).toLowerCase();\n if (ext === '.astro') {\n return {\n mode: 'astro-global-prefixed',\n styleTag: '\u003cstyle is:inline data-impeccable-css=\"SESSION_ID\">',\n };\n }\n return {\n mode: 'scoped',\n styleTag: '\u003cstyle data-impeccable-css=\"SESSION_ID\">',\n };\n}\n\nfunction buildCssSelectorPrefixExamples(styleMode, count) {\n if (styleMode !== 'astro-global-prefixed') return [];\n return Array.from({ length: count }, (_, i) => `[data-impeccable-variant=\"${i + 1}\"]`);\n}\n\nfunction buildCssAuthoring(styleMode, count) {\n const variantNumbers = Array.from({ length: count }, (_, i) => i + 1);\n if (styleMode.mode === 'astro-global-prefixed') {\n return {\n mode: styleMode.mode,\n styleTag: styleMode.styleTag,\n strategy: 'global-prefixed',\n rulePattern: '[data-impeccable-variant=\"N\"] > .variant-class { ... }',\n selectorExamples: variantNumbers.map((n) => `[data-impeccable-variant=\"${n}\"] > .variant-class`),\n requirements: [\n 'Use the styleTag exactly; the is:inline attribute is required for this file.',\n 'Prefix every preview selector with the matching [data-impeccable-variant=\"N\"] selector.',\n 'Keep selectors anchored to the generated variant wrapper; do not rely on component CSS scoping for preview rules.',\n ],\n forbidden: [\n 'Do not use @scope for this styleMode.',\n ],\n };\n }\n return {\n mode: styleMode.mode,\n styleTag: styleMode.styleTag,\n strategy: 'scope-rule',\n rulePattern: '@scope ([data-impeccable-variant=\"N\"]) { :scope > .variant-class { ... } }',\n selectorExamples: variantNumbers.map((n) => `@scope ([data-impeccable-variant=\"${n}\"]) { :scope > .variant-class { ... } }`),\n requirements: [\n 'Use @scope blocks keyed to each [data-impeccable-variant=\"N\"] wrapper.',\n 'Inside each @scope block, make :scope rules step into the replacement element with a descendant combinator.',\n 'Use the styleTag exactly; do not add framework-specific style attributes unless this object says to.',\n ],\n forbidden: [\n 'Do not use global [data-impeccable-variant=\"N\"] selector prefixes for this styleMode.',\n 'Do not add is:inline to the style tag for this styleMode.',\n ],\n };\n}\n\n/**\n * Search project files for the query string (class name, ID, etc.)\n * Returns the first matching file path, or null.\n */\nfunction findFileWithQuery(query, cwd, genOpts = {}) {\n const searchDirs = ['src', 'app', 'pages', 'components', 'public', 'views', 'templates', '.'];\n const seen = new Set();\n\n for (const dir of searchDirs) {\n const absDir = path.join(cwd, dir);\n if (!fs.existsSync(absDir)) continue;\n const result = searchDir(absDir, query, seen, 0, genOpts);\n if (result) return result;\n }\n return null;\n}\n\nfunction searchDir(dir, query, seen, depth, genOpts) {\n if (depth > 5) return null; // don't go too deep\n const realDir = fs.realpathSync(dir);\n if (seen.has(realDir)) return null;\n seen.add(realDir);\n\n let entries;\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\n catch { return null; }\n\n // Check files first\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const ext = path.extname(entry.name).toLowerCase();\n if (!EXTENSIONS.includes(ext)) continue;\n\n const filePath = path.join(dir, entry.name);\n if (!genOpts.includeGenerated && isGeneratedFile(filePath, genOpts)) continue;\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n if (content.includes(query)) return filePath;\n } catch { /* skip unreadable files */ }\n }\n\n // Then recurse into directories. Always skip node_modules and .git (never\n // project content). dist/build/out are left to the isGeneratedFile guard so\n // the includeGenerated second-pass can still find the element there and\n // report `generatedMatch`.\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (entry.name === 'node_modules' || entry.name === '.git') continue;\n const result = searchDir(path.join(dir, entry.name), query, seen, depth + 1, genOpts);\n if (result) return result;\n }\n\n return null;\n}\n\n/**\n * Regex that matches a tag opener on a line. Allows the tag name to be\n * followed by whitespace, `>`, `/`, or end-of-line so that multi-line JSX\n * openers (e.g. `\u003csection\\n className=\"...\"\\n>`) are recognised.\n */\nconst OPENER_RE = /\u003c([A-Za-z][A-Za-z0-9]*)(?=[\\s/>]|$)/;\n\n/**\n * Find the element's start and end line in the file.\n *\n * `query` is a class name, attribute fragment (`class=\"...\"`, `className=\"...\"`,\n * `id=\"...\"`), or a raw text snippet. Because a query can appear on a\n * continuation line of a multi-line tag (e.g. the `className=\"...\"` row of a\n * `\u003csection\\n className=\"...\"\\n>` JSX tag), we walk backward from the match\n * line to find the actual tag opener. When `tag` is provided, opener candidates\n * must match that tag name.\n */\n/**\n * Return the smallest leading-whitespace count across a set of lines,\n * ignoring blank lines (whose indent isn't load-bearing). Used to compute\n * the common base indent of a multi-line picked element so reindenting\n * under the wrapper preserves the relative depth between lines.\n */\nfunction minLeadingSpaces(lines) {\n let min = Infinity;\n for (const l of lines) {\n if (l.trim() === '') continue;\n const m = l.match(/^(\\s*)/);\n if (m && m[1].length \u003c min) min = m[1].length;\n }\n return min === Infinity ? 0 : min;\n}\n\nfunction findElement(lines, query, tag = null) {\n // Iterate all matches — the first substring hit isn't always the right one.\n for (let i = 0; i \u003c lines.length; i++) {\n if (!lines[i].includes(query)) continue;\n\n const stripped = lines[i].trim();\n if (stripped.startsWith('\u003c!--') || stripped.startsWith('{/*') || stripped.startsWith('//')) continue;\n // Skip lines already inside a variant wrapper\n if (lines[i].includes('data-impeccable-variant')) continue;\n\n const openerLine = findOpenerLine(lines, i, tag);\n if (openerLine === -1) continue;\n\n const endLine = findClosingLine(lines, openerLine);\n return { startLine: openerLine, endLine };\n }\n\n return null;\n}\n\n/**\n * Like findElement, but returns every match. Used for ambiguity detection\n * when the agent passes --text: when the same className appears on multiple\n * sibling elements (a list of cards, repeated section variants, etc.),\n * first-match silently lands on the wrong branch. Returning all matches lets\n * the caller narrow by textContent or fail with a structured ambiguity error.\n */\nfunction findAllElements(lines, query, tag = null) {\n const out = [];\n const seen = new Set();\n for (let i = 0; i \u003c lines.length; i++) {\n if (!lines[i].includes(query)) continue;\n const stripped = lines[i].trim();\n if (stripped.startsWith('\u003c!--') || stripped.startsWith('{/*') || stripped.startsWith('//')) continue;\n if (lines[i].includes('data-impeccable-variant')) continue;\n const openerLine = findOpenerLine(lines, i, tag);\n if (openerLine === -1) continue;\n if (seen.has(openerLine)) continue; // multiple matches inside the same element\n seen.add(openerLine);\n const endLine = findClosingLine(lines, openerLine);\n out.push({ startLine: openerLine, endLine });\n }\n return out;\n}\n\n/**\n * Narrow a candidate set to those whose source body matches a meaningful\n * prefix of the picked element's textContent. The compare strips tags and\n * JSX expressions, then checks two whitespace normalizations side-by-side:\n *\n * - single-space (\"hero two second card body\")\n * - no-whitespace (\"herotwosecondcardbody\")\n *\n * Both are needed because `el.textContent` concatenates sibling text without\n * inserting whitespace (e.g. `\u003ch1>Hero Two\u003c/h1>\u003cp>Second…\u003c/p>` reads as\n * `\"Hero TwoSecond…\"`), while the source has whitespace between tags. If\n * EITHER normalization matches, the candidate keeps. A snippet shorter than\n * 8 chars after stripping is too weak to disambiguate — the caller falls\n * back to first-match.\n */\nfunction filterByText(candidates, lines, text) {\n const trimmed = text.replace(/\\s+/g, ' ').trim().toLowerCase().slice(0, 80);\n // Too short to disambiguate. Return [] so the caller's `filtered.length\n // === 0` branch fires (fall back to first-match) — the previous\n // `candidates.slice()` return forced `filtered.length > 1` and surfaced\n // a spurious `element_ambiguous` error on every short-text picker event\n // with multiple candidates.\n if (trimmed.length \u003c 8) return [];\n const targetSpaced = trimmed;\n const targetCompact = trimmed.replace(/\\s+/g, '');\n\n return candidates.filter((c) => {\n const body = lines.slice(c.startLine, c.endLine + 1).join(' ');\n const inner = body\n .replace(/\u003c[^>]*>/g, ' ') // strip HTML/JSX tags\n .replace(/\\{[^}]*\\}/g, ' ') // strip JSX expressions\n .toLowerCase();\n const sourceSpaced = inner.replace(/\\s+/g, ' ').trim();\n const sourceCompact = inner.replace(/\\s+/g, '');\n return sourceSpaced.includes(targetSpaced) || sourceCompact.includes(targetCompact);\n });\n}\n\n/**\n * Resolve a match line to the real tag opener. If the match line itself opens\n * a tag, return it. Otherwise walk up to 10 lines backward looking for the\n * first tag opener. If `tag` is specified, the opener must match that tag\n * name; an opener with a different tag name aborts the backward walk for this\n * match (we don't jump across element boundaries).\n *\n * Returns the line index of the opener, or -1 if none can be resolved.\n */\nfunction findOpenerLine(lines, matchLine, tag) {\n const self = lines[matchLine].match(OPENER_RE);\n if (self) {\n if (!tag || self[1] === tag) return matchLine;\n return -1;\n }\n const MAX_BACKWALK = 10;\n for (let i = matchLine - 1; i >= Math.max(0, matchLine - MAX_BACKWALK); i--) {\n const opener = lines[i].match(OPENER_RE);\n if (!opener) continue;\n if (!tag || opener[1] === tag) return i;\n // Different tag name than requested — abort; we're inside a non-target opener.\n return -1;\n }\n return -1;\n}\n\n/**\n * Starting from a line with an opening tag, find the line with the matching\n * closing tag by counting tag nesting depth.\n */\nfunction findClosingLine(lines, start) {\n const openMatch = lines[start].match(OPENER_RE);\n if (!openMatch) return start; // caller passed a non-opener; nothing to span\n\n const tagName = openMatch[1];\n let depth = 0;\n const openRe = new RegExp('\u003c' + tagName + '(?=[\\\\s/>]|$)', 'g');\n const selfCloseRe = new RegExp('\u003c' + tagName + '[^>]*/>', 'g');\n const closeRe = new RegExp('\u003c/' + tagName + '\\\\s*>', 'g');\n\n for (let i = start; i \u003c lines.length; i++) {\n const line = lines[i];\n const opens = (line.match(openRe) || []).length;\n const selfCloses = (line.match(selfCloseRe) || []).length;\n const closes = (line.match(closeRe) || []).length;\n\n depth += opens - selfCloses - closes;\n\n if (depth \u003c= 0) return i;\n }\n\n // If we can't find the close, return a reasonable guess\n return Math.min(start + 50, lines.length - 1);\n}\n\n// Auto-execute when run directly (node live-wrap.mjs ...)\nconst _running = process.argv[1];\nif (_running?.endsWith('live-wrap.mjs') || _running?.endsWith('live-wrap.mjs/')) {\n wrapCli();\n}\n\n// Test exports (used by tests/live-wrap.test.mjs)\nexport { buildSearchQueries, findElement, findClosingLine, detectCommentSyntax };\n","content_type":"text/javascript","language":"javascript","size":25967,"content_sha256":"062bf8ce9f9d5040174e4316189dd5e8b0122757ba755985257cb14b221aba92"},{"filename":"scripts/live.mjs","content":"/**\n * CLI entry point: prepare everything needed to enter the live variant poll loop.\n *\n * Does (all in one command):\n * 1. Check .impeccable/live/config.json (returns config_missing if first-ever run)\n * 2. Start the live server in the background (or reuse a running one)\n * 3. Inject the browser script tag into the project's entry file\n * 4. Read PRODUCT.md / DESIGN.md for project context\n * 5. Print a single JSON blob with everything the agent needs\n *\n * After this, the agent's only remaining steps are:\n * - Open the project's live dev/preview URL in the browser (optional, if browser automation exists)—not `serverPort`; that port is the Impeccable helper for /live.js and /poll\n * - Enter the poll loop: `node live-poll.mjs`\n *\n * Usage:\n * node live.mjs # Prepare everything, print JSON, exit\n * node live.mjs --help\n */\n\nimport { execSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { loadContext } from './load-context.mjs';\nimport { resolveFiles } from './live-inject.mjs';\nimport { readLiveServerInfo } from './impeccable-paths.mjs';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nasync function liveCli() {\n const args = process.argv.slice(2);\n\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`Usage: node live.mjs\n\nPrepare everything for live variant mode in a single command:\n - Checks .impeccable/live/config.json (required, created once per project)\n - Starts (or reuses) the live server in the background\n - Injects the browser script tag\n - Reads PRODUCT.md / DESIGN.md for project context\n\nOn success, prints a JSON blob with:\n { ok, serverPort, serverToken, pageFile, hasContext, context }\n\nOn config_missing, prints:\n { ok: false, error: \"config_missing\", configPath, hint }\n\nThe agent should then:\n 1. If config_missing, create the config and re-run this script\n 2. Optionally open the project's dev/preview URL in the browser (see reference/live.md—not serverPort)\n 3. Enter the poll loop: node live-poll.mjs`);\n process.exit(0);\n }\n\n // 1. Check config (fail fast if missing — no point starting anything else)\n const checkOut = runScript('live-inject.mjs', ['--check']);\n const checkResult = safeParse(checkOut);\n if (!checkResult || !checkResult.ok) {\n console.log(JSON.stringify(checkResult || { ok: false, error: 'check_failed', raw: checkOut }));\n process.exit(0);\n }\n\n // 2. Start server (or reuse existing)\n const serverInfo = ensureServerRunning();\n if (!serverInfo) {\n console.log(JSON.stringify({ ok: false, error: 'server_start_failed' }));\n process.exit(1);\n }\n\n // 3. Inject the script tag at the current port\n const injectOut = runScript('live-inject.mjs', ['--port', String(serverInfo.port)]);\n const injectResult = safeParse(injectOut);\n if (!injectResult || !injectResult.ok) {\n console.log(JSON.stringify({\n ok: false,\n error: 'inject_failed',\n detail: injectResult || injectOut,\n serverPort: serverInfo.port,\n }));\n process.exit(1);\n }\n\n // 4. Load PRODUCT.md + DESIGN.md context (auto-migrates legacy .impeccable.md)\n const ctx = loadContext(process.cwd());\n\n // 5. Compute drift-heal: compare resolved inject targets against the\n // project's HTML files. Orphans are HTML files not covered by config.\n // Warning only — the agent decides whether to act.\n const resolvedFiles = resolveFiles(process.cwd(), checkResult.config);\n const drift = scanForDrift(process.cwd(), resolvedFiles, checkResult.config);\n\n // 6. Emit everything the agent needs\n console.log(JSON.stringify({\n ok: true,\n serverPort: serverInfo.port,\n serverToken: serverInfo.token,\n pageFiles: resolvedFiles,\n configDrift: drift,\n hasProduct: ctx.hasProduct,\n product: ctx.product,\n productPath: ctx.productPath,\n hasDesign: ctx.hasDesign,\n design: ctx.design,\n designPath: ctx.designPath,\n migrated: ctx.migrated,\n }, null, 2));\n}\n\n/**\n * Drift-heal scan. Walks the project for HTML files under common\n * page-source directories (public/, src/, app/, pages/) and reports any\n * that aren't covered by the resolved inject targets. This is purely\n * advisory — the agent can ignore it, or suggest the user add the\n * orphans to config.files.\n *\n * Skipped if config.files already contains at least one glob pattern\n * covering everything in practice (signaled by the orphan count being 0).\n */\nfunction scanForDrift(rootDir, resolvedFiles, config) {\n const SCAN_ROOTS = ['public', 'src', 'app', 'pages'];\n const IGNORE_DIRS = new Set([\n 'node_modules', '.git', '.next', '.nuxt', '.svelte-kit', '.astro',\n '.turbo', '.vercel', '.cache', 'coverage', 'dist', 'build',\n ]);\n\n const resolvedSet = new Set(resolvedFiles.map((f) => f.split(path.sep).join('/')));\n\n // Files matching the user's `exclude` globs are intentional omissions,\n // not drift. Compile them to regexes so the orphan list stays signal.\n const userExcludeRegexes = (Array.isArray(config.exclude) ? config.exclude : [])\n .map((p) => globToRegex(p));\n const isUserExcluded = (rel) => userExcludeRegexes.some((re) => re.test(rel));\n\n const orphans = [];\n\n const walk = (dir, relBase) => {\n let entries;\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\n catch { return; }\n for (const e of entries) {\n const rel = relBase ? `${relBase}/${e.name}` : e.name;\n if (e.isDirectory()) {\n if (IGNORE_DIRS.has(e.name) || e.name.startsWith('.')) continue;\n walk(path.join(dir, e.name), rel);\n } else if (e.isFile() && e.name.endsWith('.html')) {\n if (resolvedSet.has(rel)) continue;\n if (isUserExcluded(rel)) continue;\n orphans.push(rel);\n }\n }\n };\n\n for (const root of SCAN_ROOTS) {\n const abs = path.join(rootDir, root);\n if (fs.existsSync(abs) && fs.statSync(abs).isDirectory()) {\n walk(abs, root);\n }\n }\n\n if (orphans.length === 0) return null;\n const capped = orphans.slice(0, 20);\n return {\n orphans: capped,\n orphanCount: orphans.length,\n hint: `${orphans.length} HTML file(s) exist but aren't in config.files. Consider adding them, or use a glob pattern like \"public/**/*.html\".`,\n };\n}\n\n/**\n * Same glob-to-regex mapping used by live-inject.mjs. Kept inline here\n * to avoid a circular import (live-inject.mjs already imports nothing\n * from live.mjs). The two must stay in sync.\n */\nfunction globToRegex(pattern) {\n let re = '';\n let i = 0;\n while (i \u003c pattern.length) {\n const c = pattern[i];\n if (c === '*') {\n if (pattern[i + 1] === '*') {\n if (pattern[i + 2] === '/') { re += '(?:.*/)?'; i += 3; }\n else { re += '.*'; i += 2; }\n } else {\n re += '[^/]*';\n i += 1;\n }\n } else if (c === '?') {\n re += '[^/]';\n i += 1;\n } else if (/[.+^${}()|[\\]\\\\]/.test(c)) {\n re += '\\\\' + c;\n i += 1;\n } else {\n re += c;\n i += 1;\n }\n }\n return new RegExp('^' + re + '

Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. Setup (non-optional) Before any design work or file edits, pass these gates. Skipping them produces generic output that ignores the project. | Gate | Required check | If fail | |---|---|---| | Context | The PRODUCT.md / DESIGN.md loader result is known from . | Run the loader before continuing. | | Product | PRODUCT.md exists and is not empty or placeholder ( markers, <200 chars). | Run , refresh context, then resume. Never synthesize PRODUCT.md from the user's original p…

);\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction runScript(name, args) {\n const scriptPath = path.join(__dirname, name);\n const cmd = `node \"${scriptPath}\" ${args.map(a => `\"${a}\"`).join(' ')}`;\n try {\n return execSync(cmd, { encoding: 'utf-8', cwd: process.cwd(), timeout: 15_000 });\n } catch (err) {\n // execSync throws on non-zero exit; return stdout if any\n return err.stdout || err.message || '';\n }\n}\n\nfunction safeParse(out) {\n try { return JSON.parse(String(out).trim()); } catch { return null; }\n}\n\n/**\n * Return { pid, port, token } for the running live server, starting one if needed.\n */\nfunction ensureServerRunning() {\n // Try to reuse an existing server\n try {\n const existing = readLiveServerInfo(process.cwd())?.info;\n if (existing && existing.pid) {\n try {\n process.kill(existing.pid, 0); // throws if dead\n return existing;\n } catch { /* stale PID file — the server script will clean it up */ }\n }\n } catch { /* no PID file */ }\n\n // Start a new server\n const out = runScript('live-server.mjs', ['--background']);\n return safeParse(out);\n}\n\n// ---------------------------------------------------------------------------\n// Auto-execute\n// ---------------------------------------------------------------------------\n\nconst _running = process.argv[1];\nif (_running?.endsWith('live.mjs') || _running?.endsWith('live.mjs/')) {\n liveCli();\n}\n","content_type":"text/javascript","language":"javascript","size":8612,"content_sha256":"afc30c259057fd96c72b77e165971017348b9837a221701c599c8c1475b632ce"},{"filename":"scripts/load-context.mjs","content":"/**\n * Shared context loader for every impeccable command that needs to know\n * \"who is this for\" and \"what does this look like\".\n *\n * Input: project root (process.cwd()).\n *\n * Output (JSON to stdout):\n * {\n * hasProduct: boolean, // PRODUCT.md found (or auto-migrated)\n * product: string | null, // PRODUCT.md contents\n * productPath: string | null, // relative path\n * hasDesign: boolean, // DESIGN.md found\n * design: string | null, // DESIGN.md contents\n * designPath: string | null,\n * migrated: boolean, // true if we auto-renamed .impeccable.md -> PRODUCT.md\n * contextDir: string, // absolute path of the directory the files were found in\n * }\n *\n * Filename matching is case-insensitive for PRODUCT.md and DESIGN.md. The\n * Google DESIGN.md convention is uppercase at repo root; Kiro-style and\n * lowercase variants are also matched so users don't get punished for case.\n *\n * Lookup directory resolution (first match wins):\n * 1. process.env.IMPECCABLE_CONTEXT_DIR (absolute or relative to cwd)\n * 2. cwd, if PRODUCT.md / DESIGN.md / .impeccable.md is there (back-compat)\n * 3. Auto-fallback subdirectories of cwd: .agents/context/, then docs/\n * 4. cwd as a default \"no context found\" location\n *\n * Legacy `.impeccable.md` -> PRODUCT.md migration only fires at cwd root;\n * fallback directories are read-only as far as auto-rename is concerned.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst PRODUCT_NAMES = ['PRODUCT.md', 'Product.md', 'product.md'];\nconst DESIGN_NAMES = ['DESIGN.md', 'Design.md', 'design.md'];\nconst LEGACY_NAMES = ['.impeccable.md'];\nconst FALLBACK_DIRS = ['.agents/context', 'docs'];\n\n/**\n * Resolve the directory that holds PRODUCT.md / DESIGN.md for\n * this project. Exported so other scripts (e.g. live-server.mjs) can read the\n * design files from the same location the loader uses.\n */\nexport function resolveContextDir(cwd = process.cwd()) {\n // 1. Explicit override\n const envDir = process.env.IMPECCABLE_CONTEXT_DIR;\n if (envDir && envDir.trim()) {\n const trimmed = envDir.trim();\n return path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);\n }\n\n // 2. cwd wins if any canonical or legacy file is there. We check legacy too\n // so the auto-migration path in loadContext stays predictable.\n if (firstExisting(cwd, [...PRODUCT_NAMES, ...DESIGN_NAMES, ...LEGACY_NAMES])) {\n return cwd;\n }\n\n // 3. Auto-fallback subdirs. Match if PRODUCT.md or DESIGN.md is present;\n // legacy `.impeccable.md` does not pull the lookup into a fallback dir.\n for (const rel of FALLBACK_DIRS) {\n const candidate = path.resolve(cwd, rel);\n if (firstExisting(candidate, [...PRODUCT_NAMES, ...DESIGN_NAMES])) {\n return candidate;\n }\n }\n\n // 4. Nothing found — keep the historical \"default to cwd\" behaviour so the\n // caller's `hasProduct === false` branch still fires the same way.\n return cwd;\n}\n\nexport function loadContext(cwd = process.cwd()) {\n let migrated = false;\n const contextDir = resolveContextDir(cwd);\n\n // 1. Look for PRODUCT.md (case-insensitive) in the resolved dir\n let productPath = firstExisting(contextDir, PRODUCT_NAMES);\n\n // 2. Legacy: if no PRODUCT.md but .impeccable.md exists at cwd root, rename\n // it in place. We only migrate at the root — fallback dirs are read-only\n // so we don't surprise users by mutating files under docs/ or .agents/.\n if (!productPath && contextDir === cwd) {\n const legacyPath = firstExisting(cwd, LEGACY_NAMES);\n if (legacyPath) {\n const newPath = path.join(cwd, 'PRODUCT.md');\n try {\n fs.renameSync(legacyPath, newPath);\n productPath = newPath;\n migrated = true;\n } catch {\n // Rename failed (permissions, etc.) — fall back to reading legacy in place\n productPath = legacyPath;\n }\n }\n }\n\n // 3. DESIGN.md (case-insensitive)\n const designPath = firstExisting(contextDir, DESIGN_NAMES);\n\n const product = productPath ? safeRead(productPath) : null;\n const design = designPath ? safeRead(designPath) : null;\n\n return {\n hasProduct: !!product,\n product,\n productPath: productPath ? path.relative(cwd, productPath) : null,\n hasDesign: !!design,\n design,\n designPath: designPath ? path.relative(cwd, designPath) : null,\n migrated,\n contextDir,\n };\n}\n\nfunction firstExisting(dir, names) {\n for (const name of names) {\n const abs = path.join(dir, name);\n if (fs.existsSync(abs)) return abs;\n }\n return null;\n}\n\nfunction safeRead(p) {\n try { return fs.readFileSync(p, 'utf-8'); } catch { return null; }\n}\n\n// ---------------------------------------------------------------------------\n// CLI mode — print the context as JSON\n// ---------------------------------------------------------------------------\n\nfunction cli() {\n const result = loadContext(process.cwd());\n console.log(JSON.stringify(result, null, 2));\n}\n\nconst _running = process.argv[1];\nif (_running?.endsWith('load-context.mjs') || _running?.endsWith('load-context.mjs/')) {\n cli();\n}\n","content_type":"text/javascript","language":"javascript","size":5112,"content_sha256":"ece13459c80423a8cba49e97419c8bfbb9e0c6cb9ede1bf7ffcebaf11db7bea8"},{"filename":"scripts/pin.mjs","content":"#!/usr/bin/env node\n/**\n * Pin/unpin sub-commands as standalone skill shortcuts.\n *\n * Usage:\n * node \u003cscripts_path>/pin.mjs pin \u003ccommand>\n * node \u003cscripts_path>/pin.mjs unpin \u003ccommand>\n *\n * `pin audit` creates a lightweight /audit skill that redirects to /impeccable audit.\n * `unpin audit` removes that shortcut.\n *\n * The script discovers harness directories (.claude/skills, .cursor/skills, etc.)\n * in the project root and creates/removes the pin in all of them.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync } from 'node:fs';\nimport { join, resolve, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// All known harness directories\nconst HARNESS_DIRS = [\n '.claude', '.cursor', '.gemini', '.codex', '.agents',\n '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',\n];\n\n// Valid sub-command names\nconst VALID_COMMANDS = [\n 'craft', 'teach', 'extract', 'document', 'shape',\n 'critique', 'audit',\n 'polish', 'bolder', 'quieter', 'distill', 'harden', 'onboard', 'live',\n 'animate', 'colorize', 'typeset', 'layout', 'delight', 'overdrive',\n 'clarify', 'adapt', 'optimize',\n];\n\n// Marker to identify pinned skills (so unpin doesn't delete user skills)\nconst PIN_MARKER = '\u003c!-- impeccable-pinned-skill -->';\n\n/**\n * Walk up from startDir to find a project root.\n */\nfunction findProjectRoot(startDir = process.cwd()) {\n let dir = resolve(startDir);\n while (dir !== '/') {\n if (\n existsSync(join(dir, 'package.json')) ||\n existsSync(join(dir, '.git')) ||\n existsSync(join(dir, 'skills-lock.json'))\n ) {\n return dir;\n }\n const parent = resolve(dir, '..');\n if (parent === dir) break;\n dir = parent;\n }\n return resolve(startDir);\n}\n\n/**\n * Find harness skill directories that have an impeccable skill installed.\n */\nfunction findHarnessDirs(projectRoot) {\n const dirs = [];\n for (const harness of HARNESS_DIRS) {\n const skillsDir = join(projectRoot, harness, 'skills');\n // Only pin in harness dirs that already have impeccable installed\n const impeccableDir = join(skillsDir, 'impeccable');\n if (existsSync(impeccableDir) || existsSync(join(skillsDir, 'i-impeccable'))) {\n dirs.push(skillsDir);\n }\n }\n return dirs;\n}\n\n/**\n * Load command metadata (descriptions for pinned skills).\n */\nfunction loadCommandMetadata() {\n const metadataPath = join(__dirname, 'command-metadata.json');\n if (existsSync(metadataPath)) {\n return JSON.parse(readFileSync(metadataPath, 'utf-8'));\n }\n return {};\n}\n\n/**\n * Generate a pinned skill's SKILL.md content.\n */\nfunction generatePinnedSkill(command, metadata) {\n const desc = metadata[command]?.description || `Shortcut for /impeccable ${command}.`;\n const hint = metadata[command]?.argumentHint || '[target]';\n\n return `---\nname: ${command}\ndescription: \"${desc}\"\nargument-hint: \"${hint}\"\nuser-invocable: true\n---\n\n${PIN_MARKER}\n\nThis is a pinned shortcut for \\`{{command_prefix}}impeccable ${command}\\`.\n\nInvoke {{command_prefix}}impeccable ${command}, passing along any arguments provided here, and follow its instructions.\n`;\n}\n\n/**\n * Pin a command: create shortcut skill in all harness dirs.\n */\nfunction pin(command, projectRoot) {\n const metadata = loadCommandMetadata();\n const harnessDirs = findHarnessDirs(projectRoot);\n\n if (harnessDirs.length === 0) {\n console.log('No harness directories with impeccable installed found.');\n return false;\n }\n\n const content = generatePinnedSkill(command, metadata);\n let created = 0;\n\n for (const skillsDir of harnessDirs) {\n // Check if skill already exists (and isn't a pin)\n const skillDir = join(skillsDir, command);\n if (existsSync(skillDir)) {\n const existingMd = join(skillDir, 'SKILL.md');\n if (existsSync(existingMd)) {\n const existing = readFileSync(existingMd, 'utf-8');\n if (!existing.includes(PIN_MARKER)) {\n console.log(` SKIP: ${skillDir} (non-pinned skill already exists)`);\n continue;\n }\n }\n }\n\n mkdirSync(skillDir, { recursive: true });\n writeFileSync(join(skillDir, 'SKILL.md'), content, 'utf-8');\n console.log(` + ${skillDir}`);\n created++;\n }\n\n if (created > 0) {\n console.log(`\\nPinned '${command}' as a standalone shortcut in ${created} location(s).`);\n console.log(`You can now use /${command} directly.`);\n }\n\n return created > 0;\n}\n\n/**\n * Unpin a command: remove shortcut skill from all harness dirs.\n */\nfunction unpin(command, projectRoot) {\n const harnessDirs = findHarnessDirs(projectRoot);\n let removed = 0;\n\n for (const skillsDir of harnessDirs) {\n const skillDir = join(skillsDir, command);\n if (!existsSync(skillDir)) continue;\n\n const skillMd = join(skillDir, 'SKILL.md');\n if (!existsSync(skillMd)) continue;\n\n // Safety: only remove if it's a pinned skill\n const content = readFileSync(skillMd, 'utf-8');\n if (!content.includes(PIN_MARKER)) {\n console.log(` SKIP: ${skillDir} (not a pinned skill)`);\n continue;\n }\n\n rmSync(skillDir, { recursive: true, force: true });\n console.log(` - ${skillDir}`);\n removed++;\n }\n\n if (removed > 0) {\n console.log(`\\nUnpinned '${command}' from ${removed} location(s).`);\n console.log(`Use /impeccable ${command} to access it.`);\n } else {\n console.log(`No pinned '${command}' shortcut found.`);\n }\n\n return removed > 0;\n}\n\n// --- CLI ---\nconst [,, action, command] = process.argv;\n\nif (!action || !command) {\n console.log('Usage: node pin.mjs \u003cpin|unpin> \u003ccommand>');\n console.log(`\\nAvailable commands: ${VALID_COMMANDS.join(', ')}`);\n process.exit(1);\n}\n\nif (action !== 'pin' && action !== 'unpin') {\n console.error(`Unknown action: ${action}. Use 'pin' or 'unpin'.`);\n process.exit(1);\n}\n\nif (!VALID_COMMANDS.includes(command)) {\n console.error(`Unknown command: ${command}`);\n console.error(`Available commands: ${VALID_COMMANDS.join(', ')}`);\n process.exit(1);\n}\n\nconst root = findProjectRoot();\n\nif (action === 'pin') {\n pin(command, root);\n} else {\n unpin(command, root);\n}\n","content_type":"text/javascript","language":"javascript","size":6125,"content_sha256":"89a7056adfaca280519a1cc679b2e33f083300c3ed02a4fe7c71cf4d8c443bb6"}],"content_json":{"type":"doc","content":[{"type":"paragraph","content":[{"text":"Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Setup (non-optional)","type":"text"}]},{"type":"paragraph","content":[{"text":"Before any design work or file edits, pass these gates. Skipping them produces generic output that ignores the project.","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gate","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Required check","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"If fail","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Context","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"The PRODUCT.md / DESIGN.md loader result is known from ","type":"text"},{"text":"node {{scripts_path}}/load-context.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Run the loader before continuing.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Product","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PRODUCT.md exists and is not empty or placeholder (","type":"text"},{"text":"[TODO]","type":"text","marks":[{"type":"code_inline"}]},{"text":" markers, \u003c200 chars).","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"{{command_prefix}}impeccable teach","type":"text","marks":[{"type":"code_inline"}]},{"text":", refresh context, then resume. Never synthesize PRODUCT.md from the user's original prompt alone.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"The matching command reference is loaded when a sub-command is used.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Load the reference before continuing.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Craft","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"{{command_prefix}}impeccable craft","type":"text","marks":[{"type":"code_inline"}]},{"text":" has a user-confirmed shape brief for this task. ","type":"text"},{"text":"teach","type":"text","marks":[{"type":"code_inline"}]},{"text":" / PRODUCT.md never counts as shape.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"{{command_prefix}}impeccable shape","type":"text","marks":[{"type":"code_inline"}]},{"text":" and wait for explicit brief confirmation.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Image","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Required visual probes / mocks are generated or skipped with a reason.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Resolve the image-generation gate in ","type":"text"},{"text":"shape.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"craft.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" before code.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mutation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"All active gates above pass.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Do not edit project files yet.","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Codex-style agents must state this before editing files:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"text"},"content":[{"text":"IMPECCABLE_PREFLIGHT: context=pass product=pass command_reference=pass shape=pass|not_required image_gate=pass|skipped:\u003creason> mutation=open","type":"text"}]},{"type":"paragraph","content":[{"text":"For ","type":"text"},{"text":"{{command_prefix}}impeccable craft","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"shape=pass","type":"text","marks":[{"type":"code_inline"}]},{"text":" is only valid after a separate user response approving the shape design brief, or when the user provided an already-confirmed brief in the request. Do not mark ","type":"text"},{"text":"shape=pass","type":"text","marks":[{"type":"code_inline"}]},{"text":" after writing PRODUCT.md, summarizing assumptions, or drafting an unconfirmed brief yourself.","type":"text"}]},{"type":"paragraph","content":[{"text":"Other harnesses should follow the same checklist when they can expose this state.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Context gathering","type":"text"}]},{"type":"paragraph","content":[{"text":"Two files, case-insensitive. The loader looks at the project root by default and falls back to ","type":"text"},{"text":".agents/context/","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"docs/","type":"text","marks":[{"type":"code_inline"}]},{"text":" if the root is clean. Override with ","type":"text"},{"text":"IMPECCABLE_CONTEXT_DIR=path/to/dir","type":"text","marks":[{"type":"code_inline"}]},{"text":" (absolute or relative to cwd).","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PRODUCT.md","type":"text","marks":[{"type":"strong"}]},{"text":": required. Users, brand, tone, anti-references, strategic principles.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"DESIGN.md","type":"text","marks":[{"type":"strong"}]},{"text":": optional, strongly recommended. Colors, typography, elevation, components.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Load both in one call:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node {{scripts_path}}/load-context.mjs","type":"text"}]},{"type":"paragraph","content":[{"text":"Consume the full JSON output. Never pipe through ","type":"text"},{"text":"head","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tail","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"grep","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"jq","type":"text","marks":[{"type":"code_inline"}]},{"text":". The output's ","type":"text"},{"text":"contextDir","type":"text","marks":[{"type":"code_inline"}]},{"text":" field tells you where the files were resolved from.","type":"text"}]},{"type":"paragraph","content":[{"text":"If the output is already in this session's conversation history, don't re-run. Exceptions requiring a fresh load: you just ran ","type":"text"},{"text":"{{command_prefix}}impeccable teach","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"{{command_prefix}}impeccable document","type":"text","marks":[{"type":"code_inline"}]},{"text":" (they rewrite the files), or the user manually edited one.","type":"text"}]},{"type":"paragraph","content":[{"text":"{{command_prefix}}impeccable live","type":"text","marks":[{"type":"code_inline"}]},{"text":" already warms context via ","type":"text"},{"text":"live.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":". If you've run ","type":"text"},{"text":"live.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":", don't also run ","type":"text"},{"text":"load-context.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":" this session.","type":"text"}]},{"type":"paragraph","content":[{"text":"If PRODUCT.md is missing, empty, or placeholder (","type":"text"},{"text":"[TODO]","type":"text","marks":[{"type":"code_inline"}]},{"text":" markers, \u003c200 chars): run ","type":"text"},{"text":"{{command_prefix}}impeccable teach","type":"text","marks":[{"type":"code_inline"}]},{"text":", then resume the user's original task with the fresh context. If the original task was ","type":"text"},{"text":"{{command_prefix}}impeccable craft","type":"text","marks":[{"type":"code_inline"}]},{"text":", resume into ","type":"text"},{"text":"{{command_prefix}}impeccable shape","type":"text","marks":[{"type":"code_inline"}]},{"text":" before any implementation work.","type":"text"}]},{"type":"paragraph","content":[{"text":"If DESIGN.md is missing: nudge once per session (","type":"text"},{"text":"\"Run ","type":"text","marks":[{"type":"em"}]},{"text":"{{command_prefix}}impeccable document","type":"text","marks":[{"type":"code_inline"},{"type":"em"}]},{"text":" for more on-brand output\"","type":"text","marks":[{"type":"em"}]},{"text":"), then proceed.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Register","type":"text"}]},{"type":"paragraph","content":[{"text":"Every design task is ","type":"text"},{"text":"brand","type":"text","marks":[{"type":"strong"}]},{"text":" (marketing, landing, campaign, long-form content, portfolio: design IS the product) or ","type":"text"},{"text":"product","type":"text","marks":[{"type":"strong"}]},{"text":" (app UI, admin, dashboard, tool: design SERVES the product).","type":"text"}]},{"type":"paragraph","content":[{"text":"Identify before designing. Priority: (1) cue in the task itself (\"landing page\" vs \"dashboard\"); (2) the surface in focus (the page, file, or route being worked on); (3) ","type":"text"},{"text":"register","type":"text","marks":[{"type":"code_inline"}]},{"text":" field in PRODUCT.md. First match wins.","type":"text"}]},{"type":"paragraph","content":[{"text":"If PRODUCT.md lacks the ","type":"text"},{"text":"register","type":"text","marks":[{"type":"code_inline"}]},{"text":" field (legacy), infer it once from its \"Users\" and \"Product Purpose\" sections, then cache the inferred value for the session. Suggest the user run ","type":"text"},{"text":"{{command_prefix}}impeccable teach","type":"text","marks":[{"type":"code_inline"}]},{"text":" to add the field explicitly.","type":"text"}]},{"type":"paragraph","content":[{"text":"Load the matching reference: ","type":"text"},{"text":"reference/brand.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/brand.md","title":null}}]},{"text":" or ","type":"text"},{"text":"reference/product.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/product.md","title":null}}]},{"text":". The shared design laws below apply to both.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Shared design laws","type":"text"}]},{"type":"paragraph","content":[{"text":"Apply to every design, both registers. Match implementation complexity to the aesthetic vision: maximalism needs elaborate code, minimalism needs precision. Interpret creatively. Vary across projects; never converge on the same choices. {{model}} is capable of extraordinary work. Don't hold back.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Color","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use OKLCH. Reduce chroma as lightness approaches 0 or 100; high chroma at extremes looks garish.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Never use ","type":"text"},{"text":"#000","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"#fff","type":"text","marks":[{"type":"code_inline"}]},{"text":". Tint every neutral toward the brand hue (chroma 0.005–0.01 is enough).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pick a ","type":"text"},{"text":"color strategy","type":"text","marks":[{"type":"strong"}]},{"text":" before picking colors. Four steps on the commitment axis:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Restrained","type":"text","marks":[{"type":"strong"}]},{"text":": tinted neutrals + one accent ≤10%. Product default; brand minimalism.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Committed","type":"text","marks":[{"type":"strong"}]},{"text":": one saturated color carries 30–60% of the surface. Brand default for identity-driven pages.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Full palette","type":"text","marks":[{"type":"strong"}]},{"text":": 3–4 named roles, each used deliberately. Brand campaigns; product data viz.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drenched","type":"text","marks":[{"type":"strong"}]},{"text":": the surface IS the color. Brand heroes, campaign pages.","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The \"one accent ≤10%\" rule is Restrained only. Committed / Full palette / Drenched exceed it on purpose. Don't collapse every design to Restrained by reflex.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Theme","type":"text"}]},{"type":"paragraph","content":[{"text":"Dark vs. light is never a default. Not dark \"because tools look cool dark.\" Not light \"to be safe.\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Before choosing, write one sentence of physical scene: who uses this, where, under what ambient light, in what mood. If the sentence doesn't force the answer, it's not concrete enough. Add detail until it does.","type":"text"}]},{"type":"paragraph","content":[{"text":"\"Observability dashboard\" does not force an answer. \"SRE glancing at incident severity on a 27-inch monitor at 2am in a dim room\" does. Run the sentence, not the category.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Typography","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cap body line length at 65–75ch.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hierarchy through scale + weight contrast (≥1.25 ratio between steps). Avoid flat scales.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Layout","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Vary spacing for rhythm. Same padding everywhere is monotony.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cards are the lazy answer. Use them only when they're truly the best affordance. Nested cards are always wrong.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Don't wrap everything in a container. Most things don't need one.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Motion","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Don't animate CSS layout properties.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ease out with exponential curves (ease-out-quart / quint / expo). No bounce, no elastic.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Absolute bans","type":"text"}]},{"type":"paragraph","content":[{"text":"Match-and-refuse. If you're about to write any of these, rewrite the element with different structure.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Side-stripe borders.","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"border-left","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"border-right","type":"text","marks":[{"type":"code_inline"}]},{"text":" greater than 1px as a colored accent on cards, list items, callouts, or alerts. Never intentional. Rewrite with full borders, background tints, leading numbers/icons, or nothing.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Gradient text.","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"background-clip: text","type":"text","marks":[{"type":"code_inline"}]},{"text":" combined with a gradient background. Decorative, never meaningful. Use a single solid color. Emphasis via weight or size.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Glassmorphism as default.","type":"text","marks":[{"type":"strong"}]},{"text":" Blurs and glass cards used decoratively. Rare and purposeful, or nothing.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The hero-metric template.","type":"text","marks":[{"type":"strong"}]},{"text":" Big number, small label, supporting stats, gradient accent. SaaS cliché.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identical card grids.","type":"text","marks":[{"type":"strong"}]},{"text":" Same-sized cards with icon + heading + text, repeated endlessly.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Modal as first thought.","type":"text","marks":[{"type":"strong"}]},{"text":" Modals are usually laziness. Exhaust inline / progressive alternatives first.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Copy","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Every word earns its place. No restated headings, no intros that repeat the title.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No em dashes.","type":"text","marks":[{"type":"strong"}]},{"text":" Use commas, colons, semicolons, periods, or parentheses. Also not ","type":"text"},{"text":"--","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"The AI slop test","type":"text"}]},{"type":"paragraph","content":[{"text":"If someone could look at this interface and say \"AI made that\" without doubt, it's failed. Cross-register failures are the absolute bans above. Register-specific failures live in each reference.","type":"text"}]},{"type":"paragraph","content":[{"text":"Category-reflex check.","type":"text","marks":[{"type":"strong"}]},{"text":" Run at two altitudes; the second one catches what the first one misses.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"First-order:","type":"text","marks":[{"type":"strong"}]},{"text":" if someone could guess the theme + palette from the category alone (\"observability → dark blue\", \"healthcare → white + teal\", \"finance → navy + gold\", \"crypto → neon on black\"), it's the first training-data reflex. Rework the scene sentence and color strategy until the answer isn't obvious from the domain.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Second-order:","type":"text","marks":[{"type":"strong"}]},{"text":" if someone could guess the aesthetic family from category-plus-anti-references (\"AI workflow tool that's not SaaS-cream → editorial-typographic\", \"fintech that's not navy-and-gold → terminal-native dark mode\"), it's the trap one tier deeper. The first reflex was avoided; the second wasn't. Rework until both answers are not obvious. The brand register's ","type":"text"},{"text":"reflex-reject aesthetic lanes","type":"text","marks":[{"type":"link","attrs":{"href":"reference/brand.md","title":null}}]},{"text":" list catches the currently-saturated families.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Commands","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Category","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"craft [feature]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shape, then build a feature end-to-end","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/craft.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/craft.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"shape [feature]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Plan UX/UI before writing code","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/shape.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/shape.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"teach","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Set up PRODUCT.md and DESIGN.md context","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/teach.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/teach.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"document","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generate DESIGN.md from existing project code","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/document.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/document.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"extract [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pull reusable tokens and components into design system","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/extract.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/extract.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"critique [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Evaluate","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"UX design review with heuristic scoring","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/critique.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/critique.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"audit [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Evaluate","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Technical quality checks (a11y, perf, responsive)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/audit.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/audit.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"polish [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Final quality pass before shipping","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/polish.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/polish.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"bolder [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Amplify safe or bland designs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/bolder.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/bolder.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"quieter [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tone down aggressive or overstimulating designs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/quieter.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/quieter.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"distill [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Strip to essence, remove complexity","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/distill.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/distill.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"harden [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Production-ready: errors, i18n, edge cases","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/harden.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/harden.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"onboard [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Refine","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Design first-run flows, empty states, activation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/onboard.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/onboard.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"animate [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add purposeful animations and motion","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/animate.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/animate.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"colorize [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add strategic color to monochromatic UIs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/colorize.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/colorize.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"typeset [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Improve typography hierarchy and fonts","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/typeset.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/typeset.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"layout [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix spacing, rhythm, and visual hierarchy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/layout.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/layout.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"delight [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add personality and memorable touches","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/delight.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/delight.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"overdrive [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enhance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Push past conventional limits","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/overdrive.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/overdrive.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"clarify [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Improve UX copy, labels, and error messages","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/clarify.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/clarify.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"adapt [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Adapt for different devices and screen sizes","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/adapt.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/adapt.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"optimize [target]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Fix","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Diagnose and fix UI performance","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/optimize.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/optimize.md","title":null}}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"live","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Iterate","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Visual variant mode: pick elements in the browser, generate alternatives","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reference/live.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/live.md","title":null}}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Plus two management commands: ","type":"text"},{"text":"pin \u003ccommand>","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"unpin \u003ccommand>","type":"text","marks":[{"type":"code_inline"}]},{"text":", detailed below.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Routing rules","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No argument","type":"text","marks":[{"type":"strong"}]},{"text":": render the table above as the user-facing command menu, grouped by category. Ask what they'd like to do.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"First word matches a command","type":"text","marks":[{"type":"strong"}]},{"text":": load its reference file and follow its instructions. Everything after the command name is the target.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"First word doesn't match","type":"text","marks":[{"type":"strong"}]},{"text":": general design invocation. Apply the setup steps, shared design laws, and the loaded register reference, using the full argument as context.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Setup (context gathering, register) is already loaded by then; sub-commands don't re-invoke ","type":"text"},{"text":"{{command_prefix}}impeccable","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"If the first word is ","type":"text"},{"text":"craft","type":"text","marks":[{"type":"code_inline"}]},{"text":", setup still runs first, but ","type":"text"},{"text":"reference/craft.md","type":"text","marks":[{"type":"link","attrs":{"href":"reference/craft.md","title":null}}]},{"text":" owns the rest of the flow. If setup invokes ","type":"text"},{"text":"teach","type":"text","marks":[{"type":"code_inline"}]},{"text":" as a blocker, finish teach, refresh context, then resume the original command and target.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Pin / Unpin","type":"text"}]},{"type":"paragraph","content":[{"text":"Pin","type":"text","marks":[{"type":"strong"}]},{"text":" creates a standalone shortcut so ","type":"text"},{"text":"{{command_prefix}}\u003ccommand>","type":"text","marks":[{"type":"code_inline"}]},{"text":" invokes ","type":"text"},{"text":"{{command_prefix}}impeccable \u003ccommand>","type":"text","marks":[{"type":"code_inline"}]},{"text":" directly. ","type":"text"},{"text":"Unpin","type":"text","marks":[{"type":"strong"}]},{"text":" removes it. The script writes to every harness directory present in the project.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node {{scripts_path}}/pin.mjs \u003cpin|unpin> \u003ccommand>","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Valid ","type":"text"},{"text":"\u003ccommand>","type":"text","marks":[{"type":"code_inline"}]},{"text":" is any command from the table above. Report the script's result concisely. Confirm the new shortcut on success, relay stderr verbatim on error.","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"impeccable","author":"@skillopedia","source":{"stars":387,"repo_name":"skills","origin_url":"https://github.com/pedronauck/skills/blob/HEAD/skills/curated/impeccable/SKILL.md","repo_owner":"pedronauck","body_sha256":"18c22aacc0e2fc72156bd77aaf98014316f64f3baaea4dd8b72c1962207730f7","cluster_key":"2b4ddb3e268e6abcb702badd9f5000a4a2762fb95fc65ffdb43c209da67b167d","clean_bundle":{"format":"clean-skill-bundle-v1","source":"pedronauck/skills/skills/curated/impeccable/SKILL.md","attachments":[{"id":"b9ebc1ad-ffaf-593f-ba70-52bfd4ee9531","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b9ebc1ad-ffaf-593f-ba70-52bfd4ee9531/attachment.md","path":"reference/adapt.md","size":6486,"sha256":"82d2dc7fbeb868bec99828f32ba82d90efa0ceaa07dcedca78879b9b6f1da07f","contentType":"text/markdown; charset=utf-8"},{"id":"aa59b703-3cf4-51fb-9083-4dc80d06563b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/aa59b703-3cf4-51fb-9083-4dc80d06563b/attachment.md","path":"reference/animate.md","size":7768,"sha256":"9e6f096e50be90b314f33a27b16018d406af1d61b237825580f87b1485e9e1d3","contentType":"text/markdown; charset=utf-8"},{"id":"5d143118-9782-5788-a62b-37843bf5ae98","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5d143118-9782-5788-a62b-37843bf5ae98/attachment.md","path":"reference/audit.md","size":6602,"sha256":"3f0c9ad6cc5884574df870d2dc6ad2a20103232d2cea80fb7b1a4b0d441cce62","contentType":"text/markdown; charset=utf-8"},{"id":"f150fd8f-081b-59cf-ba8d-5a8cfd21cdee","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f150fd8f-081b-59cf-ba8d-5a8cfd21cdee/attachment.md","path":"reference/bolder.md","size":6383,"sha256":"99f995bdedbc2f2647947b77da772e2cb75e245a20e12164eadc835233ee4bcb","contentType":"text/markdown; charset=utf-8"},{"id":"270f9851-4a81-528a-9e14-7992693e7750","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/270f9851-4a81-528a-9e14-7992693e7750/attachment.md","path":"reference/brand.md","size":10385,"sha256":"838f4faf0aab11b5d8732874d8824da347f1cedb2c45edc226b7282ea3c7c851","contentType":"text/markdown; charset=utf-8"},{"id":"b1bf7980-71ad-54f3-97cf-a6949c659629","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b1bf7980-71ad-54f3-97cf-a6949c659629/attachment.md","path":"reference/clarify.md","size":6136,"sha256":"7f4141dbb25ba18bc775dd38adb0be1e111290ee7aa4f3cc28a847e438157041","contentType":"text/markdown; charset=utf-8"},{"id":"8b9cf3df-00f1-55fc-9f54-3c4b4fa72d53","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8b9cf3df-00f1-55fc-9f54-3c4b4fa72d53/attachment.md","path":"reference/cognitive-load.md","size":4796,"sha256":"944365dec799c122e89407c56a322a120c2401e27e41d745b57fbfbabe89da42","contentType":"text/markdown; charset=utf-8"},{"id":"b8817d93-8078-56fe-b927-731ceb4bd04e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b8817d93-8078-56fe-b927-731ceb4bd04e/attachment.md","path":"reference/color-and-contrast.md","size":5769,"sha256":"87e0e1ee4268839d8eb9a194de6dd66d747c286a56f92a22d6f8266ca13984e6","contentType":"text/markdown; charset=utf-8"},{"id":"3677a8c2-aa9c-584c-9a8b-fc8bc016f56a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3677a8c2-aa9c-584c-9a8b-fc8bc016f56a/attachment.md","path":"reference/colorize.md","size":8019,"sha256":"0abf6fd144dc88f497fee365103c73a40e60b3d12329427689e428a3106b059f","contentType":"text/markdown; charset=utf-8"},{"id":"269ba10b-f916-5d35-ad9a-1ed37bb5ee31","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/269ba10b-f916-5d35-ad9a-1ed37bb5ee31/attachment.md","path":"reference/craft.md","size":14646,"sha256":"5b4741215839d14eaeef688a17330027b28619137203979d77c483f7d0133d27","contentType":"text/markdown; charset=utf-8"},{"id":"0e7c0791-4c88-5f27-aea2-63a847054406","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0e7c0791-4c88-5f27-aea2-63a847054406/attachment.md","path":"reference/critique.md","size":12683,"sha256":"1488a4dce2c36b44bb18e1313395889d25b0947fd2622fccda8c91973ae661bd","contentType":"text/markdown; charset=utf-8"},{"id":"220195d6-6e16-5a8e-b386-35bb52d3e315","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/220195d6-6e16-5a8e-b386-35bb52d3e315/attachment.md","path":"reference/delight.md","size":9720,"sha256":"280ec04d065f9eef99189e76a8a2a343281f4a41d67454dd0c9f985842b05798","contentType":"text/markdown; charset=utf-8"},{"id":"fc45851e-08d0-5607-8c38-0cdc3199969a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fc45851e-08d0-5607-8c38-0cdc3199969a/attachment.md","path":"reference/distill.md","size":5633,"sha256":"26331f3afd2d59fc4322f7e2b39544be72749c78aecfe7d1aef48f62eec0c588","contentType":"text/markdown; charset=utf-8"},{"id":"9a37ad17-e257-54e5-8711-419bb65865d0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9a37ad17-e257-54e5-8711-419bb65865d0/attachment.md","path":"reference/document.md","size":28095,"sha256":"9edeaf75a407538ec2e387db77a53c15e5cd41a4858e008119346145809c86df","contentType":"text/markdown; charset=utf-8"},{"id":"810ef90e-35f7-5b01-8662-8e9e04411442","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/810ef90e-35f7-5b01-8662-8e9e04411442/attachment.md","path":"reference/extract.md","size":3307,"sha256":"4d4723d0b76a2153dafd29d54a16311ec5400c76815585a0004dc7c1cf6f692f","contentType":"text/markdown; charset=utf-8"},{"id":"5268168c-36ec-545e-b5ba-647a366febf7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5268168c-36ec-545e-b5ba-647a366febf7/attachment.md","path":"reference/harden.md","size":8611,"sha256":"ba240a70671f7d0bf7ee4893585b5f6b281e98f15a289678be4837bdae2b24c6","contentType":"text/markdown; charset=utf-8"},{"id":"8aa4186e-202b-5c6d-b526-d226d56dd700","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8aa4186e-202b-5c6d-b526-d226d56dd700/attachment.md","path":"reference/heuristics-scoring.md","size":8775,"sha256":"ab9df337000d79bd44da3ab29d8260a75e1ef3331ba7c2995d580979520a1bb9","contentType":"text/markdown; charset=utf-8"},{"id":"2f96fb85-3749-535c-9c92-5f3e2bc7601b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2f96fb85-3749-535c-9c92-5f3e2bc7601b/attachment.md","path":"reference/interaction-design.md","size":7082,"sha256":"b11b318017acf39998e092a49b1a38c8fe44d7dd16dfa525d509cda2a25688a3","contentType":"text/markdown; charset=utf-8"},{"id":"6cacc754-9a59-5880-8f18-5aafb13f98fa","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6cacc754-9a59-5880-8f18-5aafb13f98fa/attachment.md","path":"reference/layout.md","size":7981,"sha256":"e44625b2e83d20ce80ebb3145d2b325dfdcd2b86db08b91f8392c7e31758b7b7","contentType":"text/markdown; charset=utf-8"},{"id":"13184538-ed06-514e-aa14-39065a25fb09","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/13184538-ed06-514e-aa14-39065a25fb09/attachment.md","path":"reference/live.md","size":50820,"sha256":"aa1e366e1e46e1c5181ad02c88dc70dfebab46f82942f87d48dae39a3d9f9a62","contentType":"text/markdown; charset=utf-8"},{"id":"d90897dd-3e38-5aa5-af66-babe577f6725","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d90897dd-3e38-5aa5-af66-babe577f6725/attachment.md","path":"reference/motion-design.md","size":5784,"sha256":"6c7697aa18887407f168fa72e65265e5d9857bffa8445e74d98ba1344b5e017d","contentType":"text/markdown; charset=utf-8"},{"id":"c4260bda-042c-549a-8097-8d25061c41c3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c4260bda-042c-549a-8097-8d25061c41c3/attachment.md","path":"reference/onboard.md","size":7757,"sha256":"0d871444769f48a86db68b8b480bb6bfa61bef42d3784e65c248d7e5a555a085","contentType":"text/markdown; charset=utf-8"},{"id":"7daebb20-382a-5197-87cf-8964ce5b8b53","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7daebb20-382a-5197-87cf-8964ce5b8b53/attachment.md","path":"reference/optimize.md","size":7616,"sha256":"ea436784d13616449dc5875f144fc8baeb05101296f16ed6bc1ed3784c7b2332","contentType":"text/markdown; charset=utf-8"},{"id":"3248002d-cb81-5863-ba5a-1444cc59a773","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3248002d-cb81-5863-ba5a-1444cc59a773/attachment.md","path":"reference/overdrive.md","size":9015,"sha256":"70565c33dd51a9cdd5dc6b71874f49f22c384b89576a3752483fe7cb47e28237","contentType":"text/markdown; charset=utf-8"},{"id":"b7261bf6-51e2-5aa1-a91d-abac6272c27d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b7261bf6-51e2-5aa1-a91d-abac6272c27d/attachment.md","path":"reference/personas.md","size":7104,"sha256":"979c8b812ecab0f9180c244cedcb17a3b840fcf76ee1472fb69ff095b6f58c0d","contentType":"text/markdown; charset=utf-8"},{"id":"5c04776a-d53c-52ec-a9e9-36167099785a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5c04776a-d53c-52ec-a9e9-36167099785a/attachment.md","path":"reference/polish.md","size":12010,"sha256":"090140e051315e0bb436bb64e44fa18d50ad87ba88cf99f37f7ac0f7d9683842","contentType":"text/markdown; charset=utf-8"},{"id":"f15b50ef-af5e-539d-b163-3161e335aaf0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f15b50ef-af5e-539d-b163-3161e335aaf0/attachment.md","path":"reference/product.md","size":4137,"sha256":"e955b22fe8db598899b553e0966f8d736f3885c92711c9759b5f04bbfdb9097b","contentType":"text/markdown; charset=utf-8"},{"id":"794def78-7d93-5f4d-8111-9a79f697c541","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/794def78-7d93-5f4d-8111-9a79f697c541/attachment.md","path":"reference/quieter.md","size":4804,"sha256":"533c1ff689571fa005574bf7aff836ac42978d111ae38a0cb52a854dff0d4eef","contentType":"text/markdown; charset=utf-8"},{"id":"5b0a8ab9-99bd-5b5d-9aec-2f025f55d5b4","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5b0a8ab9-99bd-5b5d-9aec-2f025f55d5b4/attachment.md","path":"reference/responsive-design.md","size":3461,"sha256":"fefc1acaf1d293c74374c62c8c75629efa0660387315474d6302dc74b7f3ead0","contentType":"text/markdown; charset=utf-8"},{"id":"4fd06f10-820c-59ec-835c-466779ea9415","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4fd06f10-820c-59ec-835c-466779ea9415/attachment.md","path":"reference/shape.md","size":9473,"sha256":"feff21fdacc809af5bb4989ed7e3eed0e6ed4c57cb3b5177c95f2ffc0de8c504","contentType":"text/markdown; charset=utf-8"},{"id":"182e06b6-a494-5faa-9edf-686e44a4823e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/182e06b6-a494-5faa-9edf-686e44a4823e/attachment.md","path":"reference/spatial-design.md","size":3538,"sha256":"6e104d26025d4fba99f7bb538f8479f0d34877ce7cdf94481d08aea6a352bb6b","contentType":"text/markdown; charset=utf-8"},{"id":"dcc1ca9f-c281-50c1-b954-ab40e4c015e3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/dcc1ca9f-c281-50c1-b954-ab40e4c015e3/attachment.md","path":"reference/teach.md","size":9178,"sha256":"233b8d65758c2b894d386feefc7940019ec65d3ec3b770e4dd3cbd1593540007","contentType":"text/markdown; charset=utf-8"},{"id":"6b01f166-3f5a-5489-84c9-b8d9d5efccb5","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6b01f166-3f5a-5489-84c9-b8d9d5efccb5/attachment.md","path":"reference/typeset.md","size":6317,"sha256":"e0ae9b846b5d3c0a529ad88257ffb5173057f0941c661c8560bebd1b462521b4","contentType":"text/markdown; charset=utf-8"},{"id":"b5ea5aa8-0cea-5d36-9d8f-4dadea5a1470","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b5ea5aa8-0cea-5d36-9d8f-4dadea5a1470/attachment.md","path":"reference/typography.md","size":8269,"sha256":"d08a05014d5009a5f1cc156236ba64a1d24463bb1e7141bdcca9269139d9ea64","contentType":"text/markdown; charset=utf-8"},{"id":"3f07aaaa-9ef8-5ceb-a3e1-b430d0ba6e03","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3f07aaaa-9ef8-5ceb-a3e1-b430d0ba6e03/attachment.md","path":"reference/ux-writing.md","size":4326,"sha256":"20be4fe822a77558e8e169514ac7e6685d51703537b899e262f542fe99ed6af9","contentType":"text/markdown; charset=utf-8"},{"id":"3b3e022b-ce89-5dcb-8b34-2a5447dd17c8","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3b3e022b-ce89-5dcb-8b34-2a5447dd17c8/attachment.mjs","path":"scripts/cleanup-deprecated.mjs","size":9130,"sha256":"5b1a36e3241e14ba8645881e8f07255748ca7f7a158a11e1df99043357a4b6d2","contentType":"text/javascript"},{"id":"d30bf543-2717-56ec-a071-65e8a39b8835","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d30bf543-2717-56ec-a071-65e8a39b8835/attachment.json","path":"scripts/command-metadata.json","size":7944,"sha256":"d7167de1e3c242eb3788389f7c856914d05aef8e38271f9fc1aa48005992621a","contentType":"application/json; charset=utf-8"},{"id":"c70dfad0-3c79-5919-8e80-ad5f634ca624","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c70dfad0-3c79-5919-8e80-ad5f634ca624/attachment.mjs","path":"scripts/design-parser.mjs","size":25217,"sha256":"6e7b463344cdf59353acaf48f554ac0aad5a0a46cb1237a0d1a697ddc7759eab","contentType":"text/javascript"},{"id":"a1e73522-6ad7-5057-9e47-ffc10782231b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a1e73522-6ad7-5057-9e47-ffc10782231b/attachment.mjs","path":"scripts/detect-csp.mjs","size":6761,"sha256":"2d80520bef13cb93107699714bc0d2be5a2787a9aa079ecec91b94508a8125a4","contentType":"text/javascript"},{"id":"38cb8dcb-4759-54e8-a8db-27152e0c529e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/38cb8dcb-4759-54e8-a8db-27152e0c529e/attachment.mjs","path":"scripts/impeccable-paths.mjs","size":3277,"sha256":"a76f32f44e5664b4bc2767f71275749f6c9bb4b5a83d674fb349ead5ae9305d4","contentType":"text/javascript"},{"id":"983594a2-5159-577d-bcd0-ad397d6fb172","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/983594a2-5159-577d-bcd0-ad397d6fb172/attachment.mjs","path":"scripts/is-generated.mjs","size":2269,"sha256":"ed5b0b00e99ed385db541c7a068cb85f72456a4b6aa7a5460037d24b58bd90cd","contentType":"text/javascript"},{"id":"6aa35faf-2a4e-5334-a291-156ad1cd7544","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6aa35faf-2a4e-5334-a291-156ad1cd7544/attachment.mjs","path":"scripts/live-accept.mjs","size":22906,"sha256":"92c0a973866a6c69795713e3562d8b4dcb57db95ab7603edac29cde656cc0a83","contentType":"text/javascript"},{"id":"6f4bd898-e8d0-53ac-b311-f500f1c7d482","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6f4bd898-e8d0-53ac-b311-f500f1c7d482/attachment.js","path":"scripts/live-browser-session.js","size":3297,"sha256":"dddcb8b941f7460aa6a134f7d456b1820747172c12e01de36dab3265b1065cff","contentType":"application/javascript; charset=utf-8"},{"id":"10802518-7b22-5954-9416-4dcc70307375","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/10802518-7b22-5954-9416-4dcc70307375/attachment.js","path":"scripts/live-browser.js","size":198378,"sha256":"d022aea7a3ec35df374865c3f10b0b722d60aa2dce7442f9664a627250ad68cc","contentType":"application/javascript; charset=utf-8"},{"id":"fca55dd1-7f8c-5c25-b761-fe118b560c15","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fca55dd1-7f8c-5c25-b761-fe118b560c15/attachment.mjs","path":"scripts/live-complete.mjs","size":2938,"sha256":"ada702f177432c9645bf2675b8f69ac5f6be5b63f4540eb161159a247eddd697","contentType":"text/javascript"},{"id":"b15757f5-9020-591f-b8ce-f6e22f1a9a96","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b15757f5-9020-591f-b8ce-f6e22f1a9a96/attachment.mjs","path":"scripts/live-completion.mjs","size":871,"sha256":"67f11f7823b366946cae6b9b4794dec40199951d3d2bd57af759fd1511030f45","contentType":"text/javascript"},{"id":"2e4b26ed-a10b-5a0f-beaf-96217348f0d2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2e4b26ed-a10b-5a0f-beaf-96217348f0d2/attachment.mjs","path":"scripts/live-inject.mjs","size":17402,"sha256":"f4d9dfba7cb9350b5e298c8ed6cb4ee46473483644f873fb87181ea07babf06c","contentType":"text/javascript"},{"id":"06c57e08-429a-5e9e-bf92-718c40b07a7e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/06c57e08-429a-5e9e-bf92-718c40b07a7e/attachment.mjs","path":"scripts/live-poll.mjs","size":7710,"sha256":"02910a4d3547ca685198df4940f08f6b69efbcdb7633206c16f256ff54ae478e","contentType":"text/javascript"},{"id":"e6cdbca1-f69b-5928-b606-4632a8f5ec62","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e6cdbca1-f69b-5928-b606-4632a8f5ec62/attachment.mjs","path":"scripts/live-resume.mjs","size":1974,"sha256":"741b6799a406b835ccaffb396d6c12109ee596659eb751d2e8865b4fc5a08e3f","contentType":"text/javascript"},{"id":"2c7b49bb-9abb-5367-8718-916c106cf216","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2c7b49bb-9abb-5367-8718-916c106cf216/attachment.mjs","path":"scripts/live-server.mjs","size":32452,"sha256":"8db37f313b421f1a167e682fba8a64c49dd383bf8fac43da8d9db650efe89c27","contentType":"text/javascript"},{"id":"3465aa66-35dd-57b1-a8c2-09fe9c0cbeaf","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3465aa66-35dd-57b1-a8c2-09fe9c0cbeaf/attachment.mjs","path":"scripts/live-session-store.mjs","size":8997,"sha256":"f3146096b4dfb95ca36a7a669ae9904db83d327da06b9f532ee056d0076fdbac","contentType":"text/javascript"},{"id":"8ca005f0-7358-5c6b-874c-07dc053588dd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8ca005f0-7358-5c6b-874c-07dc053588dd/attachment.mjs","path":"scripts/live-status.mjs","size":1496,"sha256":"bb8a936387a53a6c8eee0c5848b5fda9a6ab60098011e110379d2db47529fbc6","contentType":"text/javascript"},{"id":"c4da6632-a389-5d7a-9766-b2c467c329c7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c4da6632-a389-5d7a-9766-b2c467c329c7/attachment.mjs","path":"scripts/live-wrap.mjs","size":25967,"sha256":"062bf8ce9f9d5040174e4316189dd5e8b0122757ba755985257cb14b221aba92","contentType":"text/javascript"},{"id":"6ac335d0-8a3b-5283-bbea-60c7f78385a0","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6ac335d0-8a3b-5283-bbea-60c7f78385a0/attachment.mjs","path":"scripts/live.mjs","size":8612,"sha256":"afc30c259057fd96c72b77e165971017348b9837a221701c599c8c1475b632ce","contentType":"text/javascript"},{"id":"7d09eca4-2a0f-5259-91e5-7235bb235a93","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7d09eca4-2a0f-5259-91e5-7235bb235a93/attachment.mjs","path":"scripts/load-context.mjs","size":5112,"sha256":"ece13459c80423a8cba49e97419c8bfbb9e0c6cb9ede1bf7ffcebaf11db7bea8","contentType":"text/javascript"},{"id":"ab7c9492-822e-5596-a57e-6b552f94e77f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ab7c9492-822e-5596-a57e-6b552f94e77f/attachment.js","path":"scripts/modern-screenshot.umd.js","size":29290,"sha256":"bb36665889124a0b6e15f16045265737449c3bdcf2712cdb08af3cfa01563e2b","contentType":"application/javascript; charset=utf-8"},{"id":"b926f583-6fb8-5799-a9b4-5c72c1a5f13b","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b926f583-6fb8-5799-a9b4-5c72c1a5f13b/attachment.mjs","path":"scripts/pin.mjs","size":6125,"sha256":"89a7056adfaca280519a1cc679b2e33f083300c3ed02a4fe7c71cf4d8c443bb6","contentType":"text/javascript"}],"bundle_sha256":"e90a41ec2a095c6aef63091e123d99b0d630756fe90cd35716c42710f5653890","attachment_count":57,"text_attachments":57,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/curated/impeccable/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"license":"Apache 2.0. Based on Anthropic's frontend-design skill. See NOTICE.md for attribution.","version":"v1","category":"security","import_tag":"clean-skills-v1","description":"Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.","allowed-tools":["Bash(npx impeccable *)"],"argument-hint":"[{{command_hint}}] [target]","user-invocable":true}},"renderedAt":1782979907152}

Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft. Setup (non-optional) Before any design work or file edits, pass these gates. Skipping them produces generic output that ignores the project. | Gate | Required check | If fail | |---|---|---| | Context | The PRODUCT.md / DESIGN.md loader result is known from . | Run the loader before continuing. | | Product | PRODUCT.md exists and is not empty or placeholder ( markers, <200 chars). | Run , refresh context, then resume. Never synthesize PRODUCT.md from the user's original p…