@wp-playground/cli 3.0.18 → 3.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,27 @@
1
- import { logger as h, LogSeverity as A, errorLogPath as q } from "@php-wasm/logger";
2
- import { PHPResponse as V, consumeAPI as j, SupportedPHPVersions as ue, printDebugDetails as de, exposeAPI as fe, exposeSyncAPI as me } from "@php-wasm/universal";
3
- import { resolveRemoteBlueprint as he, resolveRuntimeConfiguration as ge, compileBlueprintV1 as ye, isBlueprintBundle as we, runBlueprintV1Steps as be } from "@wp-playground/blueprints";
4
- import { zipDirectory as ve, RecommendedPHPVersion as G } from "@wp-playground/common";
5
- import u, { mkdirSync as z } from "fs";
6
- import { Worker as X, MessageChannel as Pe } from "worker_threads";
7
- import { p as J, a as Se, e as ke } from "./mounts-D1_eXSTw.js";
8
- import xe from "express";
1
+ import { logger as g, LogSeverity as N, errorLogPath as z } from "@php-wasm/logger";
2
+ import { PHPResponse as O, consumeAPI as R, SupportedPHPVersions as me, printDebugDetails as he, exposeAPI as ge, exposeSyncAPI as we } from "@php-wasm/universal";
3
+ import { resolveRemoteBlueprint as ye, resolveRuntimeConfiguration as X, compileBlueprintV1 as be, isBlueprintBundle as ve, runBlueprintV1Steps as Pe } from "@wp-playground/blueprints";
4
+ import { zipDirectory as Se, RecommendedPHPVersion as ee } from "@wp-playground/common";
5
+ import p, { mkdirSync as J } from "fs";
6
+ import { Worker as Z, MessageChannel as xe } from "worker_threads";
7
+ import { p as Y, a as G, e as ke } from "./mounts-ChxECdbN.js";
8
+ import Ie from "express";
9
9
  import { FileLockManagerForNode as Ee } from "@php-wasm/node";
10
- import K, { cpus as Ie } from "os";
11
- import { jspi as Ce } from "wasm-feature-detect";
12
- import Le from "yargs";
13
- import g, { basename as $e } from "path";
14
- import { NodeJsFilesystem as We, OverlayFilesystem as Te, InMemoryFilesystem as Be, ZipFilesystem as je } from "@wp-playground/storage";
15
- import { EmscriptenDownloadMonitor as Re, ProgressTracker as Fe } from "@php-wasm/progress";
16
- import { resolveWordPressRelease as Me } from "@wp-playground/wordpress";
17
- import $ from "fs-extra";
18
- import { startBridge as De } from "@php-wasm/xdebug-bridge";
19
- import { dir as Ae, setGracefulCleanup as Ue } from "tmp-promise";
20
- import Ne from "ps-man";
21
- import { XMLParser as Q, XMLBuilder as ee } from "fast-xml-parser";
22
- import P from "jsonc-parser";
23
- async function Ve(e) {
24
- const o = xe(), t = await new Promise((n, r) => {
10
+ import te, { cpus as Ce } from "os";
11
+ import { jspi as Le } from "wasm-feature-detect";
12
+ import $e from "yargs";
13
+ import m, { basename as Te } from "path";
14
+ import { NodeJsFilesystem as je, OverlayFilesystem as Be, InMemoryFilesystem as Me, ZipFilesystem as Re } from "@wp-playground/storage";
15
+ import { EmscriptenDownloadMonitor as Fe, ProgressTracker as We } from "@php-wasm/progress";
16
+ import { resolveWordPressRelease as De } from "@wp-playground/wordpress";
17
+ import T from "fs-extra";
18
+ import { startBridge as Ae } from "@php-wasm/xdebug-bridge";
19
+ import { dir as Ue, setGracefulCleanup as Ne } from "tmp-promise";
20
+ import Ve from "ps-man";
21
+ import { XMLParser as oe, XMLBuilder as re } from "fast-xml-parser";
22
+ import v from "jsonc-parser";
23
+ async function Oe(e) {
24
+ const o = Ie(), t = await new Promise((n, r) => {
25
25
  const a = o.listen(e.port, () => {
26
26
  const l = a.address();
27
27
  l === null || typeof l == "string" ? r(new Error("Server address is not available")) : n(a);
@@ -32,12 +32,12 @@ async function Ve(e) {
32
32
  try {
33
33
  a = await e.handleRequest({
34
34
  url: n.url,
35
- headers: _e(n),
35
+ headers: He(n),
36
36
  method: n.method,
37
- body: await Oe(n)
37
+ body: await _e(n)
38
38
  });
39
39
  } catch (l) {
40
- h.error(l), a = V.forHttpCode(500);
40
+ g.error(l), a = O.forHttpCode(500);
41
41
  }
42
42
  r.statusCode = a.httpStatusCode;
43
43
  for (const l in a.headers)
@@ -47,21 +47,21 @@ async function Ve(e) {
47
47
  const s = t.address().port;
48
48
  return await e.onBind(t, s);
49
49
  }
50
- const Oe = async (e) => await new Promise((o) => {
50
+ const _e = async (e) => await new Promise((o) => {
51
51
  const t = [];
52
52
  e.on("data", (i) => {
53
53
  t.push(i);
54
54
  }), e.on("end", () => {
55
55
  o(new Uint8Array(Buffer.concat(t)));
56
56
  });
57
- }), _e = (e) => {
57
+ }), He = (e) => {
58
58
  const o = {};
59
59
  if (e.rawHeaders && e.rawHeaders.length)
60
60
  for (let t = 0; t < e.rawHeaders.length; t += 2)
61
61
  o[e.rawHeaders[t].toLowerCase()] = e.rawHeaders[t + 1];
62
62
  return o;
63
63
  };
64
- class He {
64
+ class qe {
65
65
  constructor(o) {
66
66
  this.workerLoads = [], this.addWorker(o);
67
67
  }
@@ -71,6 +71,15 @@ class He {
71
71
  activeRequests: /* @__PURE__ */ new Set()
72
72
  });
73
73
  }
74
+ async removeWorker(o) {
75
+ const t = this.workerLoads.findIndex(
76
+ (s) => s.worker === o
77
+ );
78
+ if (t === -1)
79
+ return;
80
+ const [i] = this.workerLoads.splice(t, 1);
81
+ await Promise.allSettled(i.activeRequests);
82
+ }
74
83
  async handleRequest(o) {
75
84
  let t = this.workerLoads[0];
76
85
  for (let s = 1; s < this.workerLoads.length; s++) {
@@ -83,33 +92,33 @@ class He {
83
92
  });
84
93
  }
85
94
  }
86
- function qe(e) {
95
+ function ze(e) {
87
96
  return /^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e);
88
97
  }
89
- async function ze({
98
+ async function Xe({
90
99
  sourceString: e,
91
100
  blueprintMayReadAdjacentFiles: o
92
101
  }) {
93
102
  if (!e)
94
103
  return;
95
104
  if (e.startsWith("http://") || e.startsWith("https://"))
96
- return await he(e);
97
- let t = g.resolve(process.cwd(), e);
98
- if (!u.existsSync(t))
105
+ return await ye(e);
106
+ let t = m.resolve(process.cwd(), e);
107
+ if (!p.existsSync(t))
99
108
  throw new Error(`Blueprint file does not exist: ${t}`);
100
- const i = u.statSync(t);
101
- if (i.isDirectory() && (t = g.join(t, "blueprint.json")), !i.isFile() && i.isSymbolicLink())
109
+ const i = p.statSync(t);
110
+ if (i.isDirectory() && (t = m.join(t, "blueprint.json")), !i.isFile() && i.isSymbolicLink())
102
111
  throw new Error(
103
112
  `Blueprint path is neither a file nor a directory: ${t}`
104
113
  );
105
- const s = g.extname(t);
114
+ const s = m.extname(t);
106
115
  switch (s) {
107
116
  case ".zip":
108
- return je.fromArrayBuffer(
109
- u.readFileSync(t).buffer
117
+ return Re.fromArrayBuffer(
118
+ p.readFileSync(t).buffer
110
119
  );
111
120
  case ".json": {
112
- const n = u.readFileSync(t, "utf-8");
121
+ const n = p.readFileSync(t, "utf-8");
113
122
  try {
114
123
  JSON.parse(n);
115
124
  } catch {
@@ -117,9 +126,9 @@ async function ze({
117
126
  `Blueprint file at ${t} is not a valid JSON file`
118
127
  );
119
128
  }
120
- const r = g.dirname(t), a = new We(r);
121
- return new Te([
122
- new Be({
129
+ const r = m.dirname(t), a = new je(r);
130
+ return new Be([
131
+ new Me({
123
132
  "blueprint.json": n
124
133
  }),
125
134
  /**
@@ -145,15 +154,15 @@ You can allow this Blueprint to read files from the same parent directory by exp
145
154
  );
146
155
  }
147
156
  }
148
- class Xe {
157
+ class Je {
149
158
  constructor(o, t) {
150
159
  this.lastProgressMessage = "", this.args = o, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength, this.phpVersion = o.php;
151
160
  }
152
161
  getWorkerType() {
153
162
  return "v2";
154
163
  }
155
- async bootPrimaryWorker(o, t, i) {
156
- const s = j(o);
164
+ async bootAndSetUpInitialPlayground(o, t, i) {
165
+ const s = R(o);
157
166
  await s.useFileLockManager(t);
158
167
  const n = {
159
168
  ...this.args,
@@ -163,19 +172,23 @@ class Xe {
163
172
  processIdSpaceLength: this.processIdSpaceLength,
164
173
  trace: this.args.debug || !1,
165
174
  blueprint: this.args.blueprint,
166
- withXdebug: !!this.args.xdebug,
167
- xdebug: typeof this.args.xdebug == "object" ? this.args.xdebug : void 0,
175
+ // We do not enable Xdebug by default for the initial worker
176
+ // because we do not imagine users expect to hit breakpoints
177
+ // until Playground has fully booted.
178
+ // TODO: Consider supporting Xdebug for the initial worker via a dedicated flag.
179
+ withXdebug: !1,
180
+ xdebug: void 0,
168
181
  nativeInternalDirPath: i
169
182
  };
170
- return await s.bootAsPrimaryWorker(n), s;
183
+ return await s.bootAndSetUpInitialWorker(n), s;
171
184
  }
172
- async bootSecondaryWorker({
185
+ async bootPlayground({
173
186
  worker: o,
174
187
  fileLockManagerPort: t,
175
188
  firstProcessId: i,
176
189
  nativeInternalDirPath: s
177
190
  }) {
178
- const n = j(o.phpPort);
191
+ const n = R(o.phpPort);
179
192
  await n.useFileLockManager(t);
180
193
  const r = {
181
194
  ...this.args,
@@ -189,7 +202,7 @@ class Xe {
189
202
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
190
203
  mountsAfterWpInstall: this.args.mount || []
191
204
  };
192
- return await n.bootAsSecondaryWorker(r), n;
205
+ return await n.bootWorker(r), n;
193
206
  }
194
207
  writeProgressUpdate(o, t, i) {
195
208
  t !== this.lastProgressMessage && (this.lastProgressMessage = t, o.isTTY ? (o.cursorTo(0), o.write(t), o.clearLine(1), i && o.write(`
@@ -197,20 +210,20 @@ class Xe {
197
210
  `));
198
211
  }
199
212
  }
200
- const O = g.join(K.homedir(), ".wordpress-playground");
201
- async function Je(e) {
202
- return await te(
213
+ const _ = m.join(te.homedir(), ".wordpress-playground");
214
+ async function Ze(e) {
215
+ return await ne(
203
216
  "https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip",
204
217
  "sqlite.zip",
205
218
  e
206
219
  );
207
220
  }
208
- async function te(e, o, t) {
209
- const i = g.join(O, o);
210
- return $.existsSync(i) || ($.ensureDirSync(O), await Ze(e, i, t)), oe(i);
221
+ async function ne(e, o, t) {
222
+ const i = m.join(_, o);
223
+ return T.existsSync(i) || (T.ensureDirSync(_), await Ye(e, i, t)), ie(i);
211
224
  }
212
- async function Ze(e, o, t) {
213
- const s = (await t.monitorFetch(fetch(e))).body.getReader(), n = `${o}.partial`, r = $.createWriteStream(n);
225
+ async function Ye(e, o, t) {
226
+ const s = (await t.monitorFetch(fetch(e))).body.getReader(), n = `${o}.partial`, r = T.createWriteStream(n);
214
227
  for (; ; ) {
215
228
  const { done: a, value: l } = await s.read();
216
229
  if (l && r.write(l), a)
@@ -218,87 +231,95 @@ async function Ze(e, o, t) {
218
231
  }
219
232
  r.close(), r.closed || await new Promise((a, l) => {
220
233
  r.on("finish", () => {
221
- $.renameSync(n, o), a(null);
222
- }), r.on("error", (p) => {
223
- $.removeSync(n), l(p);
234
+ T.renameSync(n, o), a(null);
235
+ }), r.on("error", (d) => {
236
+ T.removeSync(n), l(d);
224
237
  });
225
238
  });
226
239
  }
227
- function oe(e, o) {
228
- return new File([$.readFileSync(e)], $e(e));
240
+ function ie(e, o) {
241
+ return new File([T.readFileSync(e)], Te(e));
229
242
  }
230
- class Ye {
243
+ class Ge {
231
244
  constructor(o, t) {
232
245
  this.lastProgressMessage = "", this.args = o, this.siteUrl = t.siteUrl, this.processIdSpaceLength = t.processIdSpaceLength;
233
246
  }
234
247
  getWorkerType() {
235
248
  return "v1";
236
249
  }
237
- async bootPrimaryWorker(o, t, i) {
238
- let s;
239
- const n = new Re();
240
- if (!this.args.skipWordPressSetup) {
241
- let I = !1;
242
- n.addEventListener("progress", (k) => {
243
- if (I)
250
+ async bootAndSetUpInitialPlayground(o, t, i) {
251
+ let s, n, r;
252
+ const a = new Fe();
253
+ if (this.args.wordpressInstallMode === "download-and-install") {
254
+ let k = !1;
255
+ a.addEventListener("progress", (j) => {
256
+ if (k)
244
257
  return;
245
- const { loaded: x, total: f } = k.detail, W = Math.floor(
258
+ const { loaded: x, total: f } = j.detail, B = Math.floor(
246
259
  Math.min(100, 100 * x / f)
247
260
  );
248
- I = W === 100, this.writeProgressUpdate(
261
+ k = B === 100, this.writeProgressUpdate(
249
262
  process.stdout,
250
- `Downloading WordPress ${W}%...`,
251
- I
263
+ `Downloading WordPress ${B}%...`,
264
+ k
252
265
  );
253
- }), s = await Me(this.args.wp), h.log(
266
+ }), s = await De(this.args.wp), r = m.join(
267
+ _,
268
+ `prebuilt-wp-content-for-wp-${s.version}.zip`
269
+ ), n = p.existsSync(r) ? ie(r) : await ne(
270
+ s.releaseUrl,
271
+ `${s.version}.zip`,
272
+ a
273
+ ), g.log(
254
274
  `Resolved WordPress release URL: ${s?.releaseUrl}`
255
275
  );
256
276
  }
257
- const r = s && g.join(
258
- O,
259
- `prebuilt-wp-content-for-wp-${s.version}.zip`
260
- ), a = s ? u.existsSync(r) ? oe(r) : await te(
261
- s.releaseUrl,
262
- `${s.version}.zip`,
263
- n
264
- ) : void 0;
265
- h.log("Fetching SQLite integration plugin...");
266
- const l = this.args.skipSqliteSetup ? void 0 : await Je(n), p = this.args.followSymlinks === !0, c = this.args.experimentalTrace === !0, d = this.args["mount-before-install"] || [], m = this.args.mount || [], b = j(o);
267
- await b.isConnected(), h.log("Booting WordPress...");
268
- const v = await ge(
277
+ g.log("Fetching SQLite integration plugin...");
278
+ const l = this.args.skipSqliteSetup ? void 0 : await Ze(a), d = this.args.followSymlinks === !0, c = this.args.experimentalTrace === !0, u = this.args["mount-before-install"] || [], h = this.args.mount || [], b = R(o);
279
+ await b.isConnected(), g.log("Booting WordPress...");
280
+ const S = await X(
269
281
  this.getEffectiveBlueprint()
270
282
  );
271
- return await b.useFileLockManager(t), await b.bootAsPrimaryWorker({
272
- phpVersion: v.phpVersion,
273
- wpVersion: v.wpVersion,
283
+ return await b.useFileLockManager(t), await b.bootAndSetUpInitialWorker({
284
+ phpVersion: S.phpVersion,
285
+ wpVersion: S.wpVersion,
274
286
  siteUrl: this.siteUrl,
275
- mountsBeforeWpInstall: d,
276
- mountsAfterWpInstall: m,
277
- wordPressZip: a && await a.arrayBuffer(),
287
+ mountsBeforeWpInstall: u,
288
+ mountsAfterWpInstall: h,
289
+ wordpressInstallMode: this.args.wordpressInstallMode || "download-and-install",
290
+ wordPressZip: n && await n.arrayBuffer(),
278
291
  sqliteIntegrationPluginZip: await l?.arrayBuffer(),
279
292
  firstProcessId: 0,
280
293
  processIdSpaceLength: this.processIdSpaceLength,
281
- followSymlinks: p,
294
+ followSymlinks: d,
282
295
  trace: c,
283
296
  internalCookieStore: this.args.internalCookieStore,
284
- withXdebug: !!this.args.xdebug,
297
+ // We do not enable Xdebug by default for the initial worker
298
+ // because we do not imagine users expect to hit breakpoints
299
+ // until Playground has fully booted.
300
+ // TODO: Consider supporting Xdebug for the initial worker via a dedicated flag.
301
+ withXdebug: !1,
285
302
  nativeInternalDirPath: i
286
- }), s && !this.args["mount-before-install"] && !u.existsSync(r) && (h.log("Caching preinstalled WordPress for the next boot..."), u.writeFileSync(
303
+ }), r && !this.args["mount-before-install"] && !p.existsSync(r) && (g.log("Caching preinstalled WordPress for the next boot..."), p.writeFileSync(
287
304
  r,
288
- await ve(b, "/wordpress")
289
- ), h.log("Cached!")), b;
305
+ await Se(b, "/wordpress")
306
+ ), g.log("Cached!")), b;
290
307
  }
291
- async bootSecondaryWorker({
308
+ async bootPlayground({
292
309
  worker: o,
293
310
  fileLockManagerPort: t,
294
311
  firstProcessId: i,
295
312
  nativeInternalDirPath: s
296
313
  }) {
297
- const n = j(
314
+ const n = R(
298
315
  o.phpPort
299
316
  );
300
- return await n.isConnected(), await n.useFileLockManager(t), await n.bootAsSecondaryWorker({
301
- phpVersion: this.phpVersion,
317
+ await n.isConnected();
318
+ const r = await X(
319
+ this.getEffectiveBlueprint()
320
+ );
321
+ return await n.useFileLockManager(t), await n.bootWorker({
322
+ phpVersion: r.phpVersion,
302
323
  siteUrl: this.siteUrl,
303
324
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
304
325
  mountsAfterWpInstall: this.args.mount || [],
@@ -314,7 +335,7 @@ class Ye {
314
335
  }), await n.isReady(), n;
315
336
  }
316
337
  async compileInputBlueprint(o) {
317
- const t = this.getEffectiveBlueprint(), i = new Fe();
338
+ const t = this.getEffectiveBlueprint(), i = new We();
318
339
  let s = "", n = !1;
319
340
  return i.addEventListener("progress", (r) => {
320
341
  if (n)
@@ -328,31 +349,31 @@ class Ye {
328
349
  l,
329
350
  n
330
351
  );
331
- }), await ye(t, {
352
+ }), await be(t, {
332
353
  progress: i,
333
354
  additionalSteps: o
334
355
  });
335
356
  }
336
357
  getEffectiveBlueprint() {
337
358
  const o = this.args.blueprint;
338
- return we(o) ? o : {
359
+ return ve(o) ? o : {
339
360
  login: this.args.login,
340
361
  ...o || {},
341
362
  preferredVersions: {
342
- php: this.args.php ?? o?.preferredVersions?.php ?? G,
363
+ php: this.args.php ?? o?.preferredVersions?.php ?? ee,
343
364
  wp: this.args.wp ?? o?.preferredVersions?.wp ?? "latest",
344
365
  ...o?.preferredVersions || {}
345
366
  }
346
367
  };
347
368
  }
348
369
  writeProgressUpdate(o, t, i) {
349
- this.args.verbosity !== _.Quiet.name && t !== this.lastProgressMessage && (this.lastProgressMessage = t, o.isTTY ? (o.cursorTo(0), o.write(t), o.clearLine(1), i && o.write(`
370
+ this.args.verbosity !== H.Quiet.name && t !== this.lastProgressMessage && (this.lastProgressMessage = t, o.isTTY ? (o.cursorTo(0), o.write(t), o.clearLine(1), i && o.write(`
350
371
  `)) : o.write(`${t}
351
372
  `));
352
373
  }
353
374
  }
354
- async function Ge(e, o = !0) {
355
- const i = `${g.basename(process.argv0)}${e}${process.pid}-`, s = await Ae({
375
+ async function Ke(e, o = !0) {
376
+ const i = `${m.basename(process.argv0)}${e}${process.pid}-`, s = await Ue({
356
377
  prefix: i,
357
378
  /*
358
379
  * Allow recursive cleanup on process exit.
@@ -364,20 +385,20 @@ async function Ge(e, o = !0) {
364
385
  */
365
386
  unsafeCleanup: !0
366
387
  });
367
- return o && Ue(), s;
388
+ return o && Ne(), s;
368
389
  }
369
- async function Ke(e, o, t) {
370
- const s = (await Qe(
390
+ async function Qe(e, o, t) {
391
+ const s = (await et(
371
392
  e,
372
393
  o,
373
394
  t
374
395
  )).map(
375
396
  (n) => new Promise((r) => {
376
- u.rm(n, { recursive: !0 }, (a) => {
377
- a ? h.warn(
397
+ p.rm(n, { recursive: !0 }, (a) => {
398
+ a ? g.warn(
378
399
  `Failed to delete stale Playground temp dir: ${n}`,
379
400
  a
380
- ) : h.info(
401
+ ) : g.info(
381
402
  `Deleted stale Playground temp dir: ${n}`
382
403
  ), r();
383
404
  });
@@ -385,24 +406,24 @@ async function Ke(e, o, t) {
385
406
  );
386
407
  await Promise.all(s);
387
408
  }
388
- async function Qe(e, o, t) {
409
+ async function et(e, o, t) {
389
410
  try {
390
- const i = u.readdirSync(t).map((n) => g.join(t, n)), s = [];
411
+ const i = p.readdirSync(t).map((n) => m.join(t, n)), s = [];
391
412
  for (const n of i)
392
- await et(
413
+ await tt(
393
414
  e,
394
415
  o,
395
416
  n
396
417
  ) && s.push(n);
397
418
  return s;
398
419
  } catch (i) {
399
- return h.warn(`Failed to find stale Playground temp dirs: ${i}`), [];
420
+ return g.warn(`Failed to find stale Playground temp dirs: ${i}`), [];
400
421
  }
401
422
  }
402
- async function et(e, o, t) {
403
- if (!u.lstatSync(t).isDirectory())
423
+ async function tt(e, o, t) {
424
+ if (!p.lstatSync(t).isDirectory())
404
425
  return !1;
405
- const s = g.basename(t);
426
+ const s = m.basename(t);
406
427
  if (!s.includes(e))
407
428
  return !1;
408
429
  const n = s.match(
@@ -414,15 +435,15 @@ async function et(e, o, t) {
414
435
  executableName: n[1],
415
436
  pid: n[2]
416
437
  };
417
- if (await tt(r.pid, r.executableName))
438
+ if (await ot(r.pid, r.executableName))
418
439
  return !1;
419
440
  const a = Date.now() - o;
420
- return u.statSync(t).mtime.getTime() < a;
441
+ return p.statSync(t).mtime.getTime() < a;
421
442
  }
422
- async function tt(e, o) {
443
+ async function ot(e, o) {
423
444
  const [t] = await new Promise(
424
445
  (i, s) => {
425
- Ne.list(
446
+ Ve.list(
426
447
  {
427
448
  pid: e,
428
449
  name: o,
@@ -437,24 +458,24 @@ async function tt(e, o) {
437
458
  );
438
459
  return !!t && t.pid === e && t.command === o;
439
460
  }
440
- async function ot(e, o, t) {
461
+ async function rt(e, o, t) {
441
462
  const i = t === "win32" ? (
442
463
  // On Windows, creating a 'dir' symlink can require elevated permissions.
443
464
  // In this case, let's make junction points because they function like
444
465
  // symlinks and do not require elevated permissions.
445
466
  "junction"
446
467
  ) : "dir";
447
- u.symlinkSync(e, o, i);
468
+ p.symlinkSync(e, o, i);
448
469
  }
449
- async function rt(e) {
470
+ async function nt(e) {
450
471
  try {
451
- u.lstatSync(e).isSymbolicLink() && u.unlinkSync(e);
472
+ p.lstatSync(e).isSymbolicLink() && p.unlinkSync(e);
452
473
  } catch {
453
474
  }
454
475
  }
455
- function nt(e, o) {
476
+ function it(e, o) {
456
477
  return o.filter((t) => {
457
- const i = g.resolve(t.hostPath), s = g.join(e, g.sep);
478
+ const i = m.resolve(t.hostPath), s = m.join(e, m.sep);
458
479
  return (
459
480
  // If auto-mounting from the current directory,
460
481
  // the entire project directory can be mapped.
@@ -470,7 +491,7 @@ const E = {
470
491
  commentPropName: "__xmlComment",
471
492
  allowBooleanAttributes: !0,
472
493
  trimValues: !0
473
- }, re = {
494
+ }, se = {
474
495
  ignoreAttributes: E.ignoreAttributes,
475
496
  attributeNamePrefix: E.attributeNamePrefix,
476
497
  preserveOrder: E.preserveOrder,
@@ -479,26 +500,25 @@ const E = {
479
500
  suppressBooleanAttributes: !E.allowBooleanAttributes,
480
501
  format: !0,
481
502
  indentBy: " "
482
- }, R = {
503
+ }, F = {
483
504
  allowEmptyContent: !0,
484
505
  allowTrailingComma: !0
485
506
  };
486
- function it(e, o) {
487
- const { name: t, host: i, port: s, mappings: n, ideKey: r } = o, a = new Q(E), l = (() => {
507
+ function st(e, o) {
508
+ const { name: t, host: i, port: s, mappings: n, ideKey: r } = o, a = new oe(E), l = (() => {
488
509
  try {
489
510
  return a.parse(e, !0);
490
511
  } catch {
491
512
  throw new Error("PhpStorm configuration file is not valid XML.");
492
513
  }
493
- })(), p = {
514
+ })(), d = {
494
515
  server: [
495
516
  {
496
517
  path_mappings: n.map((f) => ({
497
518
  mapping: [],
498
519
  ":@": {
499
- "local-root": `$PROJECT_DIR$/${f.hostPath.replace(
500
- /^\.\/?/,
501
- ""
520
+ "local-root": `$PROJECT_DIR$/${le(
521
+ m.relative(o.projectDir, f.hostPath)
502
522
  )}`,
503
523
  "remote-root": f.vfsPath
504
524
  }
@@ -530,28 +550,28 @@ function it(e, o) {
530
550
  project: [],
531
551
  ":@": { version: "4" }
532
552
  }, l.push(c));
533
- let d = c.project?.find(
553
+ let u = c.project?.find(
534
554
  (f) => !!f?.component && f?.[":@"]?.name === "PhpServers"
535
555
  );
536
- d === void 0 && (d = {
556
+ u === void 0 && (u = {
537
557
  component: [],
538
558
  ":@": { name: "PhpServers" }
539
- }, c.project === void 0 && (c.project = []), c.project.push(d));
540
- let m = d.component?.find(
559
+ }, c.project === void 0 && (c.project = []), c.project.push(u));
560
+ let h = u.component?.find(
541
561
  (f) => !!f?.servers
542
562
  );
543
- m === void 0 && (m = { servers: [] }, d.component === void 0 && (d.component = []), d.component.push(m));
544
- const b = m.servers?.findIndex(
563
+ h === void 0 && (h = { servers: [] }, u.component === void 0 && (u.component = []), u.component.push(h));
564
+ const b = h.servers?.findIndex(
545
565
  (f) => !!f?.server && f?.[":@"]?.name === t
546
566
  );
547
- (b === void 0 || b < 0) && (m.servers === void 0 && (m.servers = []), m.servers.push(p));
548
- let v = c.project?.find(
567
+ (b === void 0 || b < 0) && (h.servers === void 0 && (h.servers = []), h.servers.push(d));
568
+ let S = c.project?.find(
549
569
  (f) => !!f?.component && f?.[":@"]?.name === "RunManager"
550
570
  );
551
- if (v === void 0 && (v = {
571
+ if (S === void 0 && (S = {
552
572
  component: [],
553
573
  ":@": { name: "RunManager" }
554
- }, c.project === void 0 && (c.project = []), c.project.push(v)), (v.component?.findIndex(
574
+ }, c.project === void 0 && (c.project = []), c.project.push(S)), (S.component?.findIndex(
555
575
  (f) => !!f?.configuration && f?.[":@"]?.name === t
556
576
  ) ?? -1) < 0) {
557
577
  const f = {
@@ -570,9 +590,9 @@ function it(e, o) {
570
590
  session_id: r
571
591
  }
572
592
  };
573
- v.component === void 0 && (v.component = []), v.component.push(f);
593
+ S.component === void 0 && (S.component = []), S.component.push(f);
574
594
  }
575
- const x = new ee(re).build(l);
595
+ const x = new re(se).build(l);
576
596
  try {
577
597
  a.parse(x, !0);
578
598
  } catch {
@@ -582,35 +602,34 @@ function it(e, o) {
582
602
  }
583
603
  return x;
584
604
  }
585
- function st(e, o) {
605
+ function at(e, o) {
586
606
  const { name: t, mappings: i } = o, s = [];
587
- let n = e, r = P.parseTree(n, s, R);
607
+ let n = e, r = v.parseTree(n, s, F);
588
608
  if (r === void 0 || s.length)
589
609
  throw new Error("VS Code configuration file is not valid JSON.");
590
- let a = P.findNodeAtLocation(r, ["configurations"]);
610
+ let a = v.findNodeAtLocation(r, ["configurations"]);
591
611
  if (a === void 0 || a.children === void 0) {
592
- const p = P.modify(n, ["configurations"], [], {});
593
- n = P.applyEdits(n, p), r = P.parseTree(n, [], R), a = P.findNodeAtLocation(r, [
612
+ const d = v.modify(n, ["configurations"], [], {});
613
+ n = v.applyEdits(n, d), r = v.parseTree(n, [], F), a = v.findNodeAtLocation(r, [
594
614
  "configurations"
595
615
  ]);
596
616
  }
597
617
  const l = a?.children?.findIndex(
598
- (p) => P.findNodeAtLocation(p, ["name"])?.value === t
618
+ (d) => v.findNodeAtLocation(d, ["name"])?.value === t
599
619
  );
600
620
  if (l === void 0 || l < 0) {
601
- const p = {
621
+ const d = {
602
622
  name: t,
603
623
  type: "php",
604
624
  request: "launch",
605
625
  port: 9003,
606
- pathMappings: i.reduce((m, b) => (m[b.vfsPath] = `\${workspaceFolder}/${b.hostPath.replace(
607
- /^\.\/?/,
608
- ""
609
- )}`, m), {})
610
- }, c = a?.children?.length || 0, d = P.modify(
626
+ pathMappings: i.reduce((h, b) => (h[b.vfsPath] = `\${workspaceFolder}/${le(
627
+ m.relative(o.workspaceDir, b.hostPath)
628
+ )}`, h), {})
629
+ }, c = a?.children?.length || 0, u = v.modify(
611
630
  n,
612
631
  ["configurations", c],
613
- p,
632
+ d,
614
633
  {
615
634
  formattingOptions: {
616
635
  insertSpaces: !0,
@@ -620,11 +639,11 @@ function st(e, o) {
620
639
  }
621
640
  }
622
641
  );
623
- n = ne(n, d);
642
+ n = ae(n, u);
624
643
  }
625
644
  return n;
626
645
  }
627
- async function at({
646
+ async function lt({
628
647
  name: e,
629
648
  ides: o,
630
649
  host: t,
@@ -633,15 +652,15 @@ async function at({
633
652
  mounts: n,
634
653
  ideKey: r = "PLAYGROUNDCLI"
635
654
  }) {
636
- const a = nt(s, n), l = [];
655
+ const a = it(s, n), l = [];
637
656
  if (o.includes("phpstorm")) {
638
- const p = ".idea/workspace.xml", c = g.join(
657
+ const d = ".idea/workspace.xml", c = m.join(
639
658
  s,
640
- p
659
+ d
641
660
  );
642
- if (!u.existsSync(c)) {
643
- if (u.existsSync(g.dirname(c)))
644
- u.writeFileSync(
661
+ if (!p.existsSync(c)) {
662
+ if (p.existsSync(m.dirname(c)))
663
+ p.writeFileSync(
645
664
  c,
646
665
  `<?xml version="1.0" encoding="UTF-8"?>
647
666
  <project version="4">
@@ -652,26 +671,27 @@ async function at({
652
671
  "PhpStorm IDE integration requested, but no '.idea' directory was found in the current working directory."
653
672
  );
654
673
  }
655
- if (u.existsSync(c)) {
656
- const d = u.readFileSync(c, "utf8"), m = it(d, {
674
+ if (p.existsSync(c)) {
675
+ const u = p.readFileSync(c, "utf8"), h = st(u, {
657
676
  name: e,
658
677
  host: t,
659
678
  port: i,
679
+ projectDir: s,
660
680
  mappings: a,
661
681
  ideKey: r
662
682
  });
663
- u.writeFileSync(c, m);
683
+ p.writeFileSync(c, h);
664
684
  }
665
- l.push(p);
685
+ l.push(d);
666
686
  }
667
687
  if (o.includes("vscode")) {
668
- const p = ".vscode/launch.json", c = g.join(
688
+ const d = ".vscode/launch.json", c = m.join(
669
689
  s,
670
- p
690
+ d
671
691
  );
672
- if (!u.existsSync(c)) {
673
- if (u.existsSync(g.dirname(c)))
674
- u.writeFileSync(
692
+ if (!p.existsSync(c)) {
693
+ if (p.existsSync(m.dirname(c)))
694
+ p.writeFileSync(
675
695
  c,
676
696
  `{
677
697
  "configurations": []
@@ -682,20 +702,21 @@ async function at({
682
702
  "VS Code IDE integration requested, but no '.vscode' directory was found in the current working directory."
683
703
  );
684
704
  }
685
- if (u.existsSync(c)) {
686
- const d = u.readFileSync(c, "utf-8"), m = st(d, {
705
+ if (p.existsSync(c)) {
706
+ const u = p.readFileSync(c, "utf-8"), h = at(u, {
687
707
  name: e,
708
+ workspaceDir: s,
688
709
  mappings: a
689
710
  });
690
- m !== d && (u.writeFileSync(c, m), l.push(p));
711
+ h !== u && (p.writeFileSync(c, h), l.push(d));
691
712
  }
692
713
  }
693
714
  return l;
694
715
  }
695
- async function lt(e, o) {
696
- const t = g.join(o, ".idea/workspace.xml");
697
- if (u.existsSync(t)) {
698
- const s = u.readFileSync(t, "utf8"), n = new Q(E), r = (() => {
716
+ async function ct(e, o) {
717
+ const t = m.join(o, ".idea/workspace.xml");
718
+ if (p.existsSync(t)) {
719
+ const s = p.readFileSync(t, "utf8"), n = new oe(E), r = (() => {
699
720
  try {
700
721
  return n.parse(s, !0);
701
722
  } catch {
@@ -703,45 +724,45 @@ async function lt(e, o) {
703
724
  "PhpStorm configuration file is not valid XML."
704
725
  );
705
726
  }
706
- })(), p = r.find(
707
- (d) => !!d?.project
727
+ })(), d = r.find(
728
+ (u) => !!u?.project
708
729
  )?.project?.find(
709
- (d) => !!d?.component && d?.[":@"]?.name === "PhpServers"
730
+ (u) => !!u?.component && u?.[":@"]?.name === "PhpServers"
710
731
  )?.component?.find(
711
- (d) => !!d?.servers
712
- ), c = p?.servers?.findIndex(
713
- (d) => !!d?.server && d?.[":@"]?.name === e
732
+ (u) => !!u?.servers
733
+ ), c = d?.servers?.findIndex(
734
+ (u) => !!u?.server && u?.[":@"]?.name === e
714
735
  );
715
736
  if (c !== void 0 && c >= 0) {
716
- p.servers.splice(c, 1);
717
- const m = new ee(re).build(r);
737
+ d.servers.splice(c, 1);
738
+ const h = new re(se).build(r);
718
739
  try {
719
- n.parse(m, !0);
740
+ n.parse(h, !0);
720
741
  } catch {
721
742
  throw new Error(
722
743
  "The resulting PhpStorm configuration file is not valid XML."
723
744
  );
724
745
  }
725
- m === `<?xml version="1.0" encoding="UTF-8"?>
746
+ h === `<?xml version="1.0" encoding="UTF-8"?>
726
747
  <project version="4">
727
748
  <component name="PhpServers">
728
749
  <servers></servers>
729
750
  </component>
730
- </project>` ? u.unlinkSync(t) : u.writeFileSync(t, m);
751
+ </project>` ? p.unlinkSync(t) : p.writeFileSync(t, h);
731
752
  }
732
753
  }
733
- const i = g.join(o, ".vscode/launch.json");
734
- if (u.existsSync(i)) {
735
- const s = [], n = u.readFileSync(i, "utf-8"), r = P.parseTree(n, s, R);
754
+ const i = m.join(o, ".vscode/launch.json");
755
+ if (p.existsSync(i)) {
756
+ const s = [], n = p.readFileSync(i, "utf-8"), r = v.parseTree(n, s, F);
736
757
  if (r === void 0 || s.length)
737
758
  throw new Error("VS Code configuration file is not valid JSON.");
738
- const l = P.findNodeAtLocation(r, [
759
+ const l = v.findNodeAtLocation(r, [
739
760
  "configurations"
740
761
  ])?.children?.findIndex(
741
- (p) => P.findNodeAtLocation(p, ["name"])?.value === e
762
+ (d) => v.findNodeAtLocation(d, ["name"])?.value === e
742
763
  );
743
764
  if (l !== void 0 && l >= 0) {
744
- const p = P.modify(
765
+ const d = v.modify(
745
766
  n,
746
767
  ["configurations", l],
747
768
  void 0,
@@ -753,18 +774,18 @@ async function lt(e, o) {
753
774
  `
754
775
  }
755
776
  }
756
- ), c = ne(n, p);
777
+ ), c = ae(n, d);
757
778
  c === `{
758
779
  "configurations": []
759
- }` ? u.unlinkSync(i) : u.writeFileSync(i, c);
780
+ }` ? p.unlinkSync(i) : p.writeFileSync(i, c);
760
781
  }
761
782
  }
762
783
  }
763
- function ne(e, o) {
764
- const t = [], i = P.applyEdits(e, o);
765
- if (t.length = 0, P.parseTree(i, t, R), t.length) {
784
+ function ae(e, o) {
785
+ const t = [], i = v.applyEdits(e, o);
786
+ if (t.length = 0, v.parseTree(i, t, F), t.length) {
766
787
  const s = t.map((r) => ({
767
- message: P.printParseErrorCode(r.error),
788
+ message: v.printParseErrorCode(r.error),
768
789
  offset: r.offset,
769
790
  length: r.length,
770
791
  fragment: i.slice(
@@ -790,14 +811,17 @@ function ne(e, o) {
790
811
  }
791
812
  return i;
792
813
  }
793
- const _ = {
794
- Quiet: { name: "quiet", severity: A.Fatal },
795
- Normal: { name: "normal", severity: A.Info },
796
- Debug: { name: "debug", severity: A.Debug }
814
+ function le(e) {
815
+ return e.replaceAll(m.sep, m.posix.sep);
816
+ }
817
+ const H = {
818
+ Quiet: { name: "quiet", severity: N.Fatal },
819
+ Normal: { name: "normal", severity: N.Info },
820
+ Debug: { name: "debug", severity: N.Debug }
797
821
  };
798
- async function Dt() {
822
+ async function At() {
799
823
  try {
800
- const e = Le(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command", {
824
+ const e = $e(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command", {
801
825
  describe: "Command to run",
802
826
  choices: ["server", "run-blueprint", "build-snapshot"],
803
827
  demandOption: !0
@@ -815,8 +839,8 @@ async function Dt() {
815
839
  }).option("php", {
816
840
  describe: "PHP version to use.",
817
841
  type: "string",
818
- default: G,
819
- choices: ue
842
+ default: ee,
843
+ choices: me
820
844
  }).option("wp", {
821
845
  describe: "WordPress version to use.",
822
846
  type: "string",
@@ -825,24 +849,24 @@ async function Dt() {
825
849
  describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",
826
850
  type: "array",
827
851
  string: !0,
828
- coerce: J
852
+ coerce: Y
829
853
  }).option("mount-before-install", {
830
854
  describe: "Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",
831
855
  type: "array",
832
856
  string: !0,
833
- coerce: J
857
+ coerce: Y
834
858
  }).option("mount-dir", {
835
859
  describe: 'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',
836
860
  type: "array",
837
861
  nargs: 2,
838
- array: !0
839
- // coerce: parseMountDirArguments,
862
+ array: !0,
863
+ coerce: G
840
864
  }).option("mount-dir-before-install", {
841
865
  describe: 'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',
842
866
  type: "string",
843
867
  nargs: 2,
844
868
  array: !0,
845
- coerce: Se
869
+ coerce: G
846
870
  }).option("login", {
847
871
  describe: "Should log the user in",
848
872
  type: "boolean",
@@ -854,10 +878,20 @@ async function Dt() {
854
878
  describe: 'Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.',
855
879
  type: "boolean",
856
880
  default: !1
857
- }).option("skip-wordpress-setup", {
858
- describe: "Do not download, unzip, and install WordPress. Useful for mounting a pre-configured WordPress directory at /wordpress.",
881
+ }).option("wordpress-install-mode", {
882
+ describe: "Control how Playground prepares WordPress before booting.",
883
+ type: "string",
884
+ default: "download-and-install",
885
+ choices: [
886
+ "download-and-install",
887
+ "install-from-existing-files",
888
+ "install-from-existing-files-if-needed",
889
+ "do-not-attempt-installing"
890
+ ]
891
+ }).option("skip-wordpress-install", {
892
+ describe: "[Deprecated] Use --wordpress-install-mode instead.",
859
893
  type: "boolean",
860
- default: !1
894
+ hidden: !0
861
895
  }).option("skip-sqlite-setup", {
862
896
  describe: "Skip the SQLite integration plugin setup to allow the WordPress site to use MySQL.",
863
897
  type: "boolean",
@@ -870,7 +904,7 @@ async function Dt() {
870
904
  }).option("verbosity", {
871
905
  describe: "Output logs and progress messages.",
872
906
  type: "string",
873
- choices: Object.values(_).map(
907
+ choices: Object.values(H).map(
874
908
  (r) => r.name
875
909
  ),
876
910
  default: "normal"
@@ -917,7 +951,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
917
951
  ).option("experimental-multi-worker", {
918
952
  describe: "Enable experimental multi-worker support which requires a /wordpress directory backed by a real filesystem. Pass a positive number to specify the number of workers to use. Otherwise, default to the number of CPUs minus 1.",
919
953
  type: "number",
920
- coerce: (r) => r ?? Ie().length - 1
954
+ coerce: (r) => r ?? Ce().length - 1
921
955
  }).option("experimental-blueprints-v2-runner", {
922
956
  describe: "Use the experimental Blueprint V2 runner.",
923
957
  type: "boolean",
@@ -931,7 +965,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
931
965
  // Remove the "hidden" flag once Blueprint V2 is fully supported
932
966
  hidden: !0
933
967
  }).showHelpOnFail(!1).strictOptions().check(async (r) => {
934
- if ((r["skip-wordpress-setup"] || r.skipWordpressSetup) && (r.skipWordPressSetup = !0), r.wp !== void 0 && !qe(r.wp))
968
+ if (r["skip-wordpress-install"] === !0 && (r["wordpress-install-mode"] = "do-not-attempt-installing", r.wordpressInstallMode = "do-not-attempt-installing"), r.wp !== void 0 && !ze(r.wp))
935
969
  try {
936
970
  new URL(r.wp);
937
971
  } catch {
@@ -950,7 +984,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
950
984
  if (r["auto-mount"]) {
951
985
  let a = !1;
952
986
  try {
953
- a = u.statSync(r["auto-mount"]).isDirectory();
987
+ a = p.statSync(r["auto-mount"]).isDirectory();
954
988
  } catch {
955
989
  a = !1;
956
990
  }
@@ -965,9 +999,9 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
965
999
  );
966
1000
  if (r["experimental-blueprints-v2-runner"] === !0) {
967
1001
  if (r.mode !== void 0) {
968
- if ("skip-wordpress-setup" in r)
1002
+ if (r["wordpress-install-mode"] !== void 0)
969
1003
  throw new Error(
970
- "The --skipWordPressSetup option cannot be used with the --mode option. Use one or the other."
1004
+ "The --wordpress-install-mode option cannot be used with the --mode option. Use one or the other."
971
1005
  );
972
1006
  if ("skip-sqlite-setup" in r)
973
1007
  throw new Error(
@@ -978,7 +1012,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
978
1012
  "The --mode option cannot be used with --auto-mount because --auto-mount automatically sets the mode."
979
1013
  );
980
1014
  } else
981
- r["skip-wordpress-setup"] === !0 ? r.mode = "apply-to-existing-site" : r.mode = "create-new-site";
1015
+ r["wordpress-install-mode"] === "do-not-attempt-installing" ? r.mode = "apply-to-existing-site" : r.mode = "create-new-site";
982
1016
  const a = r.allow || [];
983
1017
  r.followSymlinks === !0 && a.push("follow-symlinks"), r["blueprint-may-read-adjacent-files"] === !0 && a.push("read-local-fs"), r.allow = a;
984
1018
  } else if (r.mode !== void 0)
@@ -1011,7 +1045,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
1011
1045
  if (!(e instanceof Error))
1012
1046
  throw e;
1013
1047
  if (process.argv.includes("--debug"))
1014
- de(e);
1048
+ he(e);
1015
1049
  else {
1016
1050
  const t = [];
1017
1051
  let i = e;
@@ -1019,108 +1053,114 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
1019
1053
  t.push(i.message), i = i.cause;
1020
1054
  while (i instanceof Error);
1021
1055
  console.error(
1022
- "\x1B[1m" + t.join(" caused by ") + "\x1B[0m"
1056
+ "\x1B[1m" + t.join(" caused by: ") + "\x1B[0m"
1023
1057
  );
1024
1058
  }
1025
1059
  process.exit(1);
1026
1060
  }
1027
1061
  }
1028
- const U = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, ct = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, N = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, Z = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
1062
+ const M = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, dt = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, V = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, K = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
1029
1063
  async function pt(e) {
1030
1064
  let o, t;
1031
1065
  const i = [];
1032
- if (e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = ke(e)), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug ? e.verbosity = "debug" : e.verbosity === "debug" && (e.debug = !0), e.verbosity) {
1033
- const l = Object.values(_).find(
1034
- (p) => p.name === e.verbosity
1066
+ if (e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = ke(e)), e.wordpressInstallMode === void 0 && (e.wordpressInstallMode = "download-and-install"), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug ? e.verbosity = "debug" : e.verbosity === "debug" && (e.debug = !0), e.verbosity) {
1067
+ const l = Object.values(H).find(
1068
+ (d) => d.name === e.verbosity
1035
1069
  ).severity;
1036
- h.setSeverityFilterLevel(l);
1070
+ g.setSeverityFilterLevel(l);
1037
1071
  }
1038
- const s = K.platform() === "win32" ? (
1072
+ const s = te.platform() === "win32" ? (
1039
1073
  // @TODO: Enable fs-ext here when it works with Windows.
1040
1074
  void 0
1041
1075
  ) : await import("fs-ext").then((l) => l.flockSync).catch(() => {
1042
- h.warn(
1076
+ g.warn(
1043
1077
  "The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking."
1044
1078
  );
1045
1079
  }), n = new Ee(s);
1046
1080
  let r = !1, a = !0;
1047
- return h.log("Starting a PHP server..."), Ve({
1081
+ return g.log("Starting a PHP server..."), Oe({
1048
1082
  port: e.port,
1049
- onBind: async (l, p) => {
1050
- const c = "127.0.0.1", d = `http://${c}:${p}`, m = e["site-url"] || d, b = e.experimentalMultiWorker ?? 1, v = Math.floor(
1051
- Number.MAX_SAFE_INTEGER / b
1052
- ), I = "-playground-cli-site-", k = await Ge(
1053
- I
1083
+ onBind: async (l, d) => {
1084
+ const c = "127.0.0.1", u = `http://${c}:${d}`, h = e["site-url"] || u, b = e.experimentalMultiWorker ?? 1, S = b + 1, k = Math.floor(
1085
+ Number.MAX_SAFE_INTEGER / S
1086
+ ), j = "-playground-cli-site-", x = await Ke(
1087
+ j
1054
1088
  );
1055
- h.debug(`Native temp dir for VFS root: ${k.path}`);
1056
- const x = "WP Playground CLI - Listen for Xdebug", f = ".playground-xdebug-root", W = g.join(process.cwd(), f);
1057
- if (await rt(W), e.xdebug && e.experimentalUnsafeIdeIntegration) {
1058
- await ot(
1059
- k.path,
1060
- W,
1089
+ g.debug(`Native temp dir for VFS root: ${x.path}`);
1090
+ const f = "WP Playground CLI - Listen for Xdebug", B = ".playground-xdebug-root", q = m.join(process.cwd(), B);
1091
+ if (await nt(q), e.xdebug && e.experimentalUnsafeIdeIntegration) {
1092
+ await rt(
1093
+ x.path,
1094
+ q,
1061
1095
  process.platform
1062
1096
  );
1063
- const y = {
1064
- hostPath: `./${f}`,
1097
+ const w = {
1098
+ hostPath: m.join(".", m.sep, B),
1065
1099
  vfsPath: "/"
1066
1100
  };
1067
1101
  try {
1068
- await lt(x, process.cwd());
1069
- const w = typeof e.xdebug == "object" ? e.xdebug : void 0, L = await at({
1070
- name: x,
1102
+ await ct(f, process.cwd());
1103
+ const y = typeof e.xdebug == "object" ? e.xdebug : void 0, $ = await lt({
1104
+ name: f,
1071
1105
  host: c,
1072
- port: p,
1106
+ port: d,
1073
1107
  ides: e.experimentalUnsafeIdeIntegration,
1074
1108
  cwd: process.cwd(),
1075
1109
  mounts: [
1076
- y,
1110
+ w,
1077
1111
  ...e["mount-before-install"] || [],
1078
1112
  ...e.mount || []
1079
1113
  ],
1080
- ideKey: w?.ideKey
1081
- }), S = e.experimentalUnsafeIdeIntegration, T = S.includes("vscode"), B = S.includes("phpstorm");
1082
- console.log(""), console.log(U("Xdebug configured successfully")), console.log(
1083
- Z("Updated IDE config: ") + L.join(" ")
1114
+ ideKey: y?.ideKey
1115
+ }), P = e.experimentalUnsafeIdeIntegration, I = P.includes("vscode"), C = P.includes("phpstorm");
1116
+ console.log(""), console.log(M("Xdebug configured successfully")), console.log(
1117
+ K("Updated IDE config: ") + $.join(" ")
1084
1118
  ), console.log(
1085
- Z("Playground source root: ") + ".playground-xdebug-root" + N(
1086
- ct(
1119
+ K("Playground source root: ") + ".playground-xdebug-root" + V(
1120
+ dt(
1087
1121
  " – you can set breakpoints and preview Playground's VFS structure in there."
1088
1122
  )
1089
1123
  )
1090
- ), console.log(""), T && (console.log(U("VS Code / Cursor instructions:")), console.log(
1091
- " 1. Open the Run and Debug panel on the left sidebar"
1124
+ ), console.log(""), I && (console.log(M("VS Code / Cursor instructions:")), console.log(
1125
+ " 1. Ensure you have installed an IDE extension for PHP Debugging"
1126
+ ), console.log(
1127
+ ` (The ${M("PHP Debug")} extension by ${M(
1128
+ "Xdebug"
1129
+ )} has been a solid option)`
1092
1130
  ), console.log(
1093
- ` 2. Select "${N(
1094
- x
1131
+ " 2. Open the Run and Debug panel on the left sidebar"
1132
+ ), console.log(
1133
+ ` 3. Select "${V(
1134
+ f
1095
1135
  )}" from the dropdown`
1096
1136
  ), console.log(' 3. Click "start debugging"'), console.log(
1097
- " 4. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
1137
+ " 5. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
1098
1138
  ), console.log(
1099
- " 5. Visit Playground in your browser to hit the breakpoint"
1100
- ), B && console.log("")), B && (console.log(U("PhpStorm instructions:")), console.log(
1101
- ` 1. Choose "${N(
1102
- x
1139
+ " 6. Visit Playground in your browser to hit the breakpoint"
1140
+ ), C && console.log("")), C && (console.log(M("PhpStorm instructions:")), console.log(
1141
+ ` 1. Choose "${V(
1142
+ f
1103
1143
  )}" debug configuration in the toolbar`
1104
1144
  ), console.log(" 2. Click the debug button (bug icon)`"), console.log(
1105
1145
  " 3. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
1106
1146
  ), console.log(
1107
1147
  " 4. Visit Playground in your browser to hit the breakpoint"
1108
1148
  )), console.log("");
1109
- } catch (w) {
1149
+ } catch (y) {
1110
1150
  throw new Error("Could not configure Xdebug", {
1111
- cause: w
1151
+ cause: y
1112
1152
  });
1113
1153
  }
1114
1154
  }
1115
- const ie = g.dirname(k.path), se = 2 * 24 * 60 * 60 * 1e3;
1116
- Ke(
1117
- I,
1118
- se,
1119
- ie
1155
+ const ce = m.dirname(x.path), de = 2 * 24 * 60 * 60 * 1e3;
1156
+ Qe(
1157
+ j,
1158
+ de,
1159
+ ce
1120
1160
  );
1121
- const F = g.join(k.path, "internal");
1122
- z(F);
1123
- const ae = [
1161
+ const W = m.join(x.path, "internal");
1162
+ J(W);
1163
+ const pe = [
1124
1164
  "wordpress",
1125
1165
  // Note: These dirs are from Emscripten's "default dirs" list:
1126
1166
  // https://github.com/emscripten-core/emscripten/blob/f431ec220e472e1f8d3db6b52fe23fb377facf30/src/lib/libfs.js#L1400-L1402
@@ -1131,140 +1171,140 @@ async function pt(e) {
1131
1171
  "tmp",
1132
1172
  "home"
1133
1173
  ];
1134
- for (const y of ae) {
1135
- const w = (S) => S.vfsPath === `/${y}`;
1136
- if (!(e["mount-before-install"]?.some(w) || e.mount?.some(w))) {
1137
- const S = g.join(
1138
- k.path,
1139
- y
1174
+ for (const w of pe) {
1175
+ const y = (P) => P.vfsPath === `/${w}`;
1176
+ if (!(e["mount-before-install"]?.some(y) || e.mount?.some(y))) {
1177
+ const P = m.join(
1178
+ x.path,
1179
+ w
1140
1180
  );
1141
- z(S), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1142
- vfsPath: `/${y}`,
1143
- hostPath: S
1181
+ J(P), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1182
+ vfsPath: `/${w}`,
1183
+ hostPath: P
1144
1184
  });
1145
1185
  }
1146
1186
  }
1147
1187
  if (e["mount-before-install"])
1148
- for (const y of e["mount-before-install"])
1149
- h.debug(
1150
- `Mount before WP install: ${y.vfsPath} -> ${y.hostPath}`
1188
+ for (const w of e["mount-before-install"])
1189
+ g.debug(
1190
+ `Mount before WP install: ${w.vfsPath} -> ${w.hostPath}`
1151
1191
  );
1152
1192
  if (e.mount)
1153
- for (const y of e.mount)
1154
- h.debug(
1155
- `Mount after WP install: ${y.vfsPath} -> ${y.hostPath}`
1193
+ for (const w of e.mount)
1194
+ g.debug(
1195
+ `Mount after WP install: ${w.vfsPath} -> ${w.hostPath}`
1156
1196
  );
1157
- let C;
1158
- e["experimental-blueprints-v2-runner"] ? C = new Xe(e, {
1159
- siteUrl: m,
1160
- processIdSpaceLength: v
1161
- }) : (C = new Ye(e, {
1162
- siteUrl: m,
1163
- processIdSpaceLength: v
1164
- }), typeof e.blueprint == "string" && (e.blueprint = await ze({
1197
+ let L;
1198
+ e["experimental-blueprints-v2-runner"] ? L = new Je(e, {
1199
+ siteUrl: h,
1200
+ processIdSpaceLength: k
1201
+ }) : (L = new Ge(e, {
1202
+ siteUrl: h,
1203
+ processIdSpaceLength: k
1204
+ }), typeof e.blueprint == "string" && (e.blueprint = await Xe({
1165
1205
  sourceString: e.blueprint,
1166
1206
  blueprintMayReadAdjacentFiles: e["blueprint-may-read-adjacent-files"] === !0
1167
1207
  })));
1168
- let M = !1;
1169
- const D = async function() {
1170
- M || (M = !0, await Promise.all(
1171
- i.map(async ({ playground: w, worker: L }) => {
1172
- await w.dispose(), await L.terminate();
1208
+ let D = !1;
1209
+ const A = async function() {
1210
+ D || (D = !0, await Promise.all(
1211
+ i.map(async ({ playground: y, worker: $ }) => {
1212
+ await y.dispose(), await $.terminate();
1173
1213
  })
1174
- ), l && await new Promise((w) => l.close(w)), await k.cleanup());
1175
- }, le = ut(
1176
- b,
1177
- C.getWorkerType(),
1178
- ({ exitCode: y, workerIndex: w }) => {
1179
- M || y === 0 && h.error(
1180
- `Worker ${w} exited with code ${y}
1214
+ ), l && await new Promise((y) => l.close(y)), await x.cleanup());
1215
+ }, ue = ut(
1216
+ S,
1217
+ L.getWorkerType(),
1218
+ ({ exitCode: w, workerIndex: y }) => {
1219
+ D || w === 0 && g.error(
1220
+ `Worker ${y} exited with code ${w}
1181
1221
  `
1182
1222
  );
1183
1223
  }
1184
1224
  );
1185
- h.log(`Setting up WordPress ${e.wp}`);
1225
+ g.log("Starting up workers");
1186
1226
  try {
1187
- const [y, ...w] = await le, L = await Y(
1227
+ const w = await ue, y = await Q(
1188
1228
  n
1189
1229
  );
1190
- if (t = await C.bootPrimaryWorker(
1191
- y.phpPort,
1192
- L,
1193
- F
1194
- ), i.push({
1195
- playground: t,
1196
- worker: y.worker
1197
- }), await t.isReady(), r = !0, h.log("Booted!"), o = new He(t), !e["experimental-blueprints-v2-runner"]) {
1198
- const S = await C.compileInputBlueprint(
1199
- e["additional-blueprint-steps"] || []
1200
- );
1201
- S && (h.log("Running the Blueprint..."), await be(
1202
- S,
1203
- t
1204
- ), h.log("Finished running the blueprint"));
1205
- }
1206
- if (e.command === "build-snapshot") {
1207
- await ft(t, e.outfile), h.log(`WordPress exported to ${e.outfile}`), await D();
1208
- return;
1209
- } else if (e.command === "run-blueprint") {
1210
- h.log("Blueprint executed"), await D();
1211
- return;
1212
- }
1213
- if (e.experimentalMultiWorker && e.experimentalMultiWorker > 1) {
1214
- h.log("Preparing additional workers...");
1215
- const S = v;
1216
- await Promise.all(
1217
- w.map(async (T, B) => {
1218
- const ce = S + B * v, pe = await Y(n), H = await C.bootSecondaryWorker({
1219
- worker: T,
1220
- fileLockManagerPort: pe,
1221
- firstProcessId: ce,
1222
- nativeInternalDirPath: F
1223
- });
1224
- i.push({
1225
- playground: H,
1226
- worker: T.worker
1227
- }), o.addWorker(H);
1228
- })
1230
+ {
1231
+ const P = w.shift(), I = await L.bootAndSetUpInitialPlayground(
1232
+ P.phpPort,
1233
+ y,
1234
+ W
1229
1235
  );
1236
+ if (await I.isReady(), r = !0, g.log("Booted!"), o = new qe(I), !e["experimental-blueprints-v2-runner"]) {
1237
+ const C = await L.compileInputBlueprint(
1238
+ e["additional-blueprint-steps"] || []
1239
+ );
1240
+ C && (g.log("Running the Blueprint..."), await Pe(
1241
+ C,
1242
+ I
1243
+ ), g.log("Finished running the blueprint"));
1244
+ }
1245
+ if (e.command === "build-snapshot") {
1246
+ await mt(t, e.outfile), g.log(`WordPress exported to ${e.outfile}`), await A();
1247
+ return;
1248
+ } else if (e.command === "run-blueprint") {
1249
+ g.log("Blueprint executed"), await A();
1250
+ return;
1251
+ }
1252
+ await o.removeWorker(I), await I.dispose(), await P.worker.terminate();
1230
1253
  }
1231
- return h.log(
1232
- `WordPress is running on ${d} with ${b} worker(s)`
1233
- ), e.xdebug && e.experimentalDevtools && (await De({
1254
+ g.log("Preparing workers...");
1255
+ const $ = k;
1256
+ return [t] = await Promise.all(
1257
+ w.map(async (P, I) => {
1258
+ const C = $ + I * k, fe = await Q(
1259
+ n
1260
+ ), U = await L.bootPlayground({
1261
+ worker: P,
1262
+ fileLockManagerPort: fe,
1263
+ firstProcessId: C,
1264
+ nativeInternalDirPath: W
1265
+ });
1266
+ return i.push({
1267
+ playground: U,
1268
+ worker: P.worker
1269
+ }), o.addWorker(U), U;
1270
+ })
1271
+ ), g.log(
1272
+ `WordPress is running on ${u} with ${b} worker(s)`
1273
+ ), e.xdebug && e.experimentalDevtools && (await Ae({
1234
1274
  phpInstance: t,
1235
1275
  phpRoot: "/wordpress"
1236
1276
  })).start(), {
1237
1277
  playground: t,
1238
1278
  server: l,
1239
- serverUrl: d,
1240
- [Symbol.asyncDispose]: D,
1279
+ serverUrl: u,
1280
+ [Symbol.asyncDispose]: A,
1241
1281
  workerThreadCount: b
1242
1282
  };
1243
- } catch (y) {
1283
+ } catch (w) {
1244
1284
  if (!e.debug)
1245
- throw y;
1246
- let w = "";
1247
- throw await t?.fileExists(q) && (w = await t.readFileAsText(q)), new Error(w, { cause: y });
1285
+ throw w;
1286
+ let y = "";
1287
+ throw await t?.fileExists(z) && (y = await t.readFileAsText(z)), new Error(y, { cause: w });
1248
1288
  }
1249
1289
  },
1250
1290
  async handleRequest(l) {
1251
1291
  if (!r)
1252
- return V.forHttpCode(
1292
+ return O.forHttpCode(
1253
1293
  502,
1254
1294
  "WordPress is not ready yet"
1255
1295
  );
1256
1296
  if (a) {
1257
1297
  a = !1;
1258
- const p = {
1298
+ const d = {
1259
1299
  "Content-Type": ["text/plain"],
1260
1300
  "Content-Length": ["0"],
1261
1301
  Location: [l.url]
1262
1302
  };
1263
1303
  return l.headers?.cookie?.includes(
1264
1304
  "playground_auto_login_already_happened"
1265
- ) && (p["Set-Cookie"] = [
1305
+ ) && (d["Set-Cookie"] = [
1266
1306
  "playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"
1267
- ]), new V(302, p, new Uint8Array());
1307
+ ]), new O(302, d, new Uint8Array());
1268
1308
  }
1269
1309
  return await o.handleRequest(l);
1270
1310
  }
@@ -1273,7 +1313,7 @@ async function pt(e) {
1273
1313
  async function ut(e, o, t) {
1274
1314
  const i = [];
1275
1315
  for (let s = 0; s < e; s++) {
1276
- const n = await dt(o), r = (a) => {
1316
+ const n = await ft(o), r = (a) => {
1277
1317
  t({
1278
1318
  exitCode: a,
1279
1319
  workerIndex: s
@@ -1282,12 +1322,12 @@ async function ut(e, o, t) {
1282
1322
  i.push(
1283
1323
  new Promise(
1284
1324
  (a, l) => {
1285
- n.once("message", function(p) {
1286
- p.command === "worker-script-initialized" && a({ worker: n, phpPort: p.phpPort });
1287
- }), n.once("error", function(p) {
1288
- console.error(p);
1325
+ n.once("message", function(d) {
1326
+ d.command === "worker-script-initialized" && a({ worker: n, phpPort: d.phpPort });
1327
+ }), n.once("error", function(d) {
1328
+ console.error(d);
1289
1329
  const c = new Error(
1290
- `Worker failed to load worker. ${p.message ? `Original error: ${p.message}` : ""}`
1330
+ `Worker failed to load worker. ${d.message ? `Original error: ${d.message}` : ""}`
1291
1331
  );
1292
1332
  l(c);
1293
1333
  }), n.once("exit", r);
@@ -1297,14 +1337,14 @@ async function ut(e, o, t) {
1297
1337
  }
1298
1338
  return Promise.all(i);
1299
1339
  }
1300
- async function dt(e) {
1301
- return e === "v1" ? new X(new URL("./worker-thread-v1.js", import.meta.url)) : new X(new URL("./worker-thread-v2.js", import.meta.url));
1340
+ async function ft(e) {
1341
+ return e === "v1" ? new Z(new URL("./worker-thread-v1.js", import.meta.url)) : new Z(new URL("./worker-thread-v2.js", import.meta.url));
1302
1342
  }
1303
- async function Y(e) {
1304
- const { port1: o, port2: t } = new Pe();
1305
- return await Ce() ? fe(e, null, o) : await me(e, o), t;
1343
+ async function Q(e) {
1344
+ const { port1: o, port2: t } = new xe();
1345
+ return await Le() ? ge(e, null, o) : await we(e, o), t;
1306
1346
  }
1307
- async function ft(e, o) {
1347
+ async function mt(e, o) {
1308
1348
  await e.run({
1309
1349
  code: `<?php
1310
1350
  $zip = new ZipArchive();
@@ -1326,11 +1366,11 @@ async function ft(e, o) {
1326
1366
  `
1327
1367
  });
1328
1368
  const t = await e.readFileAsBuffer("/tmp/build.zip");
1329
- u.writeFileSync(o, t);
1369
+ p.writeFileSync(o, t);
1330
1370
  }
1331
1371
  export {
1332
- _ as L,
1333
- Dt as p,
1372
+ H as L,
1373
+ At as p,
1334
1374
  pt as r
1335
1375
  };
1336
- //# sourceMappingURL=run-cli-BBfr5tmj.js.map
1376
+ //# sourceMappingURL=run-cli-g3_uJkf5.js.map