@wp-playground/cli 3.0.40 → 3.0.41

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,24 +1,26 @@
1
- import { logger as u, LogSeverity as V, errorLogPath as Z } from "@php-wasm/logger";
2
- import { PHPResponse as _, consumeAPI as D, SupportedPHPVersions as he, printDebugDetails as me, exposeAPI as we, exposeSyncAPI as ge } from "@php-wasm/universal";
3
- import { resolveRemoteBlueprint as ye, resolveRuntimeConfiguration as Y, compileBlueprintV1 as be, isBlueprintBundle as Pe, runBlueprintV1Steps as ve } from "@wp-playground/blueprints";
4
- import { zipDirectory as ke, RecommendedPHPVersion as re } from "@wp-playground/common";
5
- import p, { existsSync as se, mkdirSync as G } from "fs";
6
- import { Worker as Q, MessageChannel as xe } from "worker_threads";
7
- import { createNodeFsMountHandler as Se, FileLockManagerForNode as Ie } from "@php-wasm/node";
8
- import w, { basename as R, join as ne } from "path";
9
- import Te from "express";
10
- import ie, { cpus as $e } from "os";
11
- import { jspi as Ee } from "wasm-feature-detect";
12
- import Ce from "yargs";
13
- import { NodeJsFilesystem as We, OverlayFilesystem as Be, InMemoryFilesystem as Le, ZipFilesystem as Me } from "@wp-playground/storage";
14
- import { EmscriptenDownloadMonitor as Re, ProgressTracker as De } from "@php-wasm/progress";
15
- import { resolveWordPressRelease as Fe } from "@wp-playground/wordpress";
1
+ import { logger as u, LogSeverity as N, errorLogPath as ee } from "@php-wasm/logger";
2
+ import { PHPResponse as j, consumeAPI as D, SupportedPHPVersions as te, printDebugDetails as ye, exposeAPI as be, exposeSyncAPI as Pe } from "@php-wasm/universal";
3
+ import { resolveRemoteBlueprint as ve, resolveRuntimeConfiguration as oe, compileBlueprintV1 as ke, isBlueprintBundle as xe, runBlueprintV1Steps as Se } from "@wp-playground/blueprints";
4
+ import { zipDirectory as Ie, RecommendedPHPVersion as q } from "@wp-playground/common";
5
+ import f, { existsSync as Y, rmdirSync as $e, mkdirSync as z, readdirSync as Te } from "fs";
6
+ import { MessageChannel as Ee, Worker as re } from "worker_threads";
7
+ import { createNodeFsMountHandler as Ce, FileLockManagerForNode as We } from "@php-wasm/node";
8
+ import h, { basename as R, join as de } from "path";
9
+ import Be from "express";
10
+ import U, { cpus as Me } from "os";
11
+ import { jspi as Le } from "wasm-feature-detect";
12
+ import Re from "yargs";
13
+ import { NodeJsFilesystem as De, OverlayFilesystem as Ue, InMemoryFilesystem as Fe, ZipFilesystem as Ae } from "@wp-playground/storage";
14
+ import { EmscriptenDownloadMonitor as He, ProgressTracker as Ve } from "@php-wasm/progress";
15
+ import { resolveWordPressRelease as Ne } from "@wp-playground/wordpress";
16
16
  import C from "fs-extra";
17
- import { startBridge as Ue } from "@php-wasm/xdebug-bridge";
18
- import { dir as Ae, setGracefulCleanup as He } from "tmp-promise";
19
- import Ve from "ps-man";
20
- import { removeTempDirSymlink as Ne, createTempDirSymlink as _e, clearXdebugIDEConfig as Oe, addXdebugIDEConfig as je } from "@php-wasm/cli-util";
21
- function J(e) {
17
+ import { startBridge as Oe } from "@php-wasm/xdebug-bridge";
18
+ import { exec as _e } from "child_process";
19
+ import { dir as je, setGracefulCleanup as qe } from "tmp-promise";
20
+ import ze from "ps-man";
21
+ import { removeTempDirSymlink as Xe, createTempDirSymlink as Ye, clearXdebugIDEConfig as Ze, addXdebugIDEConfig as Ge } from "@php-wasm/cli-util";
22
+ import { createHash as Je } from "crypto";
23
+ function O(e) {
22
24
  const t = [];
23
25
  for (const o of e) {
24
26
  const n = o.split(":");
@@ -28,35 +30,35 @@ function J(e) {
28
30
  If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
29
31
  Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);
30
32
  const [r, s] = n;
31
- if (!se(r))
33
+ if (!Y(r))
32
34
  throw new Error(`Host path does not exist: ${r}`);
33
35
  t.push({ hostPath: r, vfsPath: s });
34
36
  }
35
37
  return t;
36
38
  }
37
- function K(e) {
39
+ function se(e) {
38
40
  if (e.length % 2 !== 0)
39
41
  throw new Error("Invalid mount format. Expected: /host/path /vfs/path");
40
42
  const t = [];
41
43
  for (let o = 0; o < e.length; o += 2) {
42
44
  const n = e[o], r = e[o + 1];
43
- if (!se(n))
45
+ if (!Y(n))
44
46
  throw new Error(`Host path does not exist: ${n}`);
45
47
  t.push({
46
- hostPath: w.resolve(process.cwd(), n),
48
+ hostPath: h.resolve(process.cwd(), n),
47
49
  vfsPath: r
48
50
  });
49
51
  }
50
52
  return t;
51
53
  }
52
- async function At(e, t) {
54
+ async function Zt(e, t) {
53
55
  for (const o of t)
54
56
  await e.mount(
55
57
  o.vfsPath,
56
- Se(o.hostPath)
58
+ Ce(o.hostPath)
57
59
  );
58
60
  }
59
- const ee = {
61
+ const ne = {
60
62
  step: "runPHP",
61
63
  code: {
62
64
  filename: "activate-theme.php",
@@ -75,7 +77,7 @@ const ee = {
75
77
  `
76
78
  }
77
79
  };
78
- function qe(e) {
80
+ function ue(e) {
79
81
  const t = e.autoMount, o = [...e.mount || []], n = [...e["mount-before-install"] || []], r = {
80
82
  ...e,
81
83
  mount: o,
@@ -84,7 +86,7 @@ function qe(e) {
84
86
  ...e["additional-blueprint-steps"] || []
85
87
  ]
86
88
  };
87
- if (Ye(t)) {
89
+ if (tt(t)) {
88
90
  const s = R(t);
89
91
  o.push({
90
92
  hostPath: t,
@@ -93,7 +95,7 @@ function qe(e) {
93
95
  step: "activatePlugin",
94
96
  pluginPath: `/wordpress/wp-content/plugins/${R(t)}`
95
97
  });
96
- } else if (Ze(t)) {
98
+ } else if (et(t)) {
97
99
  const s = R(t);
98
100
  o.push({
99
101
  hostPath: t,
@@ -107,80 +109,80 @@ function qe(e) {
107
109
  themeFolderName: s
108
110
  }
109
111
  );
110
- } else if (Xe(t)) {
111
- const s = p.readdirSync(t);
112
- for (const a of s)
113
- a !== "index.php" && o.push({
114
- hostPath: `${t}/${a}`,
115
- vfsPath: `/wordpress/wp-content/${a}`
112
+ } else if (Ke(t)) {
113
+ const s = f.readdirSync(t);
114
+ for (const i of s)
115
+ i !== "index.php" && o.push({
116
+ hostPath: `${t}/${i}`,
117
+ vfsPath: `/wordpress/wp-content/${i}`
116
118
  });
117
- r["additional-blueprint-steps"].push(ee);
118
- } else ze(t) ? (n.push({ hostPath: t, vfsPath: "/wordpress" }), r.mode = "apply-to-existing-site", r["additional-blueprint-steps"].push(ee), r.wordpressInstallMode || (r.wordpressInstallMode = "install-from-existing-files-if-needed")) : (o.push({ hostPath: t, vfsPath: "/wordpress" }), r.mode = "mount-only");
119
+ r["additional-blueprint-steps"].push(ne);
120
+ } else Qe(t) && (n.push({ hostPath: t, vfsPath: "/wordpress" }), r.mode = "apply-to-existing-site", r["additional-blueprint-steps"].push(ne), r.wordpressInstallMode || (r.wordpressInstallMode = "install-from-existing-files-if-needed"));
119
121
  return r;
120
122
  }
121
- function ze(e) {
122
- const t = p.readdirSync(e);
123
+ function Qe(e) {
124
+ const t = f.readdirSync(e);
123
125
  return t.includes("wp-admin") && t.includes("wp-includes") && t.includes("wp-content");
124
126
  }
125
- function Xe(e) {
126
- const t = p.readdirSync(e);
127
+ function Ke(e) {
128
+ const t = f.readdirSync(e);
127
129
  return t.includes("themes") || t.includes("plugins") || t.includes("mu-plugins") || t.includes("uploads");
128
130
  }
129
- function Ze(e) {
130
- if (!p.readdirSync(e).includes("style.css"))
131
+ function et(e) {
132
+ if (!f.readdirSync(e).includes("style.css"))
131
133
  return !1;
132
- const o = p.readFileSync(ne(e, "style.css"), "utf8");
134
+ const o = f.readFileSync(de(e, "style.css"), "utf8");
133
135
  return !!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(o);
134
136
  }
135
- function Ye(e) {
136
- const t = p.readdirSync(e), o = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
137
+ function tt(e) {
138
+ const t = f.readdirSync(e), o = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
137
139
  return !!t.filter((r) => r.endsWith(".php")).find((r) => {
138
- const s = p.readFileSync(ne(e, r), "utf8");
140
+ const s = f.readFileSync(de(e, r), "utf8");
139
141
  return !!o.exec(s);
140
142
  });
141
143
  }
142
- async function Ge(e) {
143
- const t = Te(), o = await new Promise((s, a) => {
144
+ async function ot(e) {
145
+ const t = Be(), o = await new Promise((s, i) => {
144
146
  const l = t.listen(e.port, () => {
145
147
  const d = l.address();
146
- d === null || typeof d == "string" ? a(new Error("Server address is not available")) : s(l);
148
+ d === null || typeof d == "string" ? i(new Error("Server address is not available")) : s(l);
147
149
  });
148
150
  });
149
- t.use("/", async (s, a) => {
151
+ t.use("/", async (s, i) => {
150
152
  let l;
151
153
  try {
152
154
  l = await e.handleRequest({
153
155
  url: s.url,
154
- headers: Je(s),
156
+ headers: st(s),
155
157
  method: s.method,
156
- body: await Qe(s)
158
+ body: await rt(s)
157
159
  });
158
160
  } catch (d) {
159
- u.error(d), l = _.forHttpCode(500);
161
+ u.error(d), l = j.forHttpCode(500);
160
162
  }
161
- a.statusCode = l.httpStatusCode;
163
+ i.statusCode = l.httpStatusCode;
162
164
  for (const d in l.headers)
163
- a.setHeader(d, l.headers[d]);
164
- a.end(l.bytes);
165
+ i.setHeader(d, l.headers[d]);
166
+ i.end(l.bytes);
165
167
  });
166
168
  const r = o.address().port;
167
169
  return await e.onBind(o, r);
168
170
  }
169
- const Qe = async (e) => await new Promise((t) => {
171
+ const rt = async (e) => await new Promise((t) => {
170
172
  const o = [];
171
173
  e.on("data", (n) => {
172
174
  o.push(n);
173
175
  }), e.on("end", () => {
174
176
  t(new Uint8Array(Buffer.concat(o)));
175
177
  });
176
- }), Je = (e) => {
178
+ }), st = (e) => {
177
179
  const t = {};
178
180
  if (e.rawHeaders && e.rawHeaders.length)
179
181
  for (let o = 0; o < e.rawHeaders.length; o += 2)
180
182
  t[e.rawHeaders[o].toLowerCase()] = e.rawHeaders[o + 1];
181
183
  return t;
182
184
  };
183
- class Ke {
185
+ class nt {
184
186
  constructor(t) {
185
187
  this.workerLoads = [], this.addWorker(t);
186
188
  }
@@ -211,33 +213,33 @@ class Ke {
211
213
  });
212
214
  }
213
215
  }
214
- function et(e) {
216
+ function it(e) {
215
217
  return /^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e);
216
218
  }
217
- async function tt({
219
+ async function at({
218
220
  sourceString: e,
219
221
  blueprintMayReadAdjacentFiles: t
220
222
  }) {
221
223
  if (!e)
222
224
  return;
223
225
  if (e.startsWith("http://") || e.startsWith("https://"))
224
- return await ye(e);
225
- let o = w.resolve(process.cwd(), e);
226
- if (!p.existsSync(o))
226
+ return await ve(e);
227
+ let o = h.resolve(process.cwd(), e);
228
+ if (!f.existsSync(o))
227
229
  throw new Error(`Blueprint file does not exist: ${o}`);
228
- const n = p.statSync(o);
229
- if (n.isDirectory() && (o = w.join(o, "blueprint.json")), !n.isFile() && n.isSymbolicLink())
230
+ const n = f.statSync(o);
231
+ if (n.isDirectory() && (o = h.join(o, "blueprint.json")), !n.isFile() && n.isSymbolicLink())
230
232
  throw new Error(
231
233
  `Blueprint path is neither a file nor a directory: ${o}`
232
234
  );
233
- const r = w.extname(o);
235
+ const r = h.extname(o);
234
236
  switch (r) {
235
237
  case ".zip":
236
- return Me.fromArrayBuffer(
237
- p.readFileSync(o).buffer
238
+ return Ae.fromArrayBuffer(
239
+ f.readFileSync(o).buffer
238
240
  );
239
241
  case ".json": {
240
- const s = p.readFileSync(o, "utf-8");
242
+ const s = f.readFileSync(o, "utf-8");
241
243
  try {
242
244
  JSON.parse(s);
243
245
  } catch {
@@ -245,9 +247,9 @@ async function tt({
245
247
  `Blueprint file at ${o} is not a valid JSON file`
246
248
  );
247
249
  }
248
- const a = w.dirname(o), l = new We(a);
249
- return new Be([
250
- new Le({
250
+ const i = h.dirname(o), l = new De(i);
251
+ return new Ue([
252
+ new Fe({
251
253
  "blueprint.json": s
252
254
  }),
253
255
  /**
@@ -273,10 +275,10 @@ You can allow this Blueprint to read files from the same parent directory by exp
273
275
  );
274
276
  }
275
277
  }
276
- function ae(e) {
278
+ function ce(e) {
277
279
  return process.env.CI === "true" || process.env.CI === "1" || process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1" || (process.env.TERM || "").toLowerCase() === "dumb" ? !1 : e ? !!e.isTTY : process.stdout.isTTY;
278
280
  }
279
- class ot {
281
+ class lt {
280
282
  constructor(t, o) {
281
283
  this.lastProgressMessage = "", this.args = t, this.siteUrl = o.siteUrl, this.processIdSpaceLength = o.processIdSpaceLength, this.phpVersion = t.php;
282
284
  }
@@ -292,7 +294,7 @@ class ot {
292
294
  siteUrl: this.siteUrl,
293
295
  firstProcessId: 1,
294
296
  processIdSpaceLength: this.processIdSpaceLength,
295
- trace: this.args.debug || !1,
297
+ trace: this.args.verbosity === "debug",
296
298
  blueprint: this.args.blueprint,
297
299
  withIntl: this.args.intl,
298
300
  // We do not enable Xdebug by default for the initial worker
@@ -315,58 +317,58 @@ class ot {
315
317
  }) {
316
318
  const s = D(t.phpPort);
317
319
  await s.useFileLockManager(o);
318
- const a = {
320
+ const i = {
319
321
  ...this.args,
320
322
  phpVersion: this.phpVersion,
321
323
  siteUrl: this.siteUrl,
322
324
  firstProcessId: n,
323
325
  processIdSpaceLength: this.processIdSpaceLength,
324
- trace: this.args.debug || !1,
326
+ trace: this.args.verbosity === "debug",
325
327
  withIntl: this.args.intl,
326
328
  withXdebug: !!this.args.xdebug,
327
329
  nativeInternalDirPath: r,
328
330
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
329
331
  mountsAfterWpInstall: this.args.mount || []
330
332
  };
331
- return await s.bootWorker(a), s;
333
+ return await s.bootWorker(i), s;
332
334
  }
333
335
  writeProgressUpdate(t, o, n) {
334
- ae(t) && o !== this.lastProgressMessage && (this.lastProgressMessage = o, t.isTTY ? (t.cursorTo(0), t.write(o), t.clearLine(1), n && t.write(`
336
+ ce(t) && o !== this.lastProgressMessage && (this.lastProgressMessage = o, t.isTTY ? (t.cursorTo(0), t.write(o), t.clearLine(1), n && t.write(`
335
337
  `)) : t.write(`${o}
336
338
  `));
337
339
  }
338
340
  }
339
- const O = w.join(ie.homedir(), ".wordpress-playground");
340
- async function rt(e) {
341
- return await le(
341
+ const X = h.join(U.homedir(), ".wordpress-playground");
342
+ async function dt(e) {
343
+ return await pe(
342
344
  "https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip",
343
345
  "sqlite.zip",
344
346
  e
345
347
  );
346
348
  }
347
- async function le(e, t, o) {
348
- const n = w.join(O, t);
349
- return C.existsSync(n) || (C.ensureDirSync(O), await st(e, n, o)), de(n);
349
+ async function pe(e, t, o) {
350
+ const n = h.join(X, t);
351
+ return C.existsSync(n) || (C.ensureDirSync(X), await ut(e, n, o)), fe(n);
350
352
  }
351
- async function st(e, t, o) {
352
- const r = (await o.monitorFetch(fetch(e))).body.getReader(), s = `${t}.partial`, a = C.createWriteStream(s);
353
+ async function ut(e, t, o) {
354
+ const r = (await o.monitorFetch(fetch(e))).body.getReader(), s = `${t}.partial`, i = C.createWriteStream(s);
353
355
  for (; ; ) {
354
356
  const { done: l, value: d } = await r.read();
355
- if (d && a.write(d), l)
357
+ if (d && i.write(d), l)
356
358
  break;
357
359
  }
358
- a.close(), a.closed || await new Promise((l, d) => {
359
- a.on("finish", () => {
360
+ i.close(), i.closed || await new Promise((l, d) => {
361
+ i.on("finish", () => {
360
362
  C.renameSync(s, t), l(null);
361
- }), a.on("error", (f) => {
362
- C.removeSync(s), d(f);
363
+ }), i.on("error", (b) => {
364
+ C.removeSync(s), d(b);
363
365
  });
364
366
  });
365
367
  }
366
- function de(e, t) {
368
+ function fe(e, t) {
367
369
  return new File([C.readFileSync(e)], R(e));
368
370
  }
369
- class nt {
371
+ class ct {
370
372
  constructor(t, o) {
371
373
  this.lastProgressMessage = "", this.args = t, this.siteUrl = o.siteUrl, this.processIdSpaceLength = o.processIdSpaceLength;
372
374
  }
@@ -374,25 +376,25 @@ class nt {
374
376
  return "v1";
375
377
  }
376
378
  async bootAndSetUpInitialPlayground(t, o, n) {
377
- let r, s, a;
378
- const l = new Re();
379
+ let r, s, i;
380
+ const l = new He();
379
381
  if (this.args.wordpressInstallMode === "download-and-install") {
380
- let I = !1;
381
- l.addEventListener("progress", (q) => {
382
- if (I)
382
+ let v = !1;
383
+ l.addEventListener("progress", (W) => {
384
+ if (v)
383
385
  return;
384
- const { loaded: F, total: x } = q.detail, W = Math.floor(
385
- Math.min(100, 100 * F / x)
386
+ const { loaded: G, total: F } = W.detail, k = Math.floor(
387
+ Math.min(100, 100 * G / F)
386
388
  );
387
- I = W === 100, this.writeProgressUpdate(
389
+ v = k === 100, this.writeProgressUpdate(
388
390
  process.stdout,
389
- `Downloading WordPress ${W}%...`,
390
- I
391
+ `Downloading WordPress ${k}%...`,
392
+ v
391
393
  );
392
- }), r = await Fe(this.args.wp), a = w.join(
393
- O,
394
+ }), r = await Ne(this.args.wp), i = h.join(
395
+ X,
394
396
  `prebuilt-wp-content-for-wp-${r.version}.zip`
395
- ), s = p.existsSync(a) ? de(a) : await le(
397
+ ), s = f.existsSync(i) ? fe(i) : await pe(
396
398
  r.releaseUrl,
397
399
  `${r.version}.zip`,
398
400
  l
@@ -401,25 +403,25 @@ class nt {
401
403
  );
402
404
  }
403
405
  let d;
404
- this.args.skipSqliteSetup ? (u.log("Skipping SQLite integration plugin setup..."), d = void 0) : (u.log("Fetching SQLite integration plugin..."), d = await rt(l));
405
- const f = this.args.followSymlinks === !0, i = this.args.experimentalTrace === !0, y = this.args["mount-before-install"] || [], g = this.args.mount || [], P = D(t);
406
- await P.isConnected(), u.log("Booting WordPress...");
407
- const k = await Y(
406
+ this.args.skipSqliteSetup ? (u.log("Skipping SQLite integration plugin setup..."), d = void 0) : (u.log("Fetching SQLite integration plugin..."), d = await dt(l));
407
+ const b = this.args.followSymlinks === !0, g = this.args.experimentalTrace === !0, a = this.args["mount-before-install"] || [], y = this.args.mount || [], p = D(t);
408
+ await p.isConnected(), u.log("Booting WordPress...");
409
+ const I = await oe(
408
410
  this.getEffectiveBlueprint()
409
411
  );
410
- return await P.useFileLockManager(o), await P.bootAndSetUpInitialWorker({
411
- phpVersion: k.phpVersion,
412
- wpVersion: k.wpVersion,
412
+ return await p.useFileLockManager(o), await p.bootAndSetUpInitialWorker({
413
+ phpVersion: I.phpVersion,
414
+ wpVersion: I.wpVersion,
413
415
  siteUrl: this.siteUrl,
414
- mountsBeforeWpInstall: y,
415
- mountsAfterWpInstall: g,
416
+ mountsBeforeWpInstall: a,
417
+ mountsAfterWpInstall: y,
416
418
  wordpressInstallMode: this.args.wordpressInstallMode || "download-and-install",
417
419
  wordPressZip: s && await s.arrayBuffer(),
418
420
  sqliteIntegrationPluginZip: await d?.arrayBuffer(),
419
421
  firstProcessId: 0,
420
422
  processIdSpaceLength: this.processIdSpaceLength,
421
- followSymlinks: f,
422
- trace: i,
423
+ followSymlinks: b,
424
+ trace: g,
423
425
  internalCookieStore: this.args.internalCookieStore,
424
426
  withIntl: this.args.intl,
425
427
  // We do not enable Xdebug by default for the initial worker
@@ -428,10 +430,10 @@ class nt {
428
430
  // TODO: Consider supporting Xdebug for the initial worker via a dedicated flag.
429
431
  withXdebug: !1,
430
432
  nativeInternalDirPath: n
431
- }), a && !this.args["mount-before-install"] && !p.existsSync(a) && (u.log("Caching preinstalled WordPress for the next boot..."), p.writeFileSync(
432
- a,
433
- await ke(P, "/wordpress")
434
- ), u.log("Cached!")), P;
433
+ }), i && !this.args["mount-before-install"] && !f.existsSync(i) && (u.log("Caching preinstalled WordPress for the next boot..."), f.writeFileSync(
434
+ i,
435
+ await Ie(p, "/wordpress")
436
+ ), u.log("Cached!")), p;
435
437
  }
436
438
  async bootPlayground({
437
439
  worker: t,
@@ -443,11 +445,11 @@ class nt {
443
445
  t.phpPort
444
446
  );
445
447
  await s.isConnected();
446
- const a = await Y(
448
+ const i = await oe(
447
449
  this.getEffectiveBlueprint()
448
450
  );
449
451
  return await s.useFileLockManager(o), await s.bootWorker({
450
- phpVersion: a.phpVersion,
452
+ phpVersion: i.phpVersion,
451
453
  siteUrl: this.siteUrl,
452
454
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
453
455
  mountsAfterWpInstall: this.args.mount || [],
@@ -464,45 +466,45 @@ class nt {
464
466
  }), await s.isReady(), s;
465
467
  }
466
468
  async compileInputBlueprint(t) {
467
- const o = this.getEffectiveBlueprint(), n = new De();
469
+ const o = this.getEffectiveBlueprint(), n = new Ve();
468
470
  let r = "", s = !1;
469
- return n.addEventListener("progress", (a) => {
471
+ return n.addEventListener("progress", (i) => {
470
472
  if (s)
471
473
  return;
472
- s = a.detail.progress === 100;
473
- const l = Math.floor(a.detail.progress);
474
- r = a.detail.caption || r || "Running the Blueprint";
474
+ s = i.detail.progress === 100;
475
+ const l = Math.floor(i.detail.progress);
476
+ r = i.detail.caption || r || "Running the Blueprint";
475
477
  const d = `${r.trim()} – ${l}%`;
476
478
  this.writeProgressUpdate(
477
479
  process.stdout,
478
480
  d,
479
481
  s
480
482
  );
481
- }), await be(o, {
483
+ }), await ke(o, {
482
484
  progress: n,
483
485
  additionalSteps: t
484
486
  });
485
487
  }
486
488
  getEffectiveBlueprint() {
487
489
  const t = this.args.blueprint;
488
- return Pe(t) ? t : {
490
+ return xe(t) ? t : {
489
491
  login: this.args.login,
490
492
  ...t || {},
491
493
  preferredVersions: {
492
- php: this.args.php ?? t?.preferredVersions?.php ?? re,
494
+ php: this.args.php ?? t?.preferredVersions?.php ?? q,
493
495
  wp: this.args.wp ?? t?.preferredVersions?.wp ?? "latest",
494
496
  ...t?.preferredVersions || {}
495
497
  }
496
498
  };
497
499
  }
498
500
  writeProgressUpdate(t, o, n) {
499
- this.args.verbosity !== j.Quiet.name && ae(t) && o !== this.lastProgressMessage && (this.lastProgressMessage = o, t.isTTY ? (t.cursorTo(0), t.write(o), t.clearLine(1), n && t.write(`
501
+ this.args.verbosity !== Z.Quiet.name && ce(t) && o !== this.lastProgressMessage && (this.lastProgressMessage = o, t.isTTY ? (t.cursorTo(0), t.write(o), t.clearLine(1), n && t.write(`
500
502
  `)) : t.write(`${o}
501
503
  `));
502
504
  }
503
505
  }
504
- async function it(e, t = !0) {
505
- const n = `${w.basename(process.argv0)}${e}${process.pid}-`, r = await Ae({
506
+ async function pt(e, t = !0) {
507
+ const n = `${h.basename(process.argv0)}${e}${process.pid}-`, r = await je({
506
508
  prefix: n,
507
509
  /*
508
510
  * Allow recursive cleanup on process exit.
@@ -514,32 +516,32 @@ async function it(e, t = !0) {
514
516
  */
515
517
  unsafeCleanup: !0
516
518
  });
517
- return t && He(), r;
519
+ return t && qe(), r;
518
520
  }
519
- async function at(e, t, o) {
520
- const r = (await lt(
521
+ async function ft(e, t, o) {
522
+ const r = (await ht(
521
523
  e,
522
524
  t,
523
525
  o
524
526
  )).map(
525
- (s) => new Promise((a) => {
526
- p.rm(s, { recursive: !0 }, (l) => {
527
+ (s) => new Promise((i) => {
528
+ f.rm(s, { recursive: !0 }, (l) => {
527
529
  l ? u.warn(
528
530
  `Failed to delete stale Playground temp dir: ${s}`,
529
531
  l
530
532
  ) : u.info(
531
533
  `Deleted stale Playground temp dir: ${s}`
532
- ), a();
534
+ ), i();
533
535
  });
534
536
  })
535
537
  );
536
538
  await Promise.all(r);
537
539
  }
538
- async function lt(e, t, o) {
540
+ async function ht(e, t, o) {
539
541
  try {
540
- const n = p.readdirSync(o).map((s) => w.join(o, s)), r = [];
542
+ const n = f.readdirSync(o).map((s) => h.join(o, s)), r = [];
541
543
  for (const s of n)
542
- await dt(
544
+ await mt(
543
545
  e,
544
546
  t,
545
547
  s
@@ -549,10 +551,10 @@ async function lt(e, t, o) {
549
551
  return u.warn(`Failed to find stale Playground temp dirs: ${n}`), [];
550
552
  }
551
553
  }
552
- async function dt(e, t, o) {
553
- if (!p.lstatSync(o).isDirectory())
554
+ async function mt(e, t, o) {
555
+ if (!f.lstatSync(o).isDirectory())
554
556
  return !1;
555
- const r = w.basename(o);
557
+ const r = h.basename(o);
556
558
  if (!r.includes(e))
557
559
  return !1;
558
560
  const s = r.match(
@@ -560,39 +562,39 @@ async function dt(e, t, o) {
560
562
  );
561
563
  if (!s)
562
564
  return !1;
563
- const a = {
565
+ const i = {
564
566
  executableName: s[1],
565
567
  pid: s[2]
566
568
  };
567
- if (await ut(a.pid, a.executableName))
569
+ if (await wt(i.pid, i.executableName))
568
570
  return !1;
569
571
  const l = Date.now() - t;
570
- return p.statSync(o).mtime.getTime() < l;
572
+ return f.statSync(o).mtime.getTime() < l;
571
573
  }
572
- async function ut(e, t) {
574
+ async function wt(e, t) {
573
575
  const [o] = await new Promise(
574
576
  (n, r) => {
575
- Ve.list(
577
+ ze.list(
576
578
  {
577
579
  pid: e,
578
580
  name: t,
579
581
  // Remove path from executable name in the results.
580
582
  clean: !0
581
583
  },
582
- (s, a) => {
583
- s ? r(s) : n(a);
584
+ (s, i) => {
585
+ s ? r(s) : n(i);
584
586
  }
585
587
  );
586
588
  }
587
589
  );
588
590
  return !!o && o.pid === e && o.command === t;
589
591
  }
590
- const j = {
591
- Quiet: { name: "quiet", severity: V.Fatal },
592
- Normal: { name: "normal", severity: V.Info },
593
- Debug: { name: "debug", severity: V.Debug }
592
+ const Z = {
593
+ Quiet: { name: "quiet", severity: N.Fatal },
594
+ Normal: { name: "normal", severity: N.Info },
595
+ Debug: { name: "debug", severity: N.Debug }
594
596
  };
595
- async function Ht(e) {
597
+ async function Gt(e) {
596
598
  try {
597
599
  const t = {
598
600
  "site-url": {
@@ -602,8 +604,8 @@ async function Ht(e) {
602
604
  php: {
603
605
  describe: "PHP version to use.",
604
606
  type: "string",
605
- default: re,
606
- choices: he
607
+ default: q,
608
+ choices: te
607
609
  },
608
610
  wp: {
609
611
  describe: "WordPress version to use.",
@@ -616,27 +618,27 @@ async function Ht(e) {
616
618
  describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",
617
619
  type: "array",
618
620
  string: !0,
619
- coerce: J
621
+ coerce: O
620
622
  },
621
623
  "mount-before-install": {
622
624
  describe: "Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",
623
625
  type: "array",
624
626
  string: !0,
625
- coerce: J
627
+ coerce: O
626
628
  },
627
629
  "mount-dir": {
628
630
  describe: 'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',
629
631
  type: "array",
630
632
  nargs: 2,
631
633
  array: !0,
632
- coerce: K
634
+ coerce: se
633
635
  },
634
636
  "mount-dir-before-install": {
635
637
  describe: 'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',
636
638
  type: "string",
637
639
  nargs: 2,
638
640
  array: !0,
639
- coerce: K
641
+ coerce: se
640
642
  },
641
643
  login: {
642
644
  describe: "Should log the user in",
@@ -683,15 +685,17 @@ async function Ht(e) {
683
685
  verbosity: {
684
686
  describe: "Output logs and progress messages.",
685
687
  type: "string",
686
- choices: Object.values(j).map(
687
- (i) => i.name
688
+ choices: Object.values(Z).map(
689
+ (a) => a.name
688
690
  ),
689
691
  default: "normal"
690
692
  },
691
693
  debug: {
692
694
  describe: "Print PHP error log content if an error occurs during Playground boot.",
693
695
  type: "boolean",
694
- default: !1
696
+ default: !1,
697
+ // Hide this deprecated option. Use verbosity=debug instead.
698
+ hidden: !0
695
699
  },
696
700
  "auto-mount": {
697
701
  describe: "Automatically mount the specified directory. If no path is provided, mount the current working directory. You can mount a WordPress directory, a plugin directory, a theme directory, a wp-content directory, or any directory containing PHP and HTML files.",
@@ -732,7 +736,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
732
736
  // supported IDEs and, if needed, will create the relevant
733
737
  // config file for each.
734
738
  choices: ["", "vscode", "phpstorm"],
735
- coerce: (i) => i === "" ? ["vscode", "phpstorm"] : [i]
739
+ coerce: (a) => a === "" ? ["vscode", "phpstorm"] : [a]
736
740
  },
737
741
  "experimental-blueprints-v2-runner": {
738
742
  describe: "Use the experimental Blueprint V2 runner.",
@@ -757,54 +761,139 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
757
761
  "experimental-multi-worker": {
758
762
  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.",
759
763
  type: "number",
760
- coerce: (i) => i ?? $e().length - 1
764
+ coerce: (a) => a ?? Me().length - 1
761
765
  },
762
766
  "experimental-devtools": {
763
767
  describe: "Enable experimental browser development tools.",
764
768
  type: "boolean"
765
769
  }
766
770
  }, n = {
771
+ path: {
772
+ describe: "Path to the project directory. Playground will auto-detect if this is a plugin, theme, wp-content, or WordPress directory.",
773
+ type: "string",
774
+ default: process.cwd()
775
+ },
776
+ php: {
777
+ describe: "PHP version to use.",
778
+ type: "string",
779
+ default: q,
780
+ choices: te
781
+ },
782
+ wp: {
783
+ describe: "WordPress version to use.",
784
+ type: "string",
785
+ default: "latest"
786
+ },
787
+ port: {
788
+ describe: "Port to listen on.",
789
+ type: "number",
790
+ default: 9400
791
+ },
792
+ blueprint: {
793
+ describe: "Path to a Blueprint JSON file to execute on startup.",
794
+ type: "string"
795
+ },
796
+ login: {
797
+ describe: "Auto-login as the admin user.",
798
+ type: "boolean",
799
+ default: !0
800
+ },
801
+ xdebug: {
802
+ describe: "Enable Xdebug for debugging.",
803
+ type: "boolean",
804
+ default: !1
805
+ },
806
+ "experimental-unsafe-ide-integration": t["experimental-unsafe-ide-integration"],
807
+ "skip-browser": {
808
+ describe: "Do not open the site in your default browser on startup.",
809
+ type: "boolean",
810
+ default: !1
811
+ },
812
+ quiet: {
813
+ describe: "Suppress non-essential output.",
814
+ type: "boolean",
815
+ default: !1
816
+ },
817
+ // Advanced options for power users who need more control
818
+ "site-url": {
819
+ describe: "Override the site URL. By default, derived from the port (http://127.0.0.1:<port>).",
820
+ type: "string"
821
+ },
822
+ mount: {
823
+ describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path. Use this for additional mounts beyond auto-detection.",
824
+ type: "array",
825
+ string: !0,
826
+ coerce: O
827
+ },
828
+ reset: {
829
+ describe: "Deletes the stored site directory and starts a new site from scratch.",
830
+ type: "boolean",
831
+ default: !1
832
+ },
833
+ "no-auto-mount": {
834
+ describe: "Disable automatic project type detection. Use --mount to manually specify mounts instead.",
835
+ type: "boolean",
836
+ default: !1
837
+ }
838
+ }, r = {
767
839
  outfile: {
768
840
  describe: "When building, write to this output file.",
769
841
  type: "string",
770
842
  default: "wordpress.zip"
771
843
  }
772
- }, r = Ce(e).usage("Usage: wp-playground <command> [options]").command(
844
+ }, s = Re(e).usage("Usage: wp-playground <command> [options]").command(
845
+ "start",
846
+ "Start a local WordPress server with automatic project detection (recommended)",
847
+ (a) => a.usage(
848
+ `Usage: wp-playground start [options]
849
+
850
+ The easiest way to run WordPress locally. Automatically detects
851
+ if your directory contains a plugin, theme, wp-content, or
852
+ WordPress installation and configures everything for you.
853
+
854
+ Examples:
855
+ wp-playground start # Start in current directory
856
+ wp-playground start --path=./my-plugin # Start with a specific path
857
+ wp-playground start --wp=6.7 --php=8.3 # Use specific versions
858
+ wp-playground start --skip-browser # Skip opening browser
859
+ wp-playground start --no-auto-mount # Disable auto-detection`
860
+ ).options(n)
861
+ ).command(
773
862
  "server",
774
- "Start a local WordPress server",
775
- (i) => i.options({
863
+ "Start a local WordPress server (advanced, low-level)",
864
+ (a) => a.options({
776
865
  ...t,
777
866
  ...o
778
867
  })
779
868
  ).command(
780
869
  "run-blueprint",
781
870
  "Execute a Blueprint without starting a server",
782
- (i) => i.options({ ...t })
871
+ (a) => a.options({ ...t })
783
872
  ).command(
784
873
  "build-snapshot",
785
874
  "Build a ZIP snapshot of a WordPress site based on a Blueprint",
786
- (i) => i.options({
875
+ (a) => a.options({
787
876
  ...t,
788
- ...n
877
+ ...r
789
878
  })
790
879
  ).demandCommand(1, "Please specify a command").strictCommands().conflicts(
791
880
  "experimental-unsafe-ide-integration",
792
881
  "experimental-devtools"
793
- ).showHelpOnFail(!1).fail((i, y, g) => {
882
+ ).showHelpOnFail(!1).fail((a, y, p) => {
794
883
  if (y)
795
884
  throw y;
796
- i && i.includes("Please specify a command") && (g.showHelp(), console.error(`
797
- ` + i), process.exit(1)), console.error(i), process.exit(1);
798
- }).strictOptions().check(async (i) => {
799
- if (i["skip-wordpress-install"] === !0 && (i["wordpress-install-mode"] = "do-not-attempt-installing", i.wordpressInstallMode = "do-not-attempt-installing"), i.wp !== void 0 && typeof i.wp == "string" && !et(i.wp))
885
+ a && a.includes("Please specify a command") && (p.showHelp(), console.error(`
886
+ ` + a), process.exit(1)), console.error(a), process.exit(1);
887
+ }).strictOptions().check(async (a) => {
888
+ if (a["skip-wordpress-install"] === !0 && (a["wordpress-install-mode"] = "do-not-attempt-installing", a.wordpressInstallMode = "do-not-attempt-installing"), a.wp !== void 0 && typeof a.wp == "string" && !it(a.wp))
800
889
  try {
801
- new URL(i.wp);
890
+ new URL(a.wp);
802
891
  } catch {
803
892
  throw new Error(
804
893
  'Unrecognized WordPress version. Please use "latest", a URL, or a numeric version such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"'
805
894
  );
806
895
  }
807
- const y = i["site-url"];
896
+ const y = a["site-url"];
808
897
  if (typeof y == "string" && y.trim() !== "")
809
898
  try {
810
899
  new URL(y);
@@ -813,82 +902,84 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
813
902
  `Invalid site-url "${y}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`
814
903
  );
815
904
  }
816
- if (i["auto-mount"]) {
817
- let g = !1;
905
+ if (a["auto-mount"]) {
906
+ let p = !1;
818
907
  try {
819
- g = p.statSync(
820
- i["auto-mount"]
908
+ p = f.statSync(
909
+ a["auto-mount"]
821
910
  ).isDirectory();
822
911
  } catch {
823
- g = !1;
912
+ p = !1;
824
913
  }
825
- if (!g)
914
+ if (!p)
826
915
  throw new Error(
827
- `The specified --auto-mount path is not a directory: '${i["auto-mount"]}'.`
916
+ `The specified --auto-mount path is not a directory: '${a["auto-mount"]}'.`
828
917
  );
829
918
  }
830
- if (i["experimental-multi-worker"] !== void 0) {
831
- if (i._[0] !== "server")
919
+ if (a["experimental-multi-worker"] !== void 0) {
920
+ if (a._[0] !== "server")
832
921
  throw new Error(
833
922
  "The --experimental-multi-worker flag is only supported when running the server command."
834
923
  );
835
- if (i["experimental-multi-worker"] !== void 0 && typeof i["experimental-multi-worker"] == "number" && i["experimental-multi-worker"] <= 1)
924
+ if (a["experimental-multi-worker"] !== void 0 && typeof a["experimental-multi-worker"] == "number" && a["experimental-multi-worker"] <= 1)
836
925
  throw new Error(
837
926
  "The --experimental-multi-worker flag must be a positive integer greater than 1."
838
927
  );
839
928
  }
840
- if (i["experimental-blueprints-v2-runner"] === !0) {
841
- if (i.mode !== void 0) {
842
- if (i["wordpress-install-mode"] !== void 0)
929
+ if (a["experimental-blueprints-v2-runner"] === !0) {
930
+ if (a.mode !== void 0) {
931
+ if (a["wordpress-install-mode"] !== void 0)
843
932
  throw new Error(
844
933
  "The --wordpress-install-mode option cannot be used with the --mode option. Use one or the other."
845
934
  );
846
- if ("skip-sqlite-setup" in i)
935
+ if ("skip-sqlite-setup" in a)
847
936
  throw new Error(
848
937
  "The --skipSqliteSetup option is not supported in Blueprint V2 mode."
849
938
  );
850
- if (i["auto-mount"] !== void 0)
939
+ if (a["auto-mount"] !== void 0)
851
940
  throw new Error(
852
941
  "The --mode option cannot be used with --auto-mount because --auto-mount automatically sets the mode."
853
942
  );
854
943
  } else
855
- i["wordpress-install-mode"] === "do-not-attempt-installing" ? i.mode = "apply-to-existing-site" : i.mode = "create-new-site";
856
- const g = i.allow || [];
857
- i.followSymlinks === !0 && g.push("follow-symlinks"), i["blueprint-may-read-adjacent-files"] === !0 && g.push("read-local-fs"), i.allow = g;
858
- } else if (i.mode !== void 0)
944
+ a["wordpress-install-mode"] === "do-not-attempt-installing" ? a.mode = "apply-to-existing-site" : a.mode = "create-new-site";
945
+ const p = a.allow || [];
946
+ a.followSymlinks === !0 && p.push("follow-symlinks"), a["blueprint-may-read-adjacent-files"] === !0 && p.push("read-local-fs"), a.allow = p;
947
+ } else if (a.mode !== void 0)
859
948
  throw new Error(
860
949
  "The --mode option requires the --experimentalBlueprintsV2Runner flag."
861
950
  );
862
951
  return !0;
863
952
  });
864
- r.wrap(r.terminalWidth());
865
- const s = await r.argv, a = s._[0];
866
- ["run-blueprint", "server", "build-snapshot"].includes(a) || (r.showHelp(), process.exit(1));
867
- const l = {
868
- ...s,
869
- command: a,
953
+ s.wrap(s.terminalWidth());
954
+ const i = await s.argv, l = i._[0];
955
+ ["start", "run-blueprint", "server", "build-snapshot"].includes(
956
+ l
957
+ ) || (s.showHelp(), process.exit(1));
958
+ const d = {
959
+ ...i,
960
+ command: l,
870
961
  mount: [
871
- ...s.mount || [],
872
- ...s["mount-dir"] || []
962
+ ...i.mount || [],
963
+ ...i["mount-dir"] || []
873
964
  ],
874
965
  "mount-before-install": [
875
- ...s["mount-before-install"] || [],
876
- ...s["mount-dir-before-install"] || []
966
+ ...i["mount-before-install"] || [],
967
+ ...i["mount-dir-before-install"] || []
877
968
  ]
878
- }, d = await ft(l);
879
- d === void 0 && process.exit(0);
880
- const f = /* @__PURE__ */ (() => {
881
- let i;
969
+ }, b = await Pt(d);
970
+ b === void 0 && process.exit(0);
971
+ const g = /* @__PURE__ */ (() => {
972
+ let a;
882
973
  return async () => {
883
- i !== void 0 && (i = d[Symbol.asyncDispose]()), await i, process.exit(0);
974
+ a !== void 0 && (a = b[Symbol.asyncDispose]()), await a, process.exit(0);
884
975
  };
885
976
  })();
886
- process.on("SIGINT", f), process.on("SIGTERM", f);
977
+ process.on("SIGINT", g), process.on("SIGTERM", g);
887
978
  } catch (t) {
888
- if (!(t instanceof Error))
979
+ if (console.error(t), !(t instanceof Error))
889
980
  throw t;
890
981
  if (process.argv.includes("--debug"))
891
- me(t);
982
+ ye(t);
892
983
  else {
893
984
  const n = [];
894
985
  let r = t;
@@ -902,53 +993,59 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
902
993
  process.exit(1);
903
994
  }
904
995
  }
905
- const ct = Symbol("playground-cli-testing"), E = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, pt = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, N = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, te = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
906
- async function ft(e) {
996
+ function ie(e, t) {
997
+ return e.find(
998
+ (o) => o.vfsPath.replace(/\/$/, "") === t.replace(/\/$/, "")
999
+ );
1000
+ }
1001
+ const gt = Symbol("playground-cli-testing"), E = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, yt = (e) => process.stdout.isTTY ? "\x1B[31m" + e + "\x1B[0m" : e, bt = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, _ = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, ae = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
1002
+ async function Pt(e) {
907
1003
  let t, o;
908
1004
  const n = /* @__PURE__ */ new Map();
909
- if (e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = qe(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) {
910
- const f = Object.values(j).find(
911
- (i) => i.name === e.verbosity
1005
+ if (e.command === "start" && (e = vt(e)), e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = ue(e)), e.wordpressInstallMode === void 0 && (e.wordpressInstallMode = "download-and-install"), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug && (e.verbosity = "debug", delete e.debug), e.verbosity) {
1006
+ const g = Object.values(Z).find(
1007
+ (a) => a.name === e.verbosity
912
1008
  ).severity;
913
- u.setSeverityFilterLevel(f);
1009
+ u.setSeverityFilterLevel(g);
914
1010
  }
915
1011
  e.intl || (e.intl = !0);
916
- const r = e.command === "server" ? e.port ?? 9400 : 0, s = ie.platform() === "win32" ? (
1012
+ const r = e.command === "server" ? e.port ?? 9400 : 0, s = U.platform() === "win32" ? (
917
1013
  // @TODO: Enable fs-ext here when it works with Windows.
918
1014
  void 0
919
- ) : await import("fs-ext").then((f) => f.flockSync).catch(() => {
1015
+ ) : await import("fs-ext").then((g) => g.flockSync).catch(() => {
920
1016
  u.warn(
921
1017
  "The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking."
922
1018
  );
923
- }), a = new Ie(s);
1019
+ }), i = new We(s);
924
1020
  let l = !1, d = !0;
925
- return u.log("Starting a PHP server..."), Ge({
1021
+ u.log("Starting a PHP server...");
1022
+ const b = await ot({
926
1023
  port: r,
927
- onBind: async (f, i) => {
928
- const y = "127.0.0.1", g = `http://${y}:${i}`, P = e["site-url"] || g, k = e.command === "server" ? e.experimentalMultiWorker ?? 1 : 1, I = e.command === "server" ? (
1024
+ onBind: async (g, a) => {
1025
+ const y = "127.0.0.1", p = `http://${y}:${a}`, I = e["site-url"] || p, v = e.command === "server" ? e.experimentalMultiWorker ?? 1 : 1, W = e.command === "server" ? (
929
1026
  // Account for the initial worker which is discarded by the server after setup.
930
- k + 1
931
- ) : k, F = 2 ** 31 - 1, x = Math.floor(
932
- F / I
933
- ), W = "-playground-cli-site-", T = await it(W);
934
- u.debug(`Native temp dir for VFS root: ${T.path}`);
935
- const B = "WP Playground CLI - Listen for Xdebug", z = ".playground-xdebug-root", X = w.join(process.cwd(), z);
936
- if (await Ne(X), e.xdebug && e.experimentalUnsafeIdeIntegration) {
937
- await _e(
938
- T.path,
939
- X,
1027
+ v + 1
1028
+ ) : v, F = 2 ** 31 - 1, k = Math.floor(
1029
+ F / W
1030
+ ), J = "-playground-cli-site-", $ = await pt(J);
1031
+ u.debug(`Native temp dir for VFS root: ${$.path}`);
1032
+ const B = "WP Playground CLI - Listen for Xdebug", Q = ".playground-xdebug-root", K = h.join(process.cwd(), Q);
1033
+ if (await Xe(K), e.xdebug && e.experimentalUnsafeIdeIntegration) {
1034
+ await Ye(
1035
+ $.path,
1036
+ K,
940
1037
  process.platform
941
1038
  );
942
1039
  const c = {
943
- hostPath: w.join(".", w.sep, z),
1040
+ hostPath: h.join(".", h.sep, Q),
944
1041
  vfsPath: "/"
945
1042
  };
946
1043
  try {
947
- await Oe(B, process.cwd());
948
- const m = typeof e.xdebug == "object" ? e.xdebug : void 0, v = await je({
1044
+ await Ze(B, process.cwd());
1045
+ const w = typeof e.xdebug == "object" ? e.xdebug : void 0, x = await Ge({
949
1046
  name: B,
950
1047
  host: y,
951
- port: i,
1048
+ port: a,
952
1049
  ides: e.experimentalUnsafeIdeIntegration,
953
1050
  cwd: process.cwd(),
954
1051
  mounts: [
@@ -956,19 +1053,19 @@ async function ft(e) {
956
1053
  ...e["mount-before-install"] || [],
957
1054
  ...e.mount || []
958
1055
  ],
959
- ideKey: m?.ideKey
960
- }), h = e.experimentalUnsafeIdeIntegration, b = h.includes("vscode"), S = h.includes("phpstorm"), M = Object.values(v);
961
- console.log(""), M.length > 0 ? (console.log(E("Xdebug configured successfully")), console.log(
962
- te("Updated IDE config: ") + M.join(" ")
1056
+ ideKey: w?.ideKey
1057
+ }), m = e.experimentalUnsafeIdeIntegration, P = m.includes("vscode"), S = m.includes("phpstorm"), L = Object.values(x);
1058
+ console.log(""), L.length > 0 ? (console.log(E("Xdebug configured successfully")), console.log(
1059
+ ae("Updated IDE config: ") + L.join(" ")
963
1060
  ), console.log(
964
- te("Playground source root: ") + ".playground-xdebug-root" + N(
965
- pt(
1061
+ ae("Playground source root: ") + ".playground-xdebug-root" + _(
1062
+ bt(
966
1063
  " – you can set breakpoints and preview Playground's VFS structure in there."
967
1064
  )
968
1065
  )
969
1066
  )) : (console.log(E("Xdebug configuration failed.")), console.log(
970
1067
  "No IDE-specific project settings directory was found in the current working directory."
971
- )), console.log(""), b && v.vscode && (console.log(E("VS Code / Cursor instructions:")), console.log(
1068
+ )), console.log(""), P && x.vscode && (console.log(E("VS Code / Cursor instructions:")), console.log(
972
1069
  " 1. Ensure you have installed an IDE extension for PHP Debugging"
973
1070
  ), console.log(
974
1071
  ` (The ${E("PHP Debug")} extension by ${E(
@@ -977,15 +1074,15 @@ async function ft(e) {
977
1074
  ), console.log(
978
1075
  " 2. Open the Run and Debug panel on the left sidebar"
979
1076
  ), console.log(
980
- ` 3. Select "${N(
1077
+ ` 3. Select "${_(
981
1078
  B
982
1079
  )}" from the dropdown`
983
1080
  ), console.log(' 3. Click "start debugging"'), console.log(
984
1081
  " 5. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
985
1082
  ), console.log(
986
1083
  " 6. Visit Playground in your browser to hit the breakpoint"
987
- ), S && console.log("")), S && v.phpstorm && (console.log(E("PhpStorm instructions:")), console.log(
988
- ` 1. Choose "${N(
1084
+ ), S && console.log("")), S && x.phpstorm && (console.log(E("PhpStorm instructions:")), console.log(
1085
+ ` 1. Choose "${_(
989
1086
  B
990
1087
  )}" debug configuration in the toolbar`
991
1088
  ), console.log(" 2. Click the debug button (bug icon)`"), console.log(
@@ -993,21 +1090,21 @@ async function ft(e) {
993
1090
  ), console.log(
994
1091
  " 4. Visit Playground in your browser to hit the breakpoint"
995
1092
  )), console.log("");
996
- } catch (m) {
1093
+ } catch (w) {
997
1094
  throw new Error("Could not configure Xdebug", {
998
- cause: m
1095
+ cause: w
999
1096
  });
1000
1097
  }
1001
1098
  }
1002
- const ue = w.dirname(T.path), ce = 2 * 24 * 60 * 60 * 1e3;
1003
- at(
1004
- W,
1005
- ce,
1006
- ue
1099
+ const he = h.dirname($.path), me = 2 * 24 * 60 * 60 * 1e3;
1100
+ ft(
1101
+ J,
1102
+ me,
1103
+ he
1007
1104
  );
1008
- const U = w.join(T.path, "internal");
1009
- G(U);
1010
- const pe = [
1105
+ const A = h.join($.path, "internal");
1106
+ z(A);
1107
+ const we = [
1011
1108
  "wordpress",
1012
1109
  // Note: These dirs are from Emscripten's "default dirs" list:
1013
1110
  // https://github.com/emscripten-core/emscripten/blob/f431ec220e472e1f8d3db6b52fe23fb377facf30/src/lib/libfs.js#L1400-L1402
@@ -1018,16 +1115,16 @@ async function ft(e) {
1018
1115
  "tmp",
1019
1116
  "home"
1020
1117
  ];
1021
- for (const c of pe) {
1022
- const m = (h) => h.vfsPath === `/${c}`;
1023
- if (!(e["mount-before-install"]?.some(m) || e.mount?.some(m))) {
1024
- const h = w.join(
1025
- T.path,
1118
+ for (const c of we) {
1119
+ const w = (m) => m.vfsPath === `/${c}`;
1120
+ if (!(e["mount-before-install"]?.some(w) || e.mount?.some(w))) {
1121
+ const m = h.join(
1122
+ $.path,
1026
1123
  c
1027
1124
  );
1028
- G(h), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1125
+ z(m), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1029
1126
  vfsPath: `/${c}`,
1030
- hostPath: h
1127
+ hostPath: m
1031
1128
  });
1032
1129
  }
1033
1130
  }
@@ -1041,164 +1138,220 @@ async function ft(e) {
1041
1138
  u.debug(
1042
1139
  `Mount after WP install: ${c.vfsPath} -> ${c.hostPath}`
1043
1140
  );
1044
- let $;
1045
- e["experimental-blueprints-v2-runner"] ? $ = new ot(e, {
1046
- siteUrl: P,
1047
- processIdSpaceLength: x
1048
- }) : ($ = new nt(e, {
1049
- siteUrl: P,
1050
- processIdSpaceLength: x
1051
- }), typeof e.blueprint == "string" && (e.blueprint = await tt({
1141
+ let T;
1142
+ e["experimental-blueprints-v2-runner"] ? T = new lt(e, {
1143
+ siteUrl: I,
1144
+ processIdSpaceLength: k
1145
+ }) : (T = new ct(e, {
1146
+ siteUrl: I,
1147
+ processIdSpaceLength: k
1148
+ }), typeof e.blueprint == "string" && (e.blueprint = await at({
1052
1149
  sourceString: e.blueprint,
1053
1150
  blueprintMayReadAdjacentFiles: e["blueprint-may-read-adjacent-files"] === !0
1054
1151
  })));
1055
- let A = !1;
1056
- const L = async function() {
1057
- A || (A = !0, await Promise.all(
1152
+ let H = !1;
1153
+ const M = async function() {
1154
+ H || (H = !0, await Promise.all(
1058
1155
  [...n].map(
1059
- async ([m, v]) => {
1060
- await v.dispose(), await m.terminate();
1156
+ async ([w, x]) => {
1157
+ await x.dispose(), await w.terminate();
1061
1158
  }
1062
1159
  )
1063
- ), f && await new Promise((m) => f.close(m)), await T.cleanup());
1064
- }, fe = ht(
1065
- I,
1066
- $.getWorkerType(),
1067
- ({ exitCode: c, workerIndex: m }) => {
1068
- A || c === 0 && u.error(
1069
- `Worker ${m} exited with code ${c}
1160
+ ), g && await new Promise((w) => g.close(w)), await $.cleanup());
1161
+ }, ge = kt(
1162
+ W,
1163
+ T.getWorkerType(),
1164
+ ({ exitCode: c, workerIndex: w }) => {
1165
+ H || c === 0 && u.error(
1166
+ `Worker ${w} exited with code ${c}
1070
1167
  `
1071
1168
  );
1072
1169
  }
1073
1170
  );
1074
1171
  u.log("Starting up workers");
1075
1172
  try {
1076
- const c = await fe, m = await oe(a);
1173
+ const c = await ge, w = await le(i);
1077
1174
  {
1078
- const h = c.shift(), b = await $.bootAndSetUpInitialPlayground(
1079
- h.phpPort,
1080
- m,
1081
- U
1175
+ const m = c.shift(), P = await T.bootAndSetUpInitialPlayground(
1176
+ m.phpPort,
1177
+ w,
1178
+ A
1082
1179
  );
1083
1180
  if (n.set(
1084
- h.worker,
1085
- b
1086
- ), await b.isReady(), l = !0, u.log("Booted!"), t = new Ke(b), !e["experimental-blueprints-v2-runner"]) {
1087
- const S = await $.compileInputBlueprint(
1181
+ m.worker,
1182
+ P
1183
+ ), await P.isReady(), l = !0, u.log("Booted!"), t = new nt(P), !e["experimental-blueprints-v2-runner"]) {
1184
+ const S = await T.compileInputBlueprint(
1088
1185
  e["additional-blueprint-steps"] || []
1089
1186
  );
1090
- S && (u.log("Running the Blueprint..."), await ve(
1187
+ S && (u.log("Running the Blueprint..."), await Se(
1091
1188
  S,
1092
- b
1189
+ P
1093
1190
  ), u.log("Finished running the blueprint"));
1094
1191
  }
1095
1192
  if (e.command === "build-snapshot") {
1096
- await wt(o, e.outfile), u.log(`WordPress exported to ${e.outfile}`), await L();
1193
+ await It(o, e.outfile), u.log(`WordPress exported to ${e.outfile}`), await M();
1097
1194
  return;
1098
1195
  } else if (e.command === "run-blueprint") {
1099
- u.log("Blueprint executed"), await L();
1196
+ u.log("Blueprint executed"), await M();
1100
1197
  return;
1101
1198
  }
1102
- await t.removeWorker(b), await b.dispose(), await h.worker.terminate(), n.delete(h.worker);
1199
+ await t.removeWorker(P), await P.dispose(), await m.worker.terminate(), n.delete(m.worker);
1103
1200
  }
1104
1201
  u.log("Preparing workers...");
1105
- const v = x;
1202
+ const x = k;
1106
1203
  return [o] = await Promise.all(
1107
- c.map(async (h, b) => {
1108
- const S = v + b * x, M = await oe(a), H = await $.bootPlayground({
1109
- worker: h,
1110
- fileLockManagerPort: M,
1204
+ c.map(async (m, P) => {
1205
+ const S = x + P * k, L = await le(i), V = await T.bootPlayground({
1206
+ worker: m,
1207
+ fileLockManagerPort: L,
1111
1208
  firstProcessId: S,
1112
- nativeInternalDirPath: U
1209
+ nativeInternalDirPath: A
1113
1210
  });
1114
1211
  return n.set(
1115
- h.worker,
1116
- H
1117
- ), t.addWorker(H), H;
1212
+ m.worker,
1213
+ V
1214
+ ), t.addWorker(V), V;
1118
1215
  })
1119
1216
  ), u.log(
1120
- `WordPress is running on ${g} with ${k} worker(s)`
1121
- ), e.xdebug && e.experimentalDevtools && (await Ue({
1217
+ `WordPress is running on ${p} with ${v} worker(s)`
1218
+ ), e.xdebug && e.experimentalDevtools && (await Oe({
1122
1219
  phpInstance: o,
1123
1220
  phpRoot: "/wordpress"
1124
1221
  })).start(), {
1125
1222
  playground: o,
1126
- server: f,
1127
- serverUrl: g,
1128
- [Symbol.asyncDispose]: L,
1129
- [ct]: {
1130
- workerThreadCount: k,
1131
- getWorkerNumberFromProcessId: (h) => Math.floor(h / x)
1223
+ server: g,
1224
+ serverUrl: p,
1225
+ [Symbol.asyncDispose]: M,
1226
+ [gt]: {
1227
+ workerThreadCount: v,
1228
+ getWorkerNumberFromProcessId: (m) => Math.floor(m / k)
1132
1229
  }
1133
1230
  };
1134
1231
  } catch (c) {
1135
- if (!e.debug)
1232
+ if (e.verbosity !== "debug")
1136
1233
  throw c;
1137
- let m = "";
1138
- throw await o?.fileExists(Z) && (m = await o.readFileAsText(Z)), await L(), new Error(m, { cause: c });
1234
+ let w = "";
1235
+ throw await o?.fileExists(ee) && (w = await o.readFileAsText(ee)), await M(), new Error(w, { cause: c });
1139
1236
  }
1140
1237
  },
1141
- async handleRequest(f) {
1238
+ async handleRequest(g) {
1142
1239
  if (!l)
1143
- return _.forHttpCode(
1240
+ return j.forHttpCode(
1144
1241
  502,
1145
1242
  "WordPress is not ready yet"
1146
1243
  );
1147
1244
  if (d) {
1148
1245
  d = !1;
1149
- const i = {
1246
+ const a = {
1150
1247
  "Content-Type": ["text/plain"],
1151
1248
  "Content-Length": ["0"],
1152
- Location: [f.url]
1249
+ Location: [g.url]
1153
1250
  };
1154
- return f.headers?.cookie?.includes(
1251
+ return g.headers?.cookie?.includes(
1155
1252
  "playground_auto_login_already_happened"
1156
- ) && (i["Set-Cookie"] = [
1253
+ ) && (a["Set-Cookie"] = [
1157
1254
  "playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"
1158
- ]), new _(302, i, new Uint8Array());
1255
+ ]), new j(302, a, new Uint8Array());
1159
1256
  }
1160
- return await t.handleRequest(f);
1257
+ return await t.handleRequest(g);
1161
1258
  }
1162
1259
  });
1260
+ return b && e.command === "start" && !e.skipBrowser && St(b.serverUrl), b;
1163
1261
  }
1164
- async function ht(e, t, o) {
1262
+ function vt(e) {
1263
+ let t = { ...e, command: "server" };
1264
+ e.noAutoMount || (t.autoMount = h.resolve(process.cwd(), t.path ?? ""), t = ue(t), delete t.autoMount);
1265
+ const o = ie(
1266
+ t["mount-before-install"] || [],
1267
+ "/wordpress"
1268
+ ) || ie(t.mount || [], "/wordpress");
1269
+ if (o)
1270
+ console.log("Site files stored at:", o?.hostPath), e.reset && (console.log(""), console.log(
1271
+ yt(
1272
+ "This site is not managed by Playground CLI and cannot be reset."
1273
+ )
1274
+ ), console.log(
1275
+ "(It's not stored in the ~/.wordpress-playground/sites/<site-id> directory.)"
1276
+ ), console.log(""), console.log(
1277
+ "You may still remove the site's directory manually if you wish."
1278
+ ), process.exit(1));
1279
+ else {
1280
+ const n = t.autoMount || process.cwd(), r = Je("sha256").update(n).digest("hex"), s = U.homedir(), i = h.join(
1281
+ s,
1282
+ ".wordpress-playground/sites",
1283
+ r
1284
+ );
1285
+ console.log("Site files stored at:", i), Y(i) && e.reset && (console.log("Resetting site..."), $e(i, { recursive: !0 })), z(i, { recursive: !0 }), t["mount-before-install"] = [
1286
+ ...t["mount-before-install"] || [],
1287
+ { vfsPath: "/wordpress", hostPath: i }
1288
+ ], t.wordpressInstallMode = Te(i).length === 0 ? (
1289
+ // Only download WordPress on the first run when the site directory is still
1290
+ // empty.
1291
+ "download-and-install"
1292
+ ) : (
1293
+ // After that, reuse the WordPress installation from the initial run.
1294
+ "install-from-existing-files-if-needed"
1295
+ );
1296
+ }
1297
+ return t;
1298
+ }
1299
+ async function kt(e, t, o) {
1165
1300
  const n = [];
1166
1301
  for (let r = 0; r < e; r++) {
1167
- const a = mt(t, { onExit: (l) => {
1302
+ const i = xt(t, { onExit: (l) => {
1168
1303
  o({
1169
1304
  exitCode: l,
1170
1305
  workerIndex: r
1171
1306
  });
1172
1307
  } });
1173
- n.push(a);
1308
+ n.push(i);
1174
1309
  }
1175
1310
  return Promise.all(n);
1176
1311
  }
1177
- function mt(e, { onExit: t } = {}) {
1312
+ function xt(e, { onExit: t } = {}) {
1178
1313
  let o;
1179
- return e === "v1" ? o = new Q(new URL("./worker-thread-v1.js", import.meta.url)) : o = new Q(new URL("./worker-thread-v2.js", import.meta.url)), new Promise((n, r) => {
1180
- o.once("message", function(a) {
1181
- a.command === "worker-script-initialized" && n({ worker: o, phpPort: a.phpPort });
1182
- }), o.once("error", function(a) {
1183
- console.error(a);
1314
+ return e === "v1" ? o = new re(new URL("./worker-thread-v1.js", import.meta.url)) : o = new re(new URL("./worker-thread-v2.js", import.meta.url)), new Promise((n, r) => {
1315
+ o.once("message", function(i) {
1316
+ i.command === "worker-script-initialized" && n({ worker: o, phpPort: i.phpPort });
1317
+ }), o.once("error", function(i) {
1318
+ console.error(i);
1184
1319
  const l = new Error(
1185
- `Worker failed to load worker. ${a.message ? `Original error: ${a.message}` : ""}`
1320
+ `Worker failed to load worker. ${i.message ? `Original error: ${i.message}` : ""}`
1186
1321
  );
1187
1322
  r(l);
1188
1323
  });
1189
1324
  let s = !1;
1190
1325
  o.once("spawn", () => {
1191
1326
  s = !0;
1192
- }), o.once("exit", (a) => {
1193
- s || r(new Error(`Worker exited before spawning: ${a}`)), t?.(a);
1327
+ }), o.once("exit", (i) => {
1328
+ s || r(new Error(`Worker exited before spawning: ${i}`)), t?.(i);
1194
1329
  });
1195
1330
  });
1196
1331
  }
1197
- async function oe(e) {
1198
- const { port1: t, port2: o } = new xe();
1199
- return await Ee() ? we(e, null, t) : await ge(e, t), o;
1332
+ async function le(e) {
1333
+ const { port1: t, port2: o } = new Ee();
1334
+ return await Le() ? be(e, null, t) : await Pe(e, t), o;
1200
1335
  }
1201
- async function wt(e, t) {
1336
+ function St(e) {
1337
+ const t = U.platform();
1338
+ let o;
1339
+ switch (t) {
1340
+ case "darwin":
1341
+ o = `open "${e}"`;
1342
+ break;
1343
+ case "win32":
1344
+ o = `start "" "${e}"`;
1345
+ break;
1346
+ default:
1347
+ o = `xdg-open "${e}"`;
1348
+ break;
1349
+ }
1350
+ _e(o, (n) => {
1351
+ n && u.debug(`Could not open browser: ${n.message}`);
1352
+ });
1353
+ }
1354
+ async function It(e, t) {
1202
1355
  await e.run({
1203
1356
  code: `<?php
1204
1357
  $zip = new ZipArchive();
@@ -1220,15 +1373,15 @@ async function wt(e, t) {
1220
1373
  `
1221
1374
  });
1222
1375
  const o = await e.readFileAsBuffer("/tmp/build.zip");
1223
- p.writeFileSync(t, o);
1376
+ f.writeFileSync(t, o);
1224
1377
  }
1225
1378
  export {
1226
- j as L,
1227
- ae as a,
1228
- ct as i,
1229
- At as m,
1230
- Ht as p,
1231
- ft as r,
1232
- mt as s
1379
+ Z as L,
1380
+ ce as a,
1381
+ gt as i,
1382
+ Zt as m,
1383
+ Gt as p,
1384
+ Pt as r,
1385
+ xt as s
1233
1386
  };
1234
- //# sourceMappingURL=run-cli-pLJHMn5d.js.map
1387
+ //# sourceMappingURL=run-cli-vem_UKTF.js.map