Skip to content

Add native TypeScript Blueprint v2 runner - #3725

Closed
adamziel wants to merge 37 commits into
trunkfrom
add/native-blueprint-v2-ts-runner
Closed

Add native TypeScript Blueprint v2 runner#3725
adamziel wants to merge 37 commits into
trunkfrom
add/native-blueprint-v2-ts-runner

Conversation

@adamziel

@adamziel adamziel commented May 31, 2026

Copy link
Copy Markdown
Collaborator

What it does

Adds a TypeScript execution path for Blueprint v2 inside @wp-playground/blueprints.

Piece What changes
compileBlueprintForExecution() New version-aware facade. V1 stays on compileBlueprintV1(); v2 goes through the new compiler.
compileBlueprintV2() Validates v2 JSON, resolves runtime requirements, lowers supported v2 declarations to v1 steps, and returns a runnable compiled Blueprint.
Step support Extends existing v1 step handlers only where v2 lowering needs it: directory plugin/theme data, onError, plugin activation options, WXR controls, safer install paths, and site option handling.
Schema output Regenerates the public schema/validator and adds a dedicated v1 validator for v1-only consumers.

This PR does not wire website, client, CLI, or remote data flows to the new runner. That is stacked in #3850.

Rationale

Blueprint v2 needs one reviewed runtime contract before every consumer starts using it.

The meaningful problem this solves is that v2 declarations can now be accepted and executed by the blueprints package itself, instead of requiring a separate PHP-side v2 runner path. The package can validate v2 input, derive boot requirements, load v2 data references, and execute the supported declaration by lowering it into the existing v1 step engine.

Consumer Benefit from this PR
Direct @wp-playground/blueprints users Can compile and run v2 declarations with the package API.
Schema/validator users Can validate the public v1/v2 schema, or stay v1-only with blueprint-v1-schema-validator.js.
Website, @wp-playground/client, CLI Get the runner contract they need, but no behavior change until #3850.
Telex, Studio, wp-env Can review the package API and schema contract before integration wiring lands.

Implementation

compileBlueprintForExecution(input, options) detects the declaration version and dispatches to the matching compiler. The old compileBlueprint() export remains v1-only for compatibility.

For v2, the compiler performs this flow:

raw JSON / bundle / declaration
-> v2 validation
-> runtime configuration resolution
-> v2 data reference conversion
-> v2-to-v1 step lowering
-> existing v1 step execution

The v2 compiler also supports upgrading v1 declarations through the v2 path for parity tests while preserving v1 runtime-only metadata internally.

Testing instructions

Validated locally on adb775c99:

git diff --check
npm exec nx run playground-blueprints:typecheck
npm exec nx run playground-blueprints:build
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/v2/compile.spec.ts --testFiles=packages/playground/blueprints/src/tests/compile.spec.ts --testFiles=packages/playground/blueprints/src/tests/schema/public-schema.spec.ts
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/v1/compile.spec.ts --testFiles=packages/playground/blueprints/src/tests/steps/import-wxr.spec.ts --testFiles=packages/playground/blueprints/src/tests/steps/install-plugin.spec.ts --testFiles=packages/playground/blueprints/src/tests/steps/install-theme.spec.ts --testFiles=packages/playground/blueprints/src/tests/steps/site-data.spec.ts

The focused test runs passed 80 tests and 83 tests respectively.

Part of #2592.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a native TypeScript Blueprint v2 compile/validate/execute path and routes v2 Blueprints through the standard v1 worker, deprecating the legacy remote v2 worker entrypoint.

Changes:

  • Deprecates/fences the remote blueprints-runner=v2 worker and routes all remote execution through the standard worker.
  • Adds native TypeScript v2 handling in the client and CLI (including v1→v2 upgrades and option normalization).
  • Expands Blueprint v2 capabilities (WordPress sources, WXR controls, plugin/theme options, runtime configuration) and adds broad regression coverage.

Reviewed changes

Copilot reviewed 25 out of 27 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
packages/playground/remote/src/lib/playground-worker-endpoint.ts Adds WordPress ZIP buffer support to worker boot options.
packages/playground/remote/src/lib/playground-worker-endpoint-blueprints-v1.ts Rejects legacy remote v2 runner options; supports caller-provided WordPress ZIP buffers.
packages/playground/remote/src/lib/playground-worker-endpoint-blueprints-v1.spec.ts Tests legacy v2 rejection and WordPress ZIP buffer passthrough.
packages/playground/remote/src/lib/boot-playground-remote.ts Removes v2 worker selection; warns when blueprints-runner=v2 is requested.
packages/playground/client/src/index.ts Routes v2 declarations to native TS handler while always using the standard worker.
packages/playground/client/src/index.spec.ts Adds routing test for v2 declarations.
packages/playground/client/src/blueprints-v2-handler.ts Implements native TS v2 compile/boot/run path and WordPress source resolution.
packages/playground/client/src/blueprints-v2-handler.spec.ts Tests native v2 boot/run, ZIP restrictions, and v1 wp opt-out behavior.
packages/playground/client/src/blueprints-v1-handler.ts Tightens v1 opt-out check and adjusts types for v1 compilation hook.
packages/playground/cli/tests/run-cli.spec.ts Adds routing/option tests and replaces unzip shelling with JS extraction helper.
packages/playground/cli/tests/blueprints-v2-handler.spec.ts Adds unit coverage for CLI native v2 handler behaviors and overrides.
packages/playground/cli/src/run-cli.ts Enables native v2 routing without experimental flag in some cases; tracks which CLI args were explicitly provided.
packages/playground/cli/src/blueprints-v2/blueprints-v2-handler.ts Reworks CLI v2 handler to use TS compiler/runtime while still using v1 worker type.
packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts Adds networking support and centralizes related php.ini entries.
packages/playground/blueprints/src/tests/v2/compile.spec.ts Adds comprehensive v2 compiler/validator/execution-plan/runtime tests.
packages/playground/blueprints/src/tests/steps/site-data.spec.ts Tests rewrite-rule flush on permalink updates.
packages/playground/blueprints/src/tests/steps/install-plugin.spec.ts Adds coverage for skip-plugin and activationOptions.
packages/playground/blueprints/src/tests/steps/import-wxr.spec.ts Adds WXR option/control and repeated-import safety tests.
packages/playground/blueprints/src/lib/steps/site-data.ts Flushes rewrite rules when permalink_structure changes.
packages/playground/blueprints/src/lib/steps/install-theme.ts Adds human-readable progress naming support.
packages/playground/blueprints/src/lib/steps/install-plugin.ts Adds activationOptions, onError, human-readable progress naming, and temp option cleanup.
packages/playground/blueprints/src/lib/steps/import-wxr.ts Adds WXR import controls (URLs/authors/comments/users/site options) and repeated-import helpers.
packages/playground/blueprints/src/lib/resolve-runtime-configuration.ts Resolves v2 runtime configuration via TS compiler (with v1→v2 upgrade).
packages/playground/blueprints/src/index.ts Exports new v2 compiler/validator/runtime APIs and types.
packages/playground/blueprints/public/blueprint-schema.json Updates public schema with new plugin/theme and WXR options.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/playground/client/src/index.ts Outdated
Comment thread packages/playground/client/src/index.ts Outdated
Comment thread packages/playground/cli/src/run-cli.ts Outdated
Comment thread packages/playground/cli/src/blueprints-v2/blueprints-v2-handler.ts Outdated
Comment thread packages/playground/cli/tests/run-cli.spec.ts Outdated
Comment thread packages/playground/blueprints/src/lib/steps/install-plugin.ts Outdated
@adamziel
adamziel force-pushed the add/native-blueprint-v2-ts-runner branch from 6b52795 to adb775c Compare June 30, 2026 23:12
adamziel added a commit that referenced this pull request Jul 1, 2026
…3851)

## What it does

Flushes WordPress rewrite rules when the `setSiteOptions` Blueprint step
changes `permalink_structure`.

```json
{
  "step": "setSiteOptions",
  "options": {
    "permalink_structure": "/%postname%/"
  }
}
```

Before this change, the option was updated but `rewrite_rules` could
remain missing or stale until WordPress regenerated them later. After
this change, `setSiteOptions` calls `flush_rewrite_rules(false)` only
when `permalink_structure` is present in the options payload.

## Rationale

`permalink_structure` is not just display metadata. It changes how
WordPress maps pretty URLs to posts, pages, feeds, embeds, and other
routes.

Updating the option without flushing rewrite rules can leave a
Playground in a split state: `get_option('permalink_structure')` reports
the new structure, but requests still rely on old or missing rewrite
rules. That matters for Blueprints that set permalink structure and then
immediately import content, run checks, or expect pretty URLs to resolve
in the same boot.

This PR extracts one v1 step behavior from #3725 so it can be reviewed
on its own.

## Implementation

`setSiteOptions` now checks whether the submitted options include
`permalink_structure`:

```php
$flush_rewrite_rules = array_key_exists('permalink_structure', $site_options);
```

After updating all requested options, it calls:

```php
flush_rewrite_rules(false);
```

The `false` argument avoids writing `.htaccess`; Playground only needs
WordPress to regenerate the in-database rewrite rules.

## Testing instructions

```bash
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/steps/site-data.spec.ts
npm exec nx run playground-blueprints:typecheck
npm exec nx run playground-blueprints:lint
git diff --check
```

The new test deletes the `rewrite_rules` option, runs `setSiteOptions`
with `permalink_structure`, and verifies that WordPress stores both the
permalink structure and regenerated rewrite rules.
adamziel added a commit that referenced this pull request Jul 1, 2026
## What it does

Adds `activationOptions` to the `installPlugin` Blueprint step.

```json
{
  "step": "installPlugin",
  "pluginData": { "resource": "wordpress.org/plugins", "slug": "my-plugin" },
  "options": {
    "activate": true,
    "activationOptions": {
      "storeCity": "Wroclaw",
      "enabled": true
    }
  }
}
```

When activation options are provided, `installPlugin` stores them in a
temporary WordPress option before running the plugin activation hook.
The option name is based on `plugin_basename(__FILE__)`, so plugin code
can read:

```php
get_option('blueprint_activation_' . plugin_basename(__FILE__))
```

The temporary option is deleted after activation, even if activation
fails.

## Rationale

Some plugins need setup values during activation, not after activation.
A later Blueprint step can update options or run PHP, but it cannot
affect code that already ran inside `register_activation_hook()`.

The Blueprint v2 schema already describes `activationOptions` as data
exposed through a WordPress option named `blueprint_activation_` plus
`plugin_basename(__FILE__)`, and removed after activation. This PR
brings the v1 `installPlugin` step in line with that contract so the
behavior can be reviewed independently before #3725 depends on it.

This does not change plugin installation, plugin path validation,
overwrite behavior, or `onError` handling.

## Implementation

`installPlugin` now wraps the activation call:

1. Locate the plugin PHP file that will receive activation options.
2. Store `options.activationOptions` in
`blueprint_activation_<plugin_basename>`.
3. Run `activatePlugin()` as before.
4. Delete the temporary option in `finally`.

The PHP staging helper prints a sentinel-prefixed JSON payload because
plugin bootstrap code may write to stdout before the helper reports the
option name.

## Testing instructions

```bash
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/steps/install-plugin.spec.ts
npm exec nx run playground-blueprints:typecheck
npm exec nx run playground-blueprints:lint
git diff --check
```

The new tests cover:

- a plugin activation hook reading `activationOptions`
- cleanup of the temporary activation option after activation
- a clear error when `activationOptions` is requested but no plugin PHP
file can be found
adamziel added a commit that referenced this pull request Jul 4, 2026
…#3908)

## What it does

Extracts the compile-only part of the native TypeScript Blueprint v2
runner work from #3725. `compileBlueprintV2()` now turns a parsed v2
declaration into a typed `BlueprintV2ExecutionPlan` while preserving
runtime metadata and `applicationOptions`.

The plan records the ordered work implied by v2 fields such as
`constants`, `siteOptions`, `muPlugins`, `themes`, `activeTheme`,
`plugins`, `fonts`, `media`, `siteLanguage`, `roles`, `users`,
`postTypes`, `content`, and `additionalStepsAfterExecution`.

## Rationale

This lets us review the v2 parser/compiler shape separately from
execution. The current PR does **not** resolve resources, lower v2 data
references into v1 resources, call v1 step handlers, or wire the plan
into existing consumer data flows.

Non-empty v2 plans still fail at `run()` with an explicit
`UnsupportedBlueprintV2FeatureError`, so callers cannot accidentally
treat parsed-but-unwired v2 declarations as executed.

## Implementation

Adds `BlueprintV2ExecutionPlan` and `BlueprintV2ExecutionPlanItem` types
in `lib/v2/compile.ts`. `createBlueprintV2ExecutionPlan()` mirrors the
ordering from the broader TypeScript runner work while keeping each item
in v2-shaped data:

```ts
{ type: 'defineWpConfigConsts', consts }
{ type: 'setSiteOptions', options }
{ type: 'installPlugin', plugin, sourcePath: '/plugins/0' }
{ type: 'runStep', step, sourcePath: '/additionalStepsAfterExecution/0' }
```

Minimal v2 declarations still compile and run as a no-op. Declarations
with planned work compile successfully but reject on `run()` until
follow-up PRs wire individual plan items.

## Testing instructions

```bash
npm run format:uncommitted
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/compile.spec.ts
npm exec nx run playground-blueprints:typecheck
npm exec nx run playground-blueprints:lint
npm exec nx run playground-blueprints:build
npm exec nx run playground-blueprints:test:vite
git diff --check
```
adamziel added a commit that referenced this pull request Jul 4, 2026
## What it does

Adds the next v2-local layer after #3908: `compileBlueprintV2()` now
includes a lowered `steps` array and an `unsupportedPlan` array
alongside the existing v2 `plan`.

In this PR, **lowering** means translating Blueprint v2 declarations
into the older v1 step records that the current TypeScript runner
already understands. For example, a v2 `plugins` declaration becomes an
`installPlugin` step record, and a v2 `siteOptions` declaration becomes
a `setSiteOptions` step record.

This PR does not execute those step records yet. It only converts the
supported v2 plan items into a runner-friendly shape and keeps the rest
visible as unsupported work.

The lowering covers many of the safe, already-understood v2 plan items:

- `constants` -> `defineWpConfigConsts`
- `siteOptions` -> `setSiteOptions`
- `siteLanguage` -> `setSiteLanguage`
- top-level `plugins` -> `installPlugin` step records
- top-level `themes` / `activeTheme` -> `installTheme` step records
- simple `additionalStepsAfterExecution` entries like `mkdir`, `cp`,
`mv`, `rm`, `rmdir`, `defineConstants`, `setSiteOptions`,
`setSiteLanguage`, `installPlugin`, `installTheme`, `activatePlugin`,
`activateTheme`, `importThemeStarterContent`, and `wp-cli`

Unsupported v2-only areas such as media/content/font/user/role/post-type
imports remain in `unsupportedPlan` instead of being silently dropped.

## Rationale

This keeps processing the larger TypeScript Blueprint v2 runner work
from #3725 piece by piece. The previous PR made v2 declarations compile
into an ordered v2 plan. This PR groups the v2-only translation work
that does not need consumer wiring or actual runtime execution yet.

The benefit is that reviewers can inspect the v2-to-v1 mapping
separately from the later execution work. If a v2 declaration maps
cleanly to an existing v1 step shape, this PR makes that explicit. If it
does not, the plan item stays in `unsupportedPlan` for a later focused
PR.

It still does **not** execute the lowered steps, resolve resources at
runtime, import content/media, or touch website/CLI/remote data flows.
Non-empty v2 plans continue to reject at `run()` until a later PR wires
execution.

## Implementation

Adds `lowerBlueprintV2ExecutionPlan()` in `lib/v2/compile.ts`. It
returns:

```ts
{
  steps: StepDefinition[],
  unsupportedPlan: BlueprintV2ExecutionPlan
}
```

The lowering layer:

- walks the ordered v2 execution plan
- converts supported plan items to existing `StepDefinition` records
- keeps unsupported items in `unsupportedPlan`
- converts plugin/theme data references into existing v1 resource shapes
- normalizes target-site paths for simple file steps
- rejects empty paths and parent-directory traversal before producing v1
paths

Plugin/theme data references are lowered for WordPress.org slugs,
versioned slugs, URLs, GitHub/GitLab repo URLs, execution-context paths,
inline files, inline directories, and git directory objects.

## Testing instructions

```bash
npm run format:uncommitted
npm exec nx run playground-blueprints:test:vite -- --testFiles=packages/playground/blueprints/src/tests/compile.spec.ts
npm exec nx run playground-blueprints:typecheck
npm exec nx run playground-blueprints:lint
npm exec nx run playground-blueprints:build
git diff --check
```
adamziel added a commit that referenced this pull request Jul 11, 2026
## What

Load custom `wordpressVersion` data references in TypeScript Blueprints
v2.

Blueprints v2 can now load WordPress from a custom ZIP, a directory
embedded in the Blueprint, or a directory in Git. The ZIP can sit next
to the Blueprint or be embedded in it. Directory sources are turned into
ZIPs before WordPress boots. Both the browser and CLI use the supplied
source instead of downloading another WordPress build.

Built-in versions and HTTP(S) archives keep their existing download
paths. This takes the useful source-resolution idea from #3725 without
reviving that PR's compiler, validator, or migration work.

## Why

The public v2 schema already accepts general data references for
`wordpressVersion`, but the TypeScript runtime rejected every form
except HTTP(S). A valid Blueprint could therefore validate and still
fail before boot.

## Testing

CI
@adamziel

Copy link
Copy Markdown
Collaborator Author

This has been merged in a series of smaller PRs, let's close it.

@adamziel adamziel closed this Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment