diff --git a/playwriter/package.json b/playwriter/package.json index b66dd49..baed79e 100644 --- a/playwriter/package.json +++ b/playwriter/package.json @@ -50,6 +50,8 @@ "hono": "^4.10.6", "kill-port-process": "^3.2.1", "playwright-core": "^1.56.1", + "posthtml": "^0.16.7", + "posthtml-beautify": "^0.7.0", "string-dedent": "^3.0.2", "strip-ansi": "^7.1.2", "user-agents": "^1.1.669", diff --git a/playwriter/src/htmlrewrite.test.ts b/playwriter/src/htmlrewrite.test.ts new file mode 100644 index 0000000..dce0f97 --- /dev/null +++ b/playwriter/src/htmlrewrite.test.ts @@ -0,0 +1,14848 @@ +import { expect, test } from 'vitest' +import { formatHtmlForPrompt } from './htmlrewrite.js' + +test('formatHtmlForPrompt', async () => { + const res = await fetch('https://framer.com') + // const html = await res.text() + const newHtml = await formatHtmlForPrompt(res) + expect(newHtml).toMatchInlineSnapshot( + ` + " + + +
+
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+

+ Developers +

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
Search
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ Developers +

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
Search
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + +
+
+

Build better sites, faster

+
+
+

Framer is the design tool for websites. Design freely, publish fast, and scale with CMS, SEO, analytics, and more.

+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+ Website made in Framer +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
    + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Create, collaborate, and go live

+
+
+
+
+
+
+
+
+
+

+ AI +

+
+
+

Generate site layouts and advanced components in seconds with AI, so you can skip the blank canvas and start designing with confidence.

+
+
+ +
+
+
+
+
+
+

+ Design +

+
+
+

Craft responsive layouts and bring them to life with smooth effects, interactions, and animations. Build exactly what you imagine, visually.

+
+
+ +
+
+
+
+
+
+

+ CMS +

+
+
+

Manage and update your content effortlessly with a built-in CMS. Keep your site fresh without touching code.

+
+
+ +
+
+
+
+
+
+

+ Collaborate +

+
+
+

Whether you’re collaborating on the canvas or editing copy directly on the page, updates are seamless and handoff-free.

+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+ A smiling person with short hair, wearing a dark shirt, against a backdrop of blue sky and clouds. +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+ +
+

Wireframer

+
+ +
+
+
+
+ +
+
+
+
+
+
+ UI +
+
+
+

+ I + created + three + unique + landing + pages + in + dark + mode + for + your + modern + design + startup: + a + main + landing + page, + a + creative-focused + page, + and + a + studio + showcase + page. +

+
+
+
+
+
+ +
+
+
+
+
+
+
+

Landing Page 1

+
+
+
+ Example of a page generated by Wireframer +
+
+
+
+
+
+
+ +
+
+
+

Landing Page 2

+
+
+
+
+ Example of a page generated by Wireframer +
+
+
+
+
+

Landing Page 3

+

+
+

+
+
+
+ Example of a page generated by Wireframer +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

100%

+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+ +
+
+
+

Benjamin

+
+
+
+
+
+ +
+
+
+

Paul

+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

100%

+
+ +
+
+
+
+ Framer canvas +
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+ +
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+

Title

+
+
+

Image

+
+
+

Date

+
+
+

Category

+
+
+

Slug

+
+
+
+
+ +
+

Search 153 items…

+
+
+
+
+
+
+ +
+

Stagger Effects

+
+
+
+
+
+ Stagger +
+
+
+
+

Sep 25, 2025

+
+
+

Canvas

+
+
+

stagger-effects

+
+
+
+
+
+
+ +
+

Text Search Plugin

+
+
+
+
+
+ Stagger +
+
+
+
+

Sep 24, 2025

+
+
+

Canvas

+
+
+

text-search-plugin

+
+
+
+
+
+
+ +
+

Lightbox Effect

+
+
+
+
+
+ Lightbox +
+
+
+
+

Sep 22, 2025

+
+
+

Canvas

+
+
+

lightbox-effect

+
+
+
+
+
+
+ +
+

Font Drop 15

+
+
+
+
+
+ Font Drop 15 +
+
+
+
+

Sep 21, 2025

+
+
+

Canvas

+
+
+

font-drop-15

+
+
+
+
+
+
+ +
+

Fit Image

+
+
+
+
+
+ +
+
+
+
+

Sep 17, 2025

+
+
+

Canvas

+
+
+

fit-image

+
+
+
+
+
+
+ +
+

Design Pages

+
+
+
+
+
+ +
+
+
+
+

Sep 16, 2025

+
+
+

Canvas

+
+
+

design-pages

+
+
+
+
+
+
+ +
+

Icon Set: Sargam

+
+
+
+
+
+ Sargam Icon Set +
+
+
+
+

Sep 15, 2025

+
+
+

Canvas

+
+
+

icon-set-sargam

+
+
+
+
+
+
+ +
+

Rolldown Bundler

+
+
+
+
+
+ Rolldown Bundler in Framer +
+
+
+
+

Sep 8, 2025

+
+
+

Canvas

+
+
+

rolldown

+
+
+
+
+
+
+ +
+

Usage Monitoring

+
+
+
+
+
+ Stagger +
+
+
+
+

Sep 5, 2025

+
+
+

Canvas

+
+
+

usage-monitoring

+
+
+
+
+
+
+ +
+

September Update: Multi Select Pages and Assets

+
+
+
+
+
+ Multi-Select for Pages and Assets +
+
+
+
+

Sep 4, 2025

+
+
+

Canvas

+
+
+

september-update-2025

+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+

Title

+
+
+
+

Stagger Effects

+
+
+
+
+
+
+

Image

+
+
+
+
+ Stagger +
+
+
+

stagger-effects.jpg

+
+
+
+
+
+

Categories

+
+
+
+
+
+

Canvas

+
+ +
+
+
+ +
+
+
+
+
+

Slug

+
+
+
+

stagger-effects

+
+
+
+
+ +
+

framer.com/updates/stagger-effects

+
+
+
+
+
+

Content

+
+
+
+
+ + + Paragraph +
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+

Introducing Stagger, a new property for Appear Effects in Framer. Stagger is now available on any layer within a Collection List, so it’s ideal for CMS-based layouts. You can find it within the Transition properties. Just like the Lightbox Effect before it, this lets you benefit from using the CMS in your designs, as you can now add sequenced animations with a single click. A simple editing experience for your content, with the flexibility to add motion. Available now in Framer.

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Baseform®

+
+
+
+
+
+
+
+
+
+
+
+

Art Direction

+
+
+
+
+
+
+
+
+
+
+

Visual Design

+
+
+
+
+
+
+
+
+
+
+
+
+

Work,

+
+
+
+
+
+
+
+
+
+
+

Archive,

+
+
+
+
+
+
+
+
+
+
+

Profile,

+
+
+
+
+
+
+
+
+
+
+

Journal

+
+
+
+
+
+
+
+
+
+
+
+

Let's Talk

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Latest News

+
+
+
+
+
+
+
+
+
+
+

View All Posts

+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+ Photo +
+
+
+
+
+
+
+
+
+
+ Photo +
+
+
+
+
+
+
+
+
+
+
+ Photo +
+
+
+
+
+
+
+
+
+
+ Photo +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+

Click to edit

+
+
+

·

+
+
+

Changes are auto-saved

+
+
+
+
+

Site saved

+
+
+

·

+
+
+

Collaborators are notified. Changes will be visible once the project is published.

+
+
+
+
+
+ +
+
+

Open in Framer

+
+
+
+
+ +
+

Finish Editing

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ AI +
+
+
+

Generate page layouts and advanced components in seconds with AI, so you can skip the blank canvas and start designing with confidence.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ AI +
+
+
+

Generate page layouts and advanced components in seconds with AI, so you can skip the blank canvas and start designing with confidence.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ AI +
+
+
+

Generate page layouts and advanced components in seconds with AI, so you can skip the blank canvas and start designing with confidence.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Design
+
+
+

Craft responsive layouts and bring them to life with smooth effects, interactions, and animations. Build exactly what you imagine, visually.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Design
+
+
+

Craft responsive layouts and bring them to life with smooth effects, interactions, and animations. Build exactly what you imagine, visually.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Design
+
+
+

Craft responsive layouts and bring them to life with smooth effects, interactions, and animations. Build exactly what you imagine, visually.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
CMS
+
+
+

Manage and update your content effortlessly with a built-in CMS. Keep your site fresh without touching code.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
CMS
+
+
+

Manage and update your content effortlessly with a built-in CMS. Keep your site fresh without touching code.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
CMS
+
+
+

Manage and update your content effortlessly with a built-in CMS. Keep your site fresh without touching code.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Collaborate
+
+
+

Whether you’re collaborating on the canvas or editing copy directly on the page, updates are seamless and handoff-free.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Collaborate
+
+
+

Whether you’re collaborating on the canvas or editing copy directly on the page, updates are seamless and handoff-free.

+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
Collaborate
+
+
+

Whether you’re collaborating on the canvas or editing copy directly on the page, updates are seamless and handoff-free.

+
+
+ +
+
+
+
+
+
+
+
+
+

Scale without switching tools

+
+
+
+
+
+
+ 3D render +
+
+
+
+
Analytics & insights
+
+
+

Track traffic, measure performance, and monitor conversions.

+
+
+ +
+
+
+
+
+
+
+

September 26, 2025

+
+
+
+
+
+

Pageviews

+
+
+

258,156

+
+
+
+
+
+

Visitors

+
+
+

85,458

+
+
+
+
+
+
+
+
+
+

Overview

+
+
+
+
+
+
+
+
+
+
+
+

Live Visitors

+
+
+
+
400
+
+
+
+
+

Unique Visitors

+
+
+
1.7M
+
+
+
+
+

Total Pageviews

+
+
+
3.2M
+
+
+
+
+
+
+

330k

+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+

Sources

+
+
+
+

Referrer

+
+ +
+
+
+
+
+
+
+
+
+ +
+
+

google.com

+
+
+

436K

+
+
+
+
+ +
+
+

chatgpt.com

+
+
+

189K

+
+
+
+
+ +
+

linkedin.com

+
+
+
+

96K

+
+
+
+
+ + +
+
+

youtube.com

+
+
+
+

82K

+
+
+
+
+ +
+
+

bing.com

+
+
+

71K

+
+
+
+
+ +
+

x.com

+
+
+

49K

+
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+

All

+
+ +
+
+
+
+ +
+

Home

+
+
+

1.8M

+
+
+
+
+ +
+

/pricing

+
+
+
+

156K

+
+
+
+ +
+

/gallery

+
+
+

91K

+
+
+
+
+ +
+

/updates

+
+
+

44K

+
+
+
+
+ +
+

/features/design

+
+
+

39K

+
+
+
+
+
+ +
+

/features/cms

+
+
+

27K

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
Analytics & insights
+
+
+

Track traffic, measure performance, and monitor conversions.

+
+
+ +
+
+
+
+
+
+
+

September 26, 2025

+
+
+
+
+
+

Pageviews

+
+
+

258,156

+
+
+
+
+
+

Visitors

+
+
+

85,458

+
+
+
+
+
+
+
+
+
+

Overview

+
+
+
+
+
+
+
+
+
+
+
+

Live Visitors

+
+
+
+
400
+
+
+
+
+

Unique Visitors

+
+
+
1.7M
+
+
+
+
+

Total Pageviews

+
+
+
3.2M
+
+
+
+
+
+
+

330k

+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+

Sources

+
+
+
+

Referrer

+
+ +
+
+
+
+
+
+
+
+
+ +
+
+

google.com

+
+
+

436K

+
+
+
+
+ +
+
+

chatgpt.com

+
+
+

189K

+
+
+
+
+ +
+

linkedin.com

+
+
+
+

96K

+
+
+
+
+ + +
+
+

youtube.com

+
+
+
+

82K

+
+
+
+
+ +
+
+

bing.com

+
+
+

71K

+
+
+
+
+ +
+

x.com

+
+
+

49K

+
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+

All

+
+ +
+
+
+
+ +
+

Home

+
+
+

1.8M

+
+
+
+
+ +
+

/pricing

+
+
+
+

156K

+
+
+
+ +
+

/gallery

+
+
+

91K

+
+
+
+
+ +
+

/updates

+
+
+

44K

+
+
+
+
+ +
+

/features/design

+
+
+

39K

+
+
+
+
+
+ +
+

/features/cms

+
+
+

27K

+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
Analytics & insights
+
+
+

Track traffic, measure performance, and monitor conversions.

+
+
+ +
+
+
+
+
+
+
+

September 26, 2025

+
+
+
+
+
+

Pageviews

+
+
+

258,156

+
+
+
+
+
+

Visitors

+
+
+

85,458

+
+
+
+
+
+
+
+
+
+

Overview

+
+
+
+
+
+
+
+
+
+
+
+

Live Visitors

+
+
+
+
400
+
+
+
+
+

Unique Visitors

+
+
+
1.7M
+
+
+
+
+

Total Pageviews

+
+
+
3.2M
+
+
+
+
+
+
+

330k

+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+

Sources

+
+
+
+

Referrer

+
+ +
+
+
+
+
+
+
+
+
+ +
+
+

google.com

+
+
+

436K

+
+
+
+
+ +
+
+

chatgpt.com

+
+
+

189K

+
+
+
+
+ +
+

linkedin.com

+
+
+
+

96K

+
+
+
+
+ + +
+
+

youtube.com

+
+
+
+

82K

+
+
+
+
+ +
+
+

bing.com

+
+
+

71K

+
+
+
+
+ +
+

x.com

+
+
+

49K

+
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+

All

+
+ +
+
+
+
+ +
+

Home

+
+
+

1.8M

+
+
+
+
+ +
+

/pricing

+
+
+
+

156K

+
+
+
+ +
+

/gallery

+
+
+

91K

+
+
+
+
+ +
+

/updates

+
+
+

44K

+
+
+
+
+ +
+

/features/design

+
+
+

39K

+
+
+
+
+
+ +
+

/features/cms

+
+
+

27K

+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
A/B Testing & optimization
+
+
+

A/B testing, funnels, and built-in growth insights.

+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+
+

Layers

+
+
+
+
+
+

Assets

+
+
+
+
+
+
+
+

Design

+
+ +
+
+
+

Pages

+
+ +
+
+
+ +
+ +
+

Home

+
+
+
+
+
+
+

A

+
+
+
+

Control

+
+
+
+
+
+

B

+
+
+
+

Version B

+
+
+
+
+
+

C

+
+
+
+

Version C

+
+
+
+
+
+ + +
+

/pricing

+
+
+
+
+

A

+
+
+
+
+

B

+
+
+
+
+
+ + +
+

/features

+
+
+
+ + +
+

/blog

+
+
+
+ + +
+

/about

+
+
+
+
+ + +
+

/404

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

Desktop

+
+
+

·

+
+
+

1200

+
+
+
+
+
+
+
+
+ Framer website +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
A/B Testing & optimization
+
+
+

A/B testing, funnels, and built-in growth insights.

+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+
+

Layers

+
+
+
+
+
+

Assets

+
+
+
+
+
+
+
+

Design

+
+ +
+
+
+

Pages

+
+ +
+
+
+ +
+ +
+

Home

+
+
+
+
+
+
+

A

+
+
+
+

Control

+
+
+
+
+
+

B

+
+
+
+

Version B

+
+
+
+
+
+

C

+
+
+
+

Version C

+
+
+
+
+
+ + +
+

/pricing

+
+
+
+
+

A

+
+
+
+
+

B

+
+
+
+
+
+ + +
+

/features

+
+
+
+ + +
+

/blog

+
+
+
+ + +
+

/about

+
+
+
+
+ + +
+

/404

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

Desktop

+
+
+

·

+
+
+

1200

+
+
+
+
+
+
+
+
+ Framer website +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
A/B Testing & optimization
+
+
+

A/B testing, funnels, and built-in growth insights.

+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+

Pages

+
+
+
+
+

Layers

+
+
+
+
+
+

Assets

+
+
+
+
+
+
+
+

Design

+
+ +
+
+
+

Pages

+
+ +
+
+
+ +
+ +
+

Home

+
+
+
+
+
+
+

A

+
+
+
+

Control

+
+
+
+
+
+

B

+
+
+
+

Version B

+
+
+
+
+
+

C

+
+
+
+

Version C

+
+
+
+
+
+ + +
+

/pricing

+
+
+
+
+

A

+
+
+
+
+

B

+
+
+
+
+
+ + +
+

/features

+
+
+
+ + +
+

/blog

+
+
+
+ + +
+

/about

+
+
+
+
+ + +
+

/404

+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

Desktop

+
+
+

·

+
+
+

1200

+
+
+
+
+
+
+
+
+ Framer website +
+
+
+
+
+
+
+
+
+
+
+
+
+ Framer UI +
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
SEO & performance
+
+
+

Optimize every page with built-in SEO settings, metadata, and blazing-fast hosting.

+
+
+ +
+
+
+
+
+
+ +
+

Google Lighthouse

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

SEO

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Performance

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Accessibility

+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
SEO & performance
+
+
+

Optimize every page with built-in SEO settings, metadata, and blazing-fast hosting.

+
+
+ +
+
+
+
+
+
+ +
+

Google Lighthouse

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

SEO

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Performance

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Accessibility

+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ 3D render +
+
+
+
+
SEO & performance
+
+
+

Optimize every page with built-in SEO settings, metadata, and blazing-fast hosting.

+
+
+ +
+
+
+
+
+
+ +
+

Google Lighthouse

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

SEO

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Performance

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
+
+
+
+
+
+

Accessibility

+
+
+
+
+
+
+
+ Lighthouse score +
+
+
+
+
+
+
+
+
+
+
+

Powering ambitious teams worldwide

+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + + + + +
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + + + + +
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + + + + +
+
+
+
+
+
+
+
+
+

Get pro help from handpicked experts

+
+ +
+
+
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+
+
+
+
+
+

Launch faster with community resources

+
+ +
+
+
+ + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

The site builder that gets design

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+

The site builder that gets design

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+

The site builder that gets design

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ + + + " + `, + ) +}) diff --git a/playwriter/src/htmlrewrite.ts b/playwriter/src/htmlrewrite.ts new file mode 100644 index 0000000..0d9258b --- /dev/null +++ b/playwriter/src/htmlrewrite.ts @@ -0,0 +1,193 @@ +import { FlatCache } from 'flat-cache' + +import posthtml from 'posthtml' +import beautify from 'posthtml-beautify' + +export async function formatHtmlForPrompt( + input: Response, +) { + const html = await input.text() + + const tagsToRemove = [ + 'hint', + 'style', + 'link', + 'script', + 'meta', + 'noscript', + 'svg', + 'head', + // 'head', + ] + const attributesToKeep = [ + 'data-framer-name', + // 'class', + // 'id', + 'label', + 'title', + 'alt', + 'href', + 'name', + 'value', + 'checked', + 'placeholder', + 'type', + 'role', + // 'src', + 'target', + 'data-llm-id', + 'vimium-label', + ] + + // Create a custom plugin to remove tags and filter attributes + const removeTagsAndAttrsPlugin = () => { + return (tree) => { + // Remove comments at root level + tree = tree.filter((item) => { + if (typeof item === 'string') { + const trimmed = item.trim() + return !(trimmed.startsWith('')) + } + return true + }) + + // Process each node recursively + const processNode = (node) => { + if (typeof node === 'string') { + return node + } + + // Remove unwanted tags + if (node.tag && tagsToRemove.includes(node.tag.toLowerCase())) { + return null + } + + // Filter attributes + if (node.attrs) { + const newAttrs: typeof node.attrs = {} + for (const [attr, value] of Object.entries(node.attrs)) { + if (attr.startsWith('aria-') || attributesToKeep.includes(attr)) { + newAttrs[attr] = value + } + } + node.attrs = newAttrs + } + + // Process content recursively + if (node.content && Array.isArray(node.content)) { + node.content = node.content + .map(processNode) + .filter(item => { + if (item === null) return false + if (typeof item === 'string') { + const trimmed = item.trim() + return !(trimmed.startsWith('')) + } + return true + }) + } + + return node + } + + // Process all root nodes + return tree.map(processNode).filter(item => item !== null) + } + } + + // Process HTML + const processor = posthtml() + .use(removeTagsAndAttrsPlugin()) + .use(beautify({ + rules: { + indent: 1, // 1-space indent + blankLines: false, // no extra blank lines + maxlen: 100000 // effectively never wrap by content length + }, + jsBeautifyOptions: { + wrap_line_length: 0, // disable js-beautify wrapping + preserve_newlines: false // reduce stray newlines + } + })) + + // Process with await + const result = await processor.process(html) + + return result.html +} + +const htmlCache = new FlatCache({ + cacheDir: '.htmlcache', + cacheId: 'htmlcache.json', + lruSize: 100, +}) +export async function fetchFormattedHtml({ + url, + signal, + timeout = 5000, +}: { + url: string + signal?: AbortSignal + timeout?: number +}): Promise { + if (!url) { + return '' + } + if (htmlCache.get(url)) { + return htmlCache.get(url) || '' + } + // if there is no https:// or http:// prefix, add it + if (!url.startsWith('https://') && !url.startsWith('http://')) { + url = 'https://' + url + } + console.time(`fetchFormattedHtml: ${url}`) + + const controller = new AbortController() + const timeoutId = setTimeout(() => { + controller.abort() + }, timeout) + + if (signal) { + signal.addEventListener('abort', () => { + controller.abort() + }) + } + + try { + const res = await fetch(url, { + headers: { + Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + Connection: 'keep-alive', + 'Upgrade-Insecure-Requests': '1', + // Referer: 'https://www.google.com/', + 'User-Agent': + 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + }, + signal: controller.signal, + }) + + if (!res.ok) { + console.timeEnd(`fetchFormattedHtml: ${url}`) + throw new Error( + `Could not get content, server responded with ${res.status}`, + ) + } + + console.time(`formatHtmlForPrompt: ${url}`) + const formattedHtml = await formatHtmlForPrompt(res) + htmlCache.set(url, formattedHtml) + htmlCache.save(true) + console.timeEnd(`formatHtmlForPrompt: ${url}`) + console.timeEnd(`fetchFormattedHtml: ${url}`) + return formattedHtml + } catch (error) { + if (error.name === 'AbortError') { + console.timeEnd(`fetchFormattedHtml: ${url}`) + throw new Error(`${url} took too long to respond`) + } + throw error + } finally { + clearTimeout(timeoutId) + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d84bfd2..a11e772 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,6 +91,12 @@ importers: playwright-core: specifier: ^1.56.1 version: 1.56.1 + posthtml: + specifier: ^0.16.7 + version: 0.16.7 + posthtml-beautify: + specifier: ^0.7.0 + version: 0.7.0 string-dedent: specifier: ^3.0.2 version: 3.0.2 @@ -1221,6 +1227,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@opentelemetry/api-logs@0.208.0': resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} engines: {node: '>=8.0.0'} @@ -2289,6 +2298,10 @@ packages: '@xmorse/deployment-utils@0.7.2': resolution: {integrity: sha512-iRnHKcuPHK1dGHH+HqWJrPbodeR0mlnmS6yhC0nS5rLkxlgoqq6UK0Xv2/6fL0uLZGoUhopXimaFs1GbYrLH2g==} + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -2618,6 +2631,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -2629,6 +2646,9 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + console-table-printer@2.15.0: resolution: {integrity: sha512-SrhBq4hYVjLCkBVOWaTzceJalvn5K1Zq5aQA6wXC/cYjI3frKWNPEMK3sZsJfNNQApvCQmgBcc13ZKmFj8qExw==} @@ -2794,6 +2814,31 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dom-serializer@0.2.2: + resolution: {integrity: sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==} + + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + domelementtype@1.3.1: + resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@2.4.2: + resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domutils@1.7.0: + resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -2808,6 +2853,11 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2835,6 +2885,16 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + entities@1.1.2: + resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -3217,6 +3277,12 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + htmlparser2@3.10.1: + resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} + + htmlparser2@7.2.0: + resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -3273,6 +3339,9 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -3306,6 +3375,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-json@2.0.1: + resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3350,6 +3422,15 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-tiktoken@1.0.21: resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} @@ -3605,6 +3686,10 @@ packages: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -3691,6 +3776,11 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -3962,6 +4052,29 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + posthtml-beautify@0.7.0: + resolution: {integrity: sha512-g9+tYK5Z1WiYHgEOXt3jmVd6ioG5Hk6wVIw8rYVMqzFBeJzELHcxUk0bxTfYYP715Qrrh/xkwHyXrDL+ETKUgQ==} + engines: {node: '>=10'} + + posthtml-parser@0.11.0: + resolution: {integrity: sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==} + engines: {node: '>=12'} + + posthtml-parser@0.4.2: + resolution: {integrity: sha512-BUIorsYJTvS9UhXxPTzupIztOMVNPa/HtAm9KHni9z6qEfiJ1bpOBL5DfUOL9XAc3XkLIEzBzpph+Zbm4AdRAg==} + + posthtml-render@1.4.0: + resolution: {integrity: sha512-W1779iVHGfq0Fvh2PROhCe2QhB8mEErgqzo1wpIt36tCgChafP+hbXIhLDOM8ePJrZcFs0vkNEtdibEWVqChqw==} + engines: {node: '>=10'} + + posthtml-render@3.0.0: + resolution: {integrity: sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==} + engines: {node: '>=12'} + + posthtml@0.16.7: + resolution: {integrity: sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw==} + engines: {node: '>=12.0.0'} + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -3984,6 +4097,9 @@ packages: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -4069,6 +4185,10 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -4326,6 +4446,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -6070,6 +6193,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@one-ini/wasm@0.1.1': {} + '@opentelemetry/api-logs@0.208.0': dependencies: '@opentelemetry/api': 1.9.0 @@ -7330,6 +7455,8 @@ snapshots: - tsx - yaml + abbrev@2.0.0: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -7672,6 +7799,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@10.0.1: {} + concat-map@0.0.1: {} concurrently@8.2.2: @@ -7688,6 +7817,11 @@ snapshots: confbox@0.2.2: {} + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + console-table-printer@2.15.0: dependencies: simple-wcswidth: 1.1.2 @@ -7814,6 +7948,40 @@ snapshots: dependencies: path-type: 4.0.0 + dom-serializer@0.2.2: + dependencies: + domelementtype: 2.3.0 + entities: 2.2.0 + + dom-serializer@1.4.1: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + domelementtype@1.3.1: {} + + domelementtype@2.3.0: {} + + domhandler@2.4.2: + dependencies: + domelementtype: 1.3.1 + + domhandler@4.3.1: + dependencies: + domelementtype: 2.3.0 + + domutils@1.7.0: + dependencies: + dom-serializer: 0.2.2 + domelementtype: 1.3.1 + + domutils@2.8.0: + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dotenv@16.6.1: {} dunder-proto@1.0.1: @@ -7828,6 +7996,13 @@ snapshots: dependencies: safe-buffer: 5.2.1 + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.3 + ee-first@1.1.1: {} electron-to-chromium@1.5.267: {} @@ -7852,6 +8027,12 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@1.1.2: {} + + entities@2.2.0: {} + + entities@3.0.1: {} + entities@6.0.1: optional: true @@ -8403,6 +8584,22 @@ snapshots: whatwg-encoding: 3.1.1 optional: true + htmlparser2@3.10.1: + dependencies: + domelementtype: 1.3.1 + domhandler: 2.4.2 + domutils: 1.7.0 + entities: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + + htmlparser2@7.2.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 3.0.1 + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -8474,6 +8671,8 @@ snapshots: inherits@2.0.4: {} + ini@1.3.8: {} + ip-address@10.1.0: optional: true @@ -8498,6 +8697,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-json@2.0.1: {} + is-number@7.0.0: {} is-potential-custom-element-name@1.0.1: @@ -8532,6 +8733,16 @@ snapshots: joycon@3.1.1: {} + js-beautify@1.15.4: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.5.0 + js-cookie: 3.0.5 + nopt: 7.2.1 + + js-cookie@3.0.5: {} + js-tiktoken@1.0.21: dependencies: base64-js: 1.5.1 @@ -8770,6 +8981,10 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.2 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 @@ -8831,6 +9046,10 @@ snapshots: node-releases@2.0.27: {} + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + normalize-path@3.0.0: {} npm-run-path@2.0.2: @@ -9094,6 +9313,33 @@ snapshots: dependencies: xtend: 4.0.2 + posthtml-beautify@0.7.0: + dependencies: + '@babel/runtime': 7.28.4 + deepmerge: 4.3.1 + js-beautify: 1.15.4 + posthtml-parser: 0.4.2 + posthtml-render: 1.4.0 + + posthtml-parser@0.11.0: + dependencies: + htmlparser2: 7.2.0 + + posthtml-parser@0.4.2: + dependencies: + htmlparser2: 3.10.1 + + posthtml-render@1.4.0: {} + + posthtml-render@3.0.0: + dependencies: + is-json: 2.0.1 + + posthtml@0.16.7: + dependencies: + posthtml-parser: 0.11.0 + posthtml-render: 3.0.0 + prettier@2.8.8: {} prettier@3.6.2: {} @@ -9105,6 +9351,8 @@ snapshots: progress@2.0.3: optional: true + proto-list@1.2.4: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -9208,6 +9456,12 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -9545,6 +9799,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1