Commit Graph
383 Commits
Author SHA1 Message Date
shadowdaoandClaude Opus 5.5 cfeeef37ce Mobile guard: HtmlBlock wrapper never gets a box; phone net is media + per-table/pre scroll only
Review of bb4fb75: overflow-x:auto on [data-wsb-html] forced overflow-y:auto (clipped dropdowns/shadows),
broke position:sticky inside customer HTML, and display:block!important merged multi-root blocks that are
direct flex/grid items. Now the wrapper stays display:contents on every viewport and no rule targets it;
at <=767px only its descendants are touched: media max-width:100% (img/video height:auto), and a table or
<pre> becomes its own sideways scroller (not when already inside an inline overflow wrapper). No
overflow-wrap:anywhere (it shrank min-content); body{overflow-wrap:break-word} inherits through the wrapper.
Deliberately wide customer markup (fixed widths, px grids) is clipped as before; the publish warning is
its guard, and its wording now says the excess is cut off. width= attributes are no longer flagged (they
size only media and tables, which the net handles). stripMediaBlocks lowercases once.

Browser suite: htmlblocks probes at every width (wrapper display:contents, sticky sticks, absolutely
positioned dropdown visible on top, multi-root block = separate flex items / grid cells, bare table
scrolls on its own); new htmlwide doc asserts wide blocks stay clipped and the page never scrolls sideways.
All probes fail on bb4fb75's net and pass now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:09:22 -08:00
shadowdaoandClaude Opus 5.5 bb4fb7548b Mobile guard: real-browser overflow suite, card-grid + HtmlBlock mobile hooks, wide custom HTML publish warning
- scripts/e2e-mobile-guard.mjs (npm run test:browser:mobile-guard): Chromium + Firefox at 360/390/768/1280 over
  exporter-built pages (navbar, columns, FeaturesGrid/Testimonials/NumberCounter/Gallery/Pricing/Reviews, big
  image, long word/URL, wide customer HtmlBlocks). Asserts body.scrollWidth and every visible box/text right edge
  (html,body{overflow-x:clip} hides overflow from documentElement.scrollWidth), stacking on phones, columns kept
  on tablet, navbar wrap, intentional overflow-x:auto still scrolls, and 1280 box + pixel identity with the hooks
  removed (optional cross-commit baseline).
- OLS home overflow was FeaturesGrid (inline repeat(3,1fr)), not an HtmlBlock. FeaturesGrid, Testimonials and
  NumberCounter grids carry data-wsb-grid; the <=767px head block makes them one column.
- HtmlBlock output is exported inside <div data-wsb-html style="display:contents"> (applied after attr
  injection, toHtml().html unchanged); on phones it becomes a max-width:100% sideways-scrolling box, media
  shrink, long words break. body{overflow-wrap:break-word} on phones. Navbar link wrap now up to 991px
  (8 links + long logo overflowed at 768).
- Head parity pins updated (mirror in WHP generateCompiledHTML); editor.css mirrors for the mobile frame.
- publish-checks: warn when an HtmlBlock's inline/<style> CSS sets widths, flex sizes or grids over 390px or a
  3+ column grid with no phone @media rule; says what is not checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 14:58:39 -08:00
shadowdaoandClaude Opus 5.5 9f9be5f41a Sitesmith modal: Clear chat explains a refusal and is disabled while a job runs
Reproduced in the e2e mock (now stateful: history + clear_history with the
server's 409 while a job is live): the normal two-step clear works (first
click arms the confirm by design), but a confirm while a job is live -- e.g.
the self-review follow-up that starts right after a send -- was refused by the
server and the modal showed the raw code 'job_in_progress', so the chat looked
like it would not clear on the first try. Now the server's sentence is shown,
and the button is disabled (with a tooltip) while a send, resume or self-review
is running. e2e scenarios 9, 9b (failed before), 9c (Firefox + Chromium).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 12:16:59 -08:00
shadowdaoandClaude Opus 5.5 465cf17bb0 Sitesmith: self-review render via review_render_upload; one-line-per-node summaries; real-browser check of cleaned output
- The render is uploaded with the new review_render_upload action (backend kind
  review_render, the only image a review job accepts); mocks follow.
- summarizeCanvas() never lets a newline or a quote into a node line (the server
  validates review summaries line by line); test.
- test:browser:sitesmith-cleaned (Firefox + Chromium): a page published from a
  cleaned ordinary Sitesmith response requests nothing outside the allow-listed
  hosts (own assets, fonts, Font Awesome CDN, images.pexels.com, placehold.co)
  and has no inline handlers or javascript:/data: URL attributes; the same
  response uncleaned is the control (requests example.com). All requests are
  answered or aborted locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:47:04 -08:00
shadowdaoandClaude Opus 5.5 4a34781ab6 Sitesmith cleaner: patches use the target component's rules; CSS values checked against a positive grammar
Review findings on clean-ai-response.ts:
1. update_props is now cleaned with the TARGET node's component (resolved on the
   live canvas by apply()); an unresolvable target gets the strictest rules
   (no code, url/src only assets/). code is kept only on an HtmlBlock.
2. cssValueAllowed() is a positive grammar: numbers/lengths/hex/keywords, an
   allow-list of functions (gradients, colour functions, calc/clamp, var(--*),
   transforms, filters), url() only of assets/<file>, quoted strings only plain
   font names; image-set(, src(, cross-fade(, element(, paint(, attr(, env(,
   ':' or '//' outside url(assets/..), backslashes and control chars rejected.
   Regression: every style/colour value in the templates, section families and
   palettes passes (clean-ai-response.ordinary.test.ts).
Also: tricky link forms (//host, backslashes, whitespace/control chars,
mixed-case schemes, > 2048) rejected; comments state the server-side mirror is
not implemented (deferred).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:38:14 -08:00
shadowdaoandClaude Opus 5.5 2b8b0557b2 Sitesmith: allow-list cleaner for model responses before they reach the canvas; export strips attack-only CSS (G8)
clean-ai-response.ts runs first in useApplyAiResponse().apply() and in
applyRegeneratedSection(): link props allow ''|#anchor|relative|mailto:|tel:|
https:|http: (never //host, backslash, whitespace/control chars, > 2048);
images only assets/<file> or https on images.pexels.com / placehold.co;
videos assets/ or YouTube/Vimeo; the model can never set form destinations,
relay settings or head code (patches keep the user's values); style names
must be CSS identifiers and values may not carry url() (except assets/),
@import, expression(, behavior, -moz-binding, javascript:, < > { } ; \;
anchor ids [A-Za-z0-9_-]. HtmlBlock code keeps its existing sanitisers.
Export boundary: stripLegacyCssVectors() in cssValue/cssPropsToString
(byte-identical for ordinary content: OLS fixture + default design measured).
Server-side mirror not implemented (deferred).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:31:42 -08:00
shadowdaoandClaude Opus 5.5 93b3cc35af Colour e2e: baseline commit overridable (COLOR_BASE_COMMIT)
On the release branch mobile-parity's <=767px head rules land before the
colour merge, so 'identical to ab7a100' cannot hold; run with
COLOR_BASE_COMMIT=<commit before the colour merge> there. Measured: vs ab7a100
the only difference is those two documented rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:23:17 -08:00
shadowdaoandClaude Opus 5.5 a113f25a62 Guard test: the capture-frame exception now fails on allow-scripts, a skipped or ignored sanitiser, or src= (G7)
captureFileViolations() pins the one allow-same-origin srcdoc frame: sandbox set
once to exactly allow-same-origin, no script/form/popup/navigation tokens,
srcdoc only from inlineResources(clean.html), sanitizeCaptureHtml called and its
verdict checked before srcdoc. Eight mutated copies of the real source prove
each rule fails. Plus a behavioural jsdom test of the real captureHtml frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:10:30 -08:00
shadowdaoandClaude Opus 5.5 6c406ca99b Sitesmith: self-review is intent 'review' (not a mockup); typed statuses with specific messages (G3, G6)
- The self-review follow-up sends intent:'review' + review_image_ids instead of
  putting the render in mockup_ids, so the backend builds a critique+patch
  instruction instead of 'build toward this mockup'. Render still deleted after.
- types/sitesmith.ts: SitesmithStatus = server statuses (adds IMAGES_BUSY,
  TOO_MANY_JOBS, SERVER_BUSY, ...) + client statuses (TIMEOUT, ABORTED, ...);
  network status strings are narrowed with a type guard (unknown -> ERROR);
  the hook builds SendResultErr without casts.
- statusMessages.ts: one specific message per status (a Record over the union,
  so a new status without a message fails tsc), used by the modal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:10:30 -08:00
shadowdaoandClaude Opus 5.5 7a58921ba3 Sitesmith design payload: brand colours carry their published slot (G1)
buildDesignPayload numbered brand colours by list position while the page
publishes them as --wsb-brand-<slot>, so the prompt could name a different
colour than the page renders. It now uses publishedBrandSwatches (same rule as
the publisher) and sends {name?, hex, slot}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:10:30 -08:00
shadowdaoandClaude Opus 5.5 3413c7816d Head parity: re-pin E_brand_swatches after the mobile-parity merge
The colour branch pinned the brand head before the <=767px stacking/nav-wrap
rules existed; the bytes are now copied from the merged WHP
generateCompiledHTML output (WHP release/sitesmith-colors).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:56:02 -08:00
shadowdaoandClaude Opus 5.5 9f48b8b134 Merge feat/sitesmith-catalog into release/sitesmith-colors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:55:05 -08:00
shadowdaoandClaude Opus 5.5 ae092990ca Merge feat/sitesmith-ui into release/sitesmith-colors
Conflict: craft/package.json scripts (kept mobile, colour and sitesmith e2e entries).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:55:05 -08:00
shadowdaoandClaude Opus 5.5 57734fbe51 Merge feat/sitesmith-hook into release/sitesmith-colors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:54:46 -08:00
shadowdaoandClaude Opus 5.5 6decf8cdb0 Merge feat/color-system into release/sitesmith-colors
Conflicts: package.json (kept both test:browser:mobile and the colour scripts);
head-parity test (kept E_icons from mobile-parity/main AND the E_brand_swatches /
F_swatches_no_brand cases from color-system; pinned bytes re-derived later
against the merged WHP script).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:54:46 -08:00
shadowdaoandClaude Sonnet 5.5 cfa8ab2e40 Sitesmith modal: load assets once; clearer oversize-image message
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:52:56 -08:00
shadowdaoandClaude Sonnet 5.5 304850fcd3 Sitesmith e2e: Firefox + Chromium end-to-end test of the modal (npm run test:browser:sitesmith)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:48:12 -08:00
shadowdaoandClaude Sonnet 5.5 a406daae1e Sitesmith e2e: reusable mock editor + Sitesmith backend server for real-browser tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:48:12 -08:00
shadowdaoandClaude Sonnet 5.5 8a481a87d8 Sitesmith modal: flow tests (phases, cancel, resume, errors, vision off, sites/assets payload, self-review round trip)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:43:23 -08:00
shadowdaoandClaude Sonnet 5.5 784d85346e Sitesmith: tests for payload, design, attachments, panels, self-review runner
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:40:55 -08:00
shadowdaoandClaude Sonnet 5.5 79159dcb28 Sitesmith modal: live job status, cancel, resume, attachments, Sites I like, asset awareness, self-review toggle, design in the request
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:39:47 -08:00
shadowdaoandClaude Sonnet 5.5 f0b3dd1dba Sitesmith capture: CSS judged via CSSOM (no regex), single URL gate (no % / dot segments / backslash), all resources inlined through a bounded no-credentials fetch, CSP img-src data: only; bypass-class proof tests (unit + Firefox/Chromium)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:37:56 -08:00
shadowdaoandClaude Sonnet 5.5 c4f45541a3 Sitesmith: contrast repair wired into apply-ai-response; scoped guard exception for the script-less capture frame
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:32:50 -08:00
shadowdaoandClaude Sonnet 5.5 197b9c46ab Sitesmith self-review capture: sanitise page HTML before it reaches the frame (inert DOMParser allow-list, fixed-point guard), CSP + script-less sandbox, real-browser hostile-page proof; UI building blocks (attachments, sites I like, asset awareness, design payload)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:31:29 -08:00
shadowdaoandClaude Sonnet 5.5 0fde4dc22f Sitesmith: contrast auto-repair for model responses; capture module (html-to-image) for self-review
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:23:26 -08:00
shadowdaoandClaude Sonnet 5.5 7627be78dc SwatchManager chooser: readable text colour and a visible chip border on dark colours
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:12:58 -08:00
shadowdaoandClaude Sonnet 5.5 75bd5921da Real-editor colour-system e2e (Firefox + Chromium): hex entry, pick from page/image, palette, persistence, brand recolour canvas==frontend==backend, caps, contrast
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:12:38 -08:00
shadowdaoandClaude Sonnet 5.5 c4b6802cab Add real-browser mobile parity test (Firefox + Chromium, 390/1280)
npm run test:browser:mobile; MOBILE_PARITY_RECORD/BASELINE compare desktop boxes against a base-commit snapshot.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:10:15 -08:00
shadowdaoandClaude Sonnet 5.5 2e5492600e Editor: mirror default mobile column stacking (canvas emulation + Stack toggle)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:10:15 -08:00
shadowdaoandClaude Sonnet 5.5 69fd34bd7c Preview/Published head: stack ColumnLayout on phones, wrap Navbar links, emit Font Awesome
- <=767px: [class^=cols_] wrappers (every ColumnLayout split) stack; a mobile flexDirection:row override still opts out.
- <=767px: navbars without a hamburger wrap instead of overflowing.
- wrapInDocument emits the same Font Awesome links as the backend sb_font_awesome_link (Preview is a sandboxed srcdoc iframe).
- head-parity pins updated (+ E_icons case).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:10:15 -08:00
shadowdaoandClaude Sonnet 5.5 79cdd593d9 Navbar: showMobileMenu defaults to true for new Navbars and the seeded header
Existing Navbars (prop absent/false) are untouched: render default and toHtml stay falsy.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:10:15 -08:00
shadowdaoandClaude Sonnet 5.5 501f276746 Colour pick mode: header/footer zone previews (pointer-events:none) are now pickable
Found by the real-editor e2e: picking over the header or its logo box returned the page colour behind it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:09:39 -08:00
shadowdaoandClaude Sonnet 5.5 ba5611c3e3 Inline contrast in Text, Button, Pricing and Nav/Footer panels (effective background from node parents)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:02:57 -08:00
shadowdaoandClaude Sonnet 5.5 dcf9c92fee Site Design panel: Saved colours section + inline contrast on text/muted/link/primary-button
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:01:21 -08:00
shadowdaoandClaude Sonnet 5.5 d83919b89a feat(sitesmith): renderer for Sitesmith responses (repo exporter + Firefox shots); catalog tips for ColumnLayout stacking, Navbar, Footer
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:01:04 -08:00
shadowdaoandClaude Sonnet 5.5 faaa8a87a0 Site Design: SwatchManager (saved colours, brand toggle, guarded delete/un-brand, use-as-site-colour, pick + palette)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 10:00:51 -08:00
shadowdaoandClaude Sonnet 5.5 c34690d08b Colour fields: hex validation, brand chips, pick tools, save colour, inline contrast prop; gradient parse accepts brand refs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:58:55 -08:00
shadowdaoandClaude Sonnet 5.5 150c84065b TokenSwatchRow: saved colours after the site tokens (brand = live ring + token ref)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:57:17 -08:00
shadowdaoandClaude Sonnet 5.5 9c61f41079 Site colours: replaceBrandRef + PageContext siteStateStrings/rewriteSiteStates for brand-ref rewriting
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:56:55 -08:00
shadowdaoandClaude Sonnet 5.5 2f5c311118 Sitesmith hook: start+poll transport, failure-safe results, refs/assets wrappers
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:54:55 -08:00
shadowdaoandClaude Sonnet 5.5 179aaebe49 Colour picking: native EyeDropper + in-canvas pick mode with brand/token matching, real-browser e2e
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:54:33 -08:00
shadowdaoandClaude Sonnet 5.5 54920dff08 Site colours: pick-from-image and palette-from-image modals
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:53:13 -08:00
shadowdaoandClaude Sonnet 5.5 e4ba07b47e ContrastNote: inline low-contrast hint with suggestion
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:53:05 -08:00
shadowdaoandClaude Sonnet 5.5 de240eee75 feat(sitesmith): catalog generator from real component/section/template definitions + drift test
craft/scripts/gen-sitesmith-catalog.mjs emits a compact JSON catalog (props with
TS types/enums/defaults, token-aware colour props, animation + icon support,
child rules, section recipes, templates, palettes) for the WHP panel prompt.
src/sitesmith/catalog.drift.test.ts regenerates and compares to the committed
whp file so drift fails.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:52:49 -08:00
shadowdaoandClaude Sonnet 5.5 453268a31c Publish checks: button + site-level contrast via checkContrast, unchecked info line
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:52:44 -08:00
shadowdaoandClaude Sonnet 5.5 fb9ac0e6c4 Site colours: real-browser check for image sampling + palette (Firefox + Chromium)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:52:40 -08:00
shadowdaoandClaude Sonnet 5.5 39e954bd77 Contrast: pure WCAG checkContrast/suggestFix/siteColorPairs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:51:57 -08:00
shadowdaoandClaude Sonnet 5.5 e09a87d2a6 Site colours: palette extraction + same-origin image sampling utils
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:51:47 -08:00
shadowdaoandClaude Sonnet 5.5 1190a98265 tokens: isTokenRef accepts brand token names (digits)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:51:32 -08:00
shadowdaoandClaude Sonnet 5.5 c388be7fe7 Head parity: pin brand-colour swatch cases (E, F) from the WHP script
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 09:50:25 -08:00