Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
138 commits
Select commit Hold shift + click to select a range
9db4315
feat(cli): create sites from static artifacts
chubes4 Jun 25, 2026
32b33d0
fix(cli): clean up temporary artifact importer
chubes4 Jun 25, 2026
336b7ea
fix(cli): bootstrap artifact import blueprint
chubes4 Jun 25, 2026
55dd6b1
feat(cli): import sites from flexible sources
chubes4 Jun 25, 2026
ba81813
fix(cli): route imports through SSI source payloads
chubes4 Jun 25, 2026
f515e02
Add Figma import handoff endpoint
chubes4 Jun 25, 2026
bf6228e
Create Figma imports from handoff endpoint
chubes4 Jun 25, 2026
22fc12c
Fix Figma handoff blueprint metadata
chubes4 Jun 25, 2026
e84b8ca
Open Figma handoff sites with admin login
chubes4 Jun 25, 2026
989eecd
Route Figma handoff through SSI importer
chubes4 Jun 25, 2026
e9234f1
Adapt Figma plugin payloads for SSI imports
chubes4 Jun 26, 2026
8daeb8b
Surface Figma handoff request diagnostics
chubes4 Jun 26, 2026
5e5323e
Trigger CI rerun
chubes4 Jul 22, 2026
241e0a9
Stabilize remote session IPC tests
chubes4 Jul 22, 2026
c22dcf7
Stage Figma sources for bounded imports
chubes4 Jul 22, 2026
7763590
Exclude CLI E2E tests from unit lane
chubes4 Jul 23, 2026
5049e40
Run static site imports outside Blueprints
chubes4 Jul 31, 2026
442c5b4
Request complete URL site collection
chubes4 Jul 31, 2026
31afb3a
Allow larger source assets
chubes4 Jul 31, 2026
26e01d8
Resume bounded static site imports
chubes4 Aug 1, 2026
87dafe6
Stream long static import output
chubes4 Aug 1, 2026
d2dc790
Remove Figma handoff from static importer
chubes4 Aug 3, 2026
7d9299b
Stabilize streamed output unit test
chubes4 Aug 4, 2026
d94f2e1
Pin Static Site Importer 1.4.0
chubes4 Aug 4, 2026
62affc4
fix(cli): use canonical URL import orchestration
chubes4 Aug 10, 2026
6ad7433
fix(cli): bootstrap static imports before execution
chubes4 Aug 12, 2026
8159b0a
Stage static import payloads outside PHP
chubes4 Aug 12, 2026
22ef991
Explore portable liberation capture handoff
chubes4 Aug 12, 2026
dd28c8a
Fix portable capture export fidelity
chubes4 Aug 12, 2026
4c7afb4
Format portable capture handoff
chubes4 Aug 12, 2026
e94d531
fix(cli): load plugins before static imports
chubes4 Aug 12, 2026
6bbb4d4
fix(cli): use canonical static import ability
chubes4 Aug 12, 2026
8df86aa
Rebuild Data Liberation MCP bundle
chubes4 Aug 12, 2026
0a3b5e9
fix(dla): preserve portable runtime dependencies
chubes4 Aug 12, 2026
ca844ad
fix(dla): preserve fetch preload dependencies
chubes4 Aug 12, 2026
b0a65b3
fix(dla): localize runtime data media
chubes4 Aug 12, 2026
a4243c0
fix(dla): constrain inline media discovery
chubes4 Aug 12, 2026
c763814
feat(dla): expose portable website capture
chubes4 Aug 13, 2026
f530d95
feat(cli): capture websites for static imports
chubes4 Aug 13, 2026
859c900
fix(cli): resume static import dependencies
chubes4 Aug 13, 2026
d936972
fix(dla): normalize responsive website captures
chubes4 Aug 14, 2026
984ac46
fix(dla): prune inert capture wrappers
chubes4 Aug 14, 2026
95c8563
fix(cli): preserve SQLite across Blueprints
chubes4 Aug 14, 2026
2c9fb22
fix(cli): persist client-canonical block content
chubes4 Aug 14, 2026
12378a2
style(cli): format canonicalization flow
chubes4 Aug 14, 2026
cd52d4f
Rebuild Data Liberation bundles
chubes4 Aug 14, 2026
333649f
fix(cli): run website capture without MCP transport
chubes4 Aug 14, 2026
5fc7836
feat(cli): create sites from Figma files
chubes4 Aug 16, 2026
1bd2026
fix(cli): import Figma site frames
chubes4 Aug 16, 2026
4bddb24
fix(data-liberation): sanitize mobile HTML capture
chubes4 Aug 16, 2026
3139d16
fix(cli): bound static import failure diagnostics
chubes4 Aug 16, 2026
62c027e
fix(data-liberation): bound portable capture artifacts
chubes4 Aug 17, 2026
9c1f4e1
feat(cli): install local Static Site Importer packages
chubes4 Aug 17, 2026
512028d
fix(data-liberation): bound portable capture exports
chubes4 Aug 21, 2026
0eba44f
fix(dla): localize Wix media variants
chubes4 Aug 19, 2026
a0443b3
build(dla): refresh capture bundles
chubes4 Aug 21, 2026
ac57faf
feat(dla): reconstruct portable site artifacts
chubes4 Aug 19, 2026
ca0f85b
fix(dla): resolve portable carry routes
chubes4 Aug 19, 2026
3b1ed6d
fix(dla): omit carried document metadata
chubes4 Aug 19, 2026
8898c1c
fix(dla): remove uncaptured runtime scripts
chubes4 Aug 21, 2026
d780b25
fix(cli): carry SSI compile checkpoints
chubes4 Aug 21, 2026
3484a86
fix(dla): discover complete portable Wix routes
chubes4 Aug 21, 2026
72396c5
fix(cli): bound stored static import results
chubes4 Aug 21, 2026
5d4d57d
fix(dla): remove uncaptured scripts safely
chubes4 Aug 21, 2026
2aec64c
fix(dla): derive canonical homepage from captured HTML
chubes4 Aug 21, 2026
7aa02ac
fix(cli): retain URL identity after capture
chubes4 Aug 21, 2026
6f2f43b
Make URL artifact capture single-pass
chubes4 Aug 22, 2026
a60d756
fix(dla): replace dangling media references
chubes4 Aug 21, 2026
5270d15
Improve static site import progress diagnostics
chubes4 Aug 22, 2026
a981852
fix(dla): bound captured site amplification
chubes4 Aug 22, 2026
d8cd299
fix(dla): preserve capture alignment and route precedence
chubes4 Aug 22, 2026
5336dfd
feat(dla): capture triggered dialog states
chubes4 Aug 22, 2026
72a3f21
fix(dla): preserve interactive static site runtimes
chubes4 Aug 22, 2026
aeccf8c
fix(cli): bound telemetry request lifetimes
chubes4 Aug 22, 2026
d8e8651
fix(dla): sanitize shared style media
chubes4 Aug 22, 2026
2809783
fix(dla): replace shared styles through DOM
chubes4 Aug 22, 2026
55c9654
fix(cli): close block validators after import
chubes4 Aug 21, 2026
fdca2f6
fix(cli): close shared browser after import
chubes4 Aug 21, 2026
2378efc
fix(dla): export semantic responsive captures
chubes4 Aug 22, 2026
cbc8f42
fix(dla): capture mobile section evidence
chubes4 Aug 23, 2026
353b736
fix(cli): preserve static import failure diagnostics
chubes4 Aug 23, 2026
5cd3072
fix(dla): localize captured section media
chubes4 Aug 23, 2026
e424953
feat(dla): emit layout geometry proof
chubes4 Aug 23, 2026
ce7f11f
fix(dla): bind geometry proof to normalized HTML
chubes4 Aug 23, 2026
83d71d3
fix(dla): preserve nested geometry identities
chubes4 Aug 23, 2026
67ff367
fix(cli): retain requested import receipt
chubes4 Aug 23, 2026
69d820e
fix(dla): preserve bounded import dependencies
chubes4 Aug 23, 2026
1f80953
fix(cli): allow isolated captured client assets
chubes4 Aug 23, 2026
b49151f
fix(cli): allow isolated artifact runtimes
chubes4 Aug 23, 2026
aa11473
fix(dla): make screenshot capture opt-in
chubes4 Aug 24, 2026
72458f6
fix(dla): compare equivalent screenshot surfaces
chubes4 Aug 24, 2026
9a674b7
fix(cli): use Static Site Importer 1.7.0
chubes4 Aug 24, 2026
d9c0854
test: allow full app boot under suite load
chubes4 Aug 24, 2026
b490987
fix(dla): align screenshots with settled html
chubes4 Aug 24, 2026
ca8972b
fix(cli): retain semantic capture evidence
chubes4 Aug 24, 2026
a833395
fix(cli): bound import script size
chubes4 Aug 24, 2026
4b7fba1
fix(cli): preserve staged import state on resume
chubes4 Aug 24, 2026
c194968
fix(dla): bound capture finalization memory
chubes4 Aug 24, 2026
dd36ef2
fix(dla): preserve responsive media variants
chubes4 Aug 24, 2026
eb1d005
fix(dla): bound browser resource capture
chubes4 Aug 24, 2026
c5d1943
fix(dla): bound browser resource capture
chubes4 Aug 24, 2026
c6e913c
Merge origin/trunk into feat/site-artifact-import-cli
chubes4 Aug 24, 2026
08cecfb
fix(cli): enforce canonical static import contract
chubes4 Aug 24, 2026
ec57bdb
fix(cli): preserve staged import state on resume
chubes4 Aug 24, 2026
3c33353
fix(dla): preserve responsive media variants
chubes4 Aug 24, 2026
90b0fb8
Merge remote-tracking branch 'origin/feat/site-artifact-import-cli' i…
chubes4 Aug 25, 2026
4039bce
fix(cli): retain capture routes and report progress
chubes4 Aug 25, 2026
a072ce8
fix(dla): preserve declarative HubSpot forms
chubes4 Aug 25, 2026
f0aa975
fix(cli): resume static artifact imports
chubes4 Aug 25, 2026
6f432a9
refactor(cli): route URL imports through Data Liberation
chubes4 Aug 25, 2026
65d0661
refactor(cli): narrow the Data Liberation handoff
chubes4 Aug 25, 2026
a30a09f
refactor(cli): remove direct SSI URL imports
chubes4 Aug 25, 2026
ecfcc58
refactor(cli): consolidate import orchestration
chubes4 Aug 25, 2026
174f11b
fix(dla): budget portable media from the remaining artifact capacity
aagam-shah Aug 25, 2026
48ec28d
fix(dla): negotiate browser image formats when downloading media
aagam-shah Aug 25, 2026
abd13b2
fix(cli): bound the stored static import receipt
aagam-shah Aug 25, 2026
4729515
fix(dla): avoid false resource capture failures
chubes4 Aug 25, 2026
612bcec
fix(dla): capture mobile render dependencies
chubes4 Aug 25, 2026
54bedce
fix(dla): bound dialog interaction discovery
chubes4 Aug 25, 2026
ebb7064
fix(dla): capture mobile-only dialog interactions
chubes4 Aug 25, 2026
ae9971b
fix(dla): continue dialog capture after false candidates
chubes4 Aug 25, 2026
34caad2
style(dla): format dialog capture
chubes4 Aug 25, 2026
1f3e92c
test(dla): stabilize constrained heap export coverage
chubes4 Aug 25, 2026
b6765ac
Merge trunk into site artifact import CLI
chubes4 Aug 25, 2026
eb2e73d
fix(cli): use command logger for URL capture
chubes4 Aug 25, 2026
06addad
fix(cli): bound static import result receipts
chubes4 Aug 25, 2026
52a7a65
fix(dla): scope Wix discovery to source path
chubes4 Aug 25, 2026
289c6d7
Merge Studio PR #4674: negotiate browser image formats
chubes4 Aug 26, 2026
95d781c
Merge Studio PR #4675: budget portable media capacity
chubes4 Aug 26, 2026
67ca1ad
Merge Studio PR #4676 and make import fixtures portable
chubes4 Aug 26, 2026
4c83bef
test(dla): align suite timeout with standalone
chubes4 Aug 26, 2026
b163a07
test(cli): make create fixtures portable
chubes4 Aug 26, 2026
49af6ec
Merge remote-tracking branch 'origin/trunk' into fix/pr3952-wix-subpa…
chubes4 Aug 26, 2026
dbd9e2b
fix(dla): preserve Wix same-page anchor targets
chubes4 Aug 26, 2026
dffeb6b
fix(dla): keep mobile CSS when responsive bodies match
ellenbauer Aug 26, 2026
0998e3d
fix(cli): report honest progress for direct-artifact imports
ellenbauer Aug 26, 2026
05c1935
fix(dla): collapse canonical duplicate routes
chubes4 Aug 27, 2026
ea170f0
fix(dla): name Wix pages from nav label or slug when every page share…
ellenbauer Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .buildkite/commands/run-unit-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,4 @@ else
fi

echo '--- :npm: Run Unit Tests'
npm run test

npm run test -- --tagsFilter='!e2e'
29 changes: 29 additions & 0 deletions apps/cli/ai/block-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ export interface ValidationReport extends ValidationReportBase {
proposedFix?: BlockFixProposal;
}

/** Serialize content exactly as the target site's registered editor would save it. */
export async function canonicalizeBlocks( content: string, siteUrl: string ): Promise< string > {
const editorPage = getEditorPage( siteUrl );

try {
const page = await editorPage.getPage();
return await page.evaluate( ( html: string ) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const wpBlocks = ( window as any ).wp?.blocks;
if ( ! wpBlocks ) {
throw new Error( 'wp.blocks is not available on this page.' );
}

const canonical = wpBlocks.serialize( wpBlocks.parse( html ) );
if ( canonical !== wpBlocks.serialize( wpBlocks.parse( canonical ) ) ) {
throw new Error( 'The target block registry did not produce a stable serialization.' );
}

return canonical;
}, content );
} catch ( error ) {
await editorPage.close();
editorPages.delete( siteUrl );
throw new Error(
`Block canonicalization error: ${ error instanceof Error ? error.message : String( error ) }`
);
}
}

// Cache one EditorPage per site URL so repeated validations reuse the same
// browser tab instead of navigating and loading the block editor each time.
const editorPages = new Map< string, EditorPage >();
Expand Down
104 changes: 13 additions & 91 deletions apps/cli/ai/tools/data-liberation.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,14 @@
import { existsSync } from 'fs';
import path from 'path';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { Type } from 'typebox';
import { ensurePlaywrightChromiumInstalled } from '../browser-utils';
import {
callDataLiberationTool,
getDataLiberationEngineDir,
listDataLiberationTools,
} from 'cli/lib/data-liberation-client';
import { defineTool } from './define-tool';
import { textResult } from './utils';

const engineDir = path.join( import.meta.dirname, 'data-liberation-agent' );

// Engine ops (extract/screenshot/reconstruct) routinely run for minutes; the MCP SDK's
// 60 s default times them out (-32001) even though the engine keeps working.
const ENGINE_CALL_TIMEOUT_MS = 600_000;

let chromiumPromise: Promise< void > | null = null;

function ensureEngineChromium(): Promise< void > {
if ( ! chromiumPromise ) {
chromiumPromise = ( async () => {
const { chromium } = await import( 'playwright' );
const problem = await ensurePlaywrightChromiumInstalled( chromium );
if ( problem ) {
chromiumPromise = null; // allow a retry on the next tool call
console.error(
`[data_liberation] ${ problem } Browser-dependent steps (extract/screenshot/reconstruct) may fail.`
);
}
} )();
}
return chromiumPromise;
}

let clientPromise: Promise< Client > | null = null;

function getClient(): Promise< Client > {
if ( ! clientPromise ) {
clientPromise = connectClient().catch( ( error ) => {
clientPromise = null;
throw error;
} );
}
return clientPromise;
}

async function connectClient(): Promise< Client > {
if ( ! existsSync( path.join( engineDir, 'dist', 'mcp-server.bundle.mjs' ) ) ) {
throw new Error(
'Data Liberation engine is not compiled. Run `npm run cli:build` — it builds the ' +
'`data-liberation` MCP bundle and copies it into `dist/cli`.'
);
}

const transport = new StdioClientTransport( {
command: process.execPath,
args: [ path.join( engineDir, 'dist', 'mcp-server.bundle.mjs' ) ],
cwd: engineDir,
stderr: 'pipe',
} );
const client = new Client( { name: 'studio-code', version: '1.0.0' }, { capabilities: {} } );
await client.connect( transport );
return client;
}

interface DataLiberationResultContent {
type: string;
text?: string;
[ key: string ]: unknown;
}
const engineDir = getDataLiberationEngineDir();

// The model sometimes sends `args` as a JSON-encoded STRING instead of an object;
// forwarding that as MCP `arguments` fails the SDK schema ("expected record").
Expand Down Expand Up @@ -142,35 +84,15 @@ export const dataLiberationTool = defineTool(
);
}

const client = await getClient();

if ( args.tool === 'list' ) {
const listed = await client.listTools();
return textResult( JSON.stringify( listed.tools, null, 2 ) );
return textResult( JSON.stringify( await listDataLiberationTools(), null, 2 ) );
}

await ensureEngineChromium();

const result = await client.callTool(
{
name: args.tool,
arguments: normalizeArgs( args.args ),
},
undefined,
{ timeout: ENGINE_CALL_TIMEOUT_MS, resetTimeoutOnProgress: true }
return textResult(
JSON.stringify(
await callDataLiberationTool( args.tool, normalizeArgs( args.args ) ),
null,
2
)
);

const rawContent = Array.isArray( result.content )
? ( result.content as DataLiberationResultContent[] )
: [];
const text = rawContent
.map( ( part ) => ( part.type === 'text' ? part.text ?? '' : `[${ part.type }]` ) )
.join( '\n' );

if ( result.isError ) {
throw new Error( `Engine tool ${ args.tool } failed: ${ text }` );
}

return textResult( text );
}
);
2 changes: 1 addition & 1 deletion apps/cli/commands/preview/tests/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ describe( 'Preview Create Command', () => {

it( 'should handle errors when folder is not a Studio site', async () => {
const errorMessage =
'The specified folder is not added to Studio. Please use `studio site create` to add it first.';
'The specified folder is not added to Studio. Please use `studio create` to add it first.';
vi.mocked( getSiteByFolder ).mockImplementation( () => {
throw new LoggerError( errorMessage );
} );
Expand Down
Loading