sdc-build-wp 5.5.2 → 5.6.0

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,7 +1,6 @@
1
- import { fileURLToPath } from 'url';
2
1
  import BaseComponent from './base.js';
3
- import { stat, readFile } from 'fs/promises';
4
- import { exec } from 'child_process';
2
+ import { access, stat, readFile } from 'fs/promises';
3
+ import { execFile } from 'child_process';
5
4
  import { promisify } from 'util';
6
5
  import { createHash } from 'crypto';
7
6
 
@@ -10,6 +9,31 @@ export default class BlocksComponent extends BaseComponent {
10
9
  constructor() {
11
10
  super();
12
11
  this.description = `Process the theme's WordPress blocks`;
12
+ this._didLogWpScriptsFallback = false;
13
+ }
14
+
15
+ async getWpScriptsRunner() {
16
+ const localWpScripts = `${this.project.path}/node_modules/@wordpress/scripts/bin/wp-scripts.js`;
17
+
18
+ try {
19
+ await access(localWpScripts);
20
+ return {
21
+ command: process.execPath,
22
+ baseArgs: [localWpScripts]
23
+ };
24
+ } catch {
25
+ if (!this._didLogWpScriptsFallback) {
26
+ this.log('info', 'Using temporary @wordpress/scripts via npx for block builds');
27
+ this._didLogWpScriptsFallback = true;
28
+ }
29
+
30
+ const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';
31
+
32
+ return {
33
+ command: npxCommand,
34
+ baseArgs: ['--yes', '--package', '@wordpress/scripts@31', 'wp-scripts']
35
+ };
36
+ }
13
37
  }
14
38
 
15
39
  async init() {
@@ -132,17 +156,17 @@ export default class BlocksComponent extends BaseComponent {
132
156
  this.clearHashCache([workingBlockJson, ...dependencies]);
133
157
 
134
158
  try {
135
- const cmds = [
136
- `${this.project.path}/node_modules/@wordpress/scripts/bin/wp-scripts.js`,
137
- `build`,
159
+ const runner = await this.getWpScriptsRunner();
160
+ const args = [
161
+ ...runner.baseArgs,
162
+ 'build',
138
163
  `--source-path=.${entry.replace(this.project.path, '')}/src`,
139
164
  `--output-path=.${entry.replace(this.project.path, '')}/build`,
140
- `--webpack-copy-php`,
141
- `--config=${this.path.resolve(this.path.dirname(fileURLToPath(import.meta.url)), '../../webpack.config.js')}`,
165
+ '--webpack-copy-php'
142
166
  ];
143
- const execPromise = promisify(exec);
167
+ const execFilePromise = promisify(execFile);
144
168
  const timeoutMS = 40000;
145
- const buildPromise = execPromise(cmds.join(' '), {
169
+ const buildPromise = execFilePromise(runner.command, args, {
146
170
  maxBuffer: 1024 * 1024 * 10,
147
171
  cwd: this.project.path
148
172
  });
@@ -5,23 +5,22 @@ let socket = window.___browserSync___?.socket;
5
5
  let checkedForPort = false;
6
6
 
7
7
  function redirectAdminFromPort() {
8
- if (!checkedForPort && window.location.port) {
9
- const url = new URL(window.location.href);
10
- const urlParams = new URLSearchParams(window.location.search);
11
- if (urlParams.has('keepPort')) {
12
- checkedForPort = true;
13
- return;
14
- }
15
- url.port = '';
16
- socket.emit('sdc:redirectAdminFromPort', {
17
- timestamp: Date.now(),
18
- port: window.location.port,
19
- from: window.location.href,
20
- to: url.toString()
21
- });
22
- window.location.replace(url.toString());
23
- }
24
8
  checkedForPort = true;
9
+ if (!window.location.port) { return; }
10
+ const url = new URL(window.location.href);
11
+ const isAdmin = /^\/wp-admin(?:\/|$)/.test(url.pathname);
12
+ const urlParams = new URLSearchParams(url.search);
13
+ if (!isAdmin || urlParams.has('keepPort')) {
14
+ return;
15
+ }
16
+ url.port = '';
17
+ socket.emit('sdc:redirectAdminFromPort', {
18
+ timestamp: Date.now(),
19
+ port: window.location.port,
20
+ from: window.location.href,
21
+ to: url.toString()
22
+ });
23
+ window.location.replace(url.toString());
25
24
  }
26
25
 
27
26
  function getScriptsOnPage() {
@@ -36,7 +35,7 @@ function getScriptsOnPage() {
36
35
  const scriptsOnPageInterval = setInterval(() => {
37
36
  socket = window.___browserSync___?.socket;
38
37
  if (socket) {
39
- redirectAdminFromPort();
38
+ if (!checkedForPort) { redirectAdminFromPort(); }
40
39
  getScriptsOnPage();
41
40
  clearInterval(scriptsOnPageInterval);
42
41
  }
package/lib/project.js CHANGED
@@ -252,6 +252,10 @@ export function keypressListen() {
252
252
  if (isPrompting) { return; }
253
253
  switch (key) {
254
254
  case '\r': // [Enter]/[Return]
255
+ if (tui.isInitialized && !tui.isMouseEnabled) {
256
+ tui.enableMouseCapture();
257
+ break;
258
+ }
255
259
  log(null, '');
256
260
  break;
257
261
  case '\u0003': // [Ctrl]+C
package/lib/tui.js CHANGED
@@ -1,12 +1,95 @@
1
- import blessed from 'blessed';
1
+ import React from 'react';
2
+ import { Box, Text, render as renderInk, useInput, useStdout } from 'ink';
2
3
  import { styleText } from 'node:util';
3
4
  import log from './logging.js';
4
5
 
6
+ const sgrMouseRegex = /\x1b\[<(\d+);(\d+);(\d+)([mM])/g;
7
+
8
+ function TUIRoot({ tui }) {
9
+ const { stdout } = useStdout();
10
+ const terminalRows = stdout?.rows || 24;
11
+ const headerLines = tui.getHeaderLines();
12
+ const promptLines = tui.getPromptRenderLines();
13
+ const availableLogRows = Math.max(3, terminalRows - headerLines.length - promptLines.length - 6);
14
+ const visibleLogs = tui.getVisibleLogLines(availableLogRows);
15
+
16
+ useInput((input, key) => {
17
+ if (!tui.isInitialized) {
18
+ return;
19
+ }
20
+
21
+ if (tui.isMouseEscapeSequence(input)) {
22
+ return;
23
+ }
24
+
25
+ if (tui.hasPrompt()) {
26
+ tui.handlePromptInput(input, key);
27
+ return;
28
+ }
29
+
30
+ if (key.upArrow) {
31
+ tui.scrollLogs(1);
32
+ return;
33
+ }
34
+
35
+ if (key.downArrow) {
36
+ tui.scrollLogs(-1);
37
+ return;
38
+ }
39
+
40
+ if (key.pageUp) {
41
+ tui.scrollLogs(availableLogRows);
42
+ return;
43
+ }
44
+
45
+ if (key.pageDown) {
46
+ tui.scrollLogs(-availableLogRows);
47
+ }
48
+ });
49
+
50
+ return React.createElement(
51
+ Box,
52
+ { flexDirection: 'column' },
53
+ React.createElement(
54
+ Box,
55
+ {
56
+ borderStyle: 'round',
57
+ borderColor: 'blue',
58
+ paddingX: 1,
59
+ flexDirection: 'column'
60
+ },
61
+ headerLines.map((line, index) => React.createElement(Text, { key: `header-${index}` }, line))
62
+ ),
63
+ React.createElement(
64
+ Box,
65
+ {
66
+ borderStyle: 'single',
67
+ borderColor: 'blue',
68
+ paddingX: 1,
69
+ flexDirection: 'column',
70
+ height: availableLogRows + 2
71
+ },
72
+ visibleLogs.map((line, index) => React.createElement(Text, { key: `log-${index}` }, line))
73
+ ),
74
+ tui.hasPrompt()
75
+ ? React.createElement(
76
+ Box,
77
+ {
78
+ borderStyle: 'round',
79
+ borderColor: 'cyan',
80
+ paddingX: 1,
81
+ marginTop: 1,
82
+ flexDirection: 'column'
83
+ },
84
+ tui.getPromptRenderLines().map((line, index) => React.createElement(Text, { key: `prompt-${index}` }, line))
85
+ )
86
+ : null
87
+ );
88
+ }
89
+
5
90
  class TUI {
6
91
  constructor() {
7
- this.screen = null;
8
- this.headerBox = null;
9
- this.logBox = null;
92
+ this.app = null;
10
93
  this.isInitialized = false;
11
94
  this.urls = {
12
95
  local: '',
@@ -18,141 +101,95 @@ class TUI {
18
101
  this.isPaused = false;
19
102
  this.isMouseEnabled = true;
20
103
  this._logHistory = [];
104
+ this._logScrollOffset = 0;
105
+ this._activePrompt = null;
106
+ this._mouseDataHandler = null;
21
107
  }
22
108
 
23
109
  init() {
24
110
  if (this.isInitialized) {
25
- // If already initialized, redraw the header to reflect current state
26
- this.updateHeader();
27
111
  this.render();
28
112
  return;
29
113
  }
30
114
 
31
- if (process.stdout.isTTY) {
32
- process.stdout.write('\x1b[?25h');
33
- process.stdout.write('\x1b[0m');
34
- }
35
-
36
- this.screen = blessed.screen({
37
- smartCSR: true,
38
- fullUnicode: true,
39
- title: 'SDC Build WP',
40
- input: process.stdin,
41
- output: process.stdout
115
+ this.isInitialized = true;
116
+ this.app = renderInk(React.createElement(TUIRoot, { tui: this }), {
117
+ exitOnCtrlC: false,
118
+ stdin: process.stdin,
119
+ stdout: process.stdout,
120
+ patchConsole: false
42
121
  });
43
122
 
44
- this.headerBox = blessed.box({
45
- top: 0,
46
- left: 0,
47
- width: '100%',
48
- height: 5,
49
- content: '',
50
- tags: true,
51
- style: {
52
- fg: 'white',
53
- bg: 'black',
54
- border: {
55
- fg: 'blue'
56
- }
57
- },
58
- border: {
59
- type: 'line',
60
- bottom: true
61
- },
62
- shrink: false,
63
- scrollable: false
64
- });
123
+ this.setMouseCaptureEnabled(this.isMouseEnabled);
124
+ this.attachMouseHandler();
65
125
 
66
- this.logBox = blessed.log({
67
- top: 5,
68
- left: 0,
69
- width: '100%',
70
- height: '100%-5',
71
- tags: true,
72
- scrollable: true,
73
- alwaysScroll: true,
74
- scrollbar: {
75
- ch: ' ',
76
- track: {
77
- bg: 'blue'
78
- },
79
- style: {
80
- inverse: true
81
- }
82
- },
83
- mouse: true,
84
- keys: true,
85
- vi: true,
86
- style: {
87
- fg: 'white',
88
- bg: 'black'
89
- }
90
- });
126
+ this.render();
127
+ }
91
128
 
92
- this.screen.append(this.logBox);
93
- this.screen.append(this.headerBox);
129
+ isMouseEscapeSequence(input) {
130
+ if (!input || typeof input !== 'string') {
131
+ return false;
132
+ }
94
133
 
95
- this.screen.on('resize', () => {
96
- this.updateHeader();
97
- this.screen.render();
98
- });
134
+ sgrMouseRegex.lastIndex = 0;
135
+ return sgrMouseRegex.test(input);
136
+ }
99
137
 
100
- this.screen.key(['escape', 'q', 'C-c'], () => {
101
- return false;
102
- });
138
+ attachMouseHandler() {
139
+ if (!process.stdin?.isTTY || this._mouseDataHandler) {
140
+ return;
141
+ }
103
142
 
104
- this.screen.key(['enter', 'return'], () => {
105
- if (!this.isMouseEnabled) {
106
- this.enableMouseCapture();
107
- this.updateHeader();
108
- this.render();
143
+ this._mouseDataHandler = (chunk) => {
144
+ if (!this.isInitialized || !this.isMouseEnabled || this.hasPrompt()) {
109
145
  return;
110
146
  }
111
- this.logBox.log('');
112
- this.screen.render();
113
- });
114
147
 
115
- const handleMouseDisable = () => {
116
- if (this.isMouseEnabled) {
117
- this.disableMouseCapture();
118
- this.updateHeader();
119
- this.render();
120
- }
148
+ const data = String(chunk);
149
+ this.handleMouseData(data);
121
150
  };
122
- this.logBox.on('click', handleMouseDisable);
123
- this.headerBox.on('click', handleMouseDisable);
124
151
 
125
- this.screen.key(['down'], () => {
126
- this.logBox.scroll(1);
127
- this.screen.render();
128
- });
152
+ process.stdin.on('data', this._mouseDataHandler);
153
+ }
129
154
 
130
- this.screen.key(['up'], () => {
131
- this.logBox.scroll(-1);
132
- this.screen.render();
133
- });
155
+ handleMouseData(data) {
156
+ sgrMouseRegex.lastIndex = 0;
134
157
 
135
- this.screen.key(['pagedown'], () => {
136
- this.logBox.scroll(this.logBox.height);
137
- this.screen.render();
138
- });
158
+ let match;
159
+ while ((match = sgrMouseRegex.exec(data)) !== null) {
160
+ const code = Number(match[1]);
161
+ const action = match[4];
139
162
 
140
- this.screen.key(['pageup'], () => {
141
- this.logBox.scroll(-this.logBox.height);
142
- this.screen.render();
143
- });
163
+ if ((code & 64) === 64) {
164
+ const isScrollDown = (code & 1) === 1;
165
+ this.scrollLogs(isScrollDown ? -3 : 3);
166
+ continue;
167
+ }
144
168
 
145
- this.updateHeader();
146
- this.screen.render();
169
+ const isButtonPress = action === 'M';
170
+ const isDragEvent = (code & 32) === 32;
147
171
 
148
- this.isInitialized = true;
172
+ if (isButtonPress && !isDragEvent) {
173
+ this.disableMouseCapture();
174
+ break;
175
+ }
176
+ }
149
177
  }
150
178
 
151
- updateHeader() {
152
- if (!this.isInitialized) {
179
+ setMouseCaptureEnabled(isEnabled) {
180
+ if (!process.stdout?.isTTY) {
181
+ return;
182
+ }
183
+
184
+ if (isEnabled) {
185
+ process.stdout.write('\x1b[?1000h\x1b[?1002h\x1b[?1006h');
153
186
  return;
154
187
  }
155
188
 
189
+ process.stdout.write('\x1b[?1000l\x1b[?1002l\x1b[?1006l');
190
+ }
191
+
192
+ getHeaderLines() {
156
193
  const lines = [];
157
194
 
158
195
  let titleLine = ' ' + styleText(['bold', 'blue'], 'SDC Build WP');
@@ -173,7 +210,9 @@ class TUI {
173
210
  urlLine += `Local: ${styleText('green', this.urls.local)}`;
174
211
  }
175
212
  if (this.urls.external) {
176
- if (urlLine.length > 1) urlLine += ' ';
213
+ if (urlLine.length > 1) {
214
+ urlLine += ' ';
215
+ }
177
216
  urlLine += `External: ${styleText('green', this.urls.external)}`;
178
217
  }
179
218
  lines.push(urlLine);
@@ -193,32 +232,28 @@ class TUI {
193
232
  lines.push(' ');
194
233
  }
195
234
 
196
- this.headerBox.setContent(lines.join('\n'));
235
+ return lines;
197
236
  }
198
237
 
199
238
  setURLs(local, external) {
200
239
  this.urls.local = local;
201
240
  this.urls.external = external;
202
- this.updateHeader();
203
241
  this.render();
204
242
  }
205
243
 
206
244
  setCommands(commands) {
207
245
  this.commands = commands;
208
- this.updateHeader();
209
246
  this.render();
210
247
  }
211
248
 
212
249
  setPaused(isPaused) {
213
250
  this.isPaused = isPaused;
214
- this.updateHeader();
215
251
  this.render();
216
252
  }
217
253
 
218
254
  setComponents(components, watchMode = false) {
219
255
  this.components = components;
220
256
  this.watchMode = watchMode;
221
- this.updateHeader();
222
257
  this.render();
223
258
  }
224
259
 
@@ -228,7 +263,10 @@ class TUI {
228
263
  log(null, message);
229
264
  return;
230
265
  }
231
- this.logBox.log(message);
266
+
267
+ if (this._logScrollOffset === 0) {
268
+ this._logScrollOffset = 0;
269
+ }
232
270
  this.render();
233
271
  }
234
272
 
@@ -236,104 +274,156 @@ class TUI {
236
274
  return this._logHistory.join('\n');
237
275
  }
238
276
 
277
+ getVisibleLogLines(maxRows) {
278
+ if (this._logHistory.length === 0) {
279
+ return [''];
280
+ }
281
+
282
+ const maxOffset = Math.max(0, this._logHistory.length - maxRows);
283
+ this._logScrollOffset = Math.max(0, Math.min(this._logScrollOffset, maxOffset));
284
+
285
+ const endIndex = this._logHistory.length - this._logScrollOffset;
286
+ const startIndex = Math.max(0, endIndex - maxRows);
287
+ return this._logHistory.slice(startIndex, endIndex);
288
+ }
289
+
290
+ scrollLogs(delta) {
291
+ const nextOffset = this._logScrollOffset + delta;
292
+ const maxOffset = Math.max(0, this._logHistory.length - 1);
293
+ this._logScrollOffset = Math.max(0, Math.min(nextOffset, maxOffset));
294
+ this.render();
295
+ }
296
+
239
297
  render() {
240
- if (this.isInitialized && this.screen) {
241
- this.screen.render();
298
+ if (this.isInitialized && this.app) {
299
+ this.app.rerender(React.createElement(TUIRoot, { tui: this }));
300
+ }
301
+ }
302
+
303
+ hasPrompt() {
304
+ return Boolean(this._activePrompt);
305
+ }
306
+
307
+ getPromptRenderLines() {
308
+ if (!this._activePrompt) {
309
+ return [];
310
+ }
311
+
312
+ if (this._activePrompt.type === 'menu') {
313
+ const promptLines = [this._activePrompt.prompt];
314
+ for (let i = 0; i < this._activePrompt.options.length; i++) {
315
+ const isSelected = i === this._activePrompt.selectedIndex;
316
+ const prefix = isSelected ? styleText(['bold', 'green'], '>') : ' ';
317
+ promptLines.push(`${prefix} ${this._activePrompt.options[i]}`);
318
+ }
319
+ promptLines.push(styleText('gray', 'Use arrows to choose. Enter to confirm. Esc/q to cancel.'));
320
+ return promptLines;
321
+ }
322
+
323
+ if (this._activePrompt.type === 'input') {
324
+ const cursor = styleText(['bold', 'cyan'], '_');
325
+ return [
326
+ this._activePrompt.prompt,
327
+ `${styleText('gray', '>')} ${this._activePrompt.value}${cursor}`,
328
+ styleText('gray', 'Type your value, Enter to submit, Esc/q to cancel.')
329
+ ];
330
+ }
331
+
332
+ return [];
333
+ }
334
+
335
+ handlePromptInput(input, key) {
336
+ if (!this._activePrompt) {
337
+ return;
338
+ }
339
+
340
+ if (this._activePrompt.type === 'menu') {
341
+ if (key.upArrow) {
342
+ this._activePrompt.selectedIndex = (this._activePrompt.selectedIndex - 1 + this._activePrompt.options.length) % this._activePrompt.options.length;
343
+ this.render();
344
+ return;
345
+ }
346
+ if (key.downArrow) {
347
+ this._activePrompt.selectedIndex = (this._activePrompt.selectedIndex + 1) % this._activePrompt.options.length;
348
+ this.render();
349
+ return;
350
+ }
351
+ if (key.return) {
352
+ const selectedIndex = this._activePrompt.selectedIndex;
353
+ const selectedValue = this._activePrompt.options[selectedIndex];
354
+ const resolve = this._activePrompt.resolve;
355
+ this._activePrompt = null;
356
+ this.render();
357
+ resolve({ value: selectedValue, index: selectedIndex });
358
+ return;
359
+ }
360
+ if (key.escape || input === 'q') {
361
+ const resolve = this._activePrompt.resolve;
362
+ this._activePrompt = null;
363
+ this.render();
364
+ resolve(null);
365
+ }
366
+ return;
367
+ }
368
+
369
+ if (this._activePrompt.type === 'input') {
370
+ if (key.return) {
371
+ const resolve = this._activePrompt.resolve;
372
+ const value = this._activePrompt.value;
373
+ this._activePrompt = null;
374
+ this.render();
375
+ resolve(value);
376
+ return;
377
+ }
378
+ if (key.escape || input === 'q') {
379
+ const resolve = this._activePrompt.resolve;
380
+ this._activePrompt = null;
381
+ this.render();
382
+ resolve(null);
383
+ return;
384
+ }
385
+ if (key.backspace || key.delete) {
386
+ this._activePrompt.value = this._activePrompt.value.slice(0, -1);
387
+ this.render();
388
+ return;
389
+ }
390
+ if (!key.ctrl && !key.meta && input) {
391
+ this._activePrompt.value += input;
392
+ this.render();
393
+ }
242
394
  }
243
395
  }
244
396
 
245
397
  async showMenu(options, prompt = 'Choose an option:') {
398
+ if (!this.isInitialized) {
399
+ return null;
400
+ }
401
+
246
402
  return new Promise((resolve) => {
247
- const menu = blessed.list({
248
- parent: this.screen,
249
- top: 'center',
250
- left: 'center',
251
- width: '50%',
252
- height: options.length + 4,
253
- label: ` ${prompt} `,
254
- items: options,
255
- keys: true,
256
- mouse: true,
257
- border: 'line',
258
- style: {
259
- fg: 'white',
260
- bg: 'black',
261
- border: { fg: 'blue' },
262
- selected: { bg: 'blue', fg: 'white' }
263
- }
264
- });
265
- menu.focus();
266
- const stopLogScroll = (ch, key) => {
267
- if (['up', 'down', 'pagedown', 'pageup'].includes(key.name)) {
268
- return false;
269
- }
403
+ this._activePrompt = {
404
+ type: 'menu',
405
+ options,
406
+ prompt,
407
+ selectedIndex: 0,
408
+ resolve
270
409
  };
271
- this.logBox.ignoreKeys = true;
272
- menu.on('detach', () => {
273
- this.logBox.ignoreKeys = false;
274
- });
275
- menu.on('keypress', stopLogScroll);
276
- this.screen.render();
277
- menu.on('select', (item, idx) => {
278
- menu.destroy();
279
- this.screen.render();
280
- resolve({ value: item.getText(), index: idx });
281
- });
282
- menu.on('cancel', () => {
283
- menu.destroy();
284
- this.screen.render();
285
- resolve(null);
286
- });
287
- menu.key(['escape', 'q'], () => {
288
- menu.emit('cancel');
289
- });
410
+ this.render();
290
411
  });
291
412
  }
292
413
 
293
414
  async showInput(prompt = 'Enter value:') {
415
+ if (!this.isInitialized) {
416
+ return null;
417
+ }
418
+
294
419
  return new Promise((resolve) => {
295
- const box = blessed.box({
296
- parent: this.screen,
297
- top: 'center',
298
- left: 'center',
299
- width: '50%',
300
- height: 5,
301
- label: ` ${prompt} `,
302
- border: 'line',
303
- style: {
304
- fg: 'white',
305
- bg: 'black',
306
- border: { fg: 'blue' }
307
- }
308
- });
309
- const input = blessed.textbox({
310
- parent: box,
311
- top: 2,
312
- left: 2,
313
- width: '90%',
314
- height: 1,
315
- inputOnFocus: true,
316
- style: {
317
- fg: 'white',
318
- bg: 'black',
319
- focus: { bg: 'blue' }
320
- }
321
- });
322
- input.focus();
323
- this.screen.render();
324
- input.on('submit', (value) => {
325
- box.destroy();
326
- this.screen.render();
327
- resolve(value);
328
- });
329
- input.on('cancel', () => {
330
- box.destroy();
331
- this.screen.render();
332
- resolve(null);
333
- });
334
- input.key(['escape', 'q'], () => {
335
- input.emit('cancel');
336
- });
420
+ this._activePrompt = {
421
+ type: 'input',
422
+ prompt,
423
+ value: '',
424
+ resolve
425
+ };
426
+ this.render();
337
427
  });
338
428
  }
339
429
 
@@ -356,65 +446,53 @@ class TUI {
356
446
  this.watchMode = state.watchMode;
357
447
  this.isPaused = state.isPaused;
358
448
  this.isMouseEnabled = state.isMouseEnabled ?? true;
359
- if (this.isMouseEnabled) {
360
- this.enableMouseCapture();
361
- } else {
362
- this.disableMouseCapture();
363
- }
364
- this.updateHeader();
365
449
  this.render();
366
450
  }
367
451
  }
368
452
 
369
453
  enableMouseCapture() {
370
- if (!this.screen || this.isMouseEnabled) {
454
+ if (this.isMouseEnabled) {
371
455
  return;
372
456
  }
373
457
  this.isMouseEnabled = true;
374
- if (this.screen.enableMouse) {
375
- this.screen.enableMouse();
376
- return;
377
- }
378
- if (this.screen.program && this.screen.program.enableMouse) {
379
- this.screen.program.enableMouse();
380
- }
458
+ this.setMouseCaptureEnabled(true);
459
+ this.render();
381
460
  }
382
461
 
383
462
  disableMouseCapture() {
384
- if (!this.screen || !this.isMouseEnabled) {
463
+ if (!this.isMouseEnabled) {
385
464
  return;
386
465
  }
387
466
  this.isMouseEnabled = false;
388
- if (this.screen.disableMouse) {
389
- this.screen.disableMouse();
467
+ this.setMouseCaptureEnabled(false);
468
+ this.render();
469
+ }
470
+
471
+ destroy() {
472
+ if (!this.isInitialized) {
390
473
  return;
391
474
  }
392
- if (this.screen.program && this.screen.program.disableMouse) {
393
- this.screen.program.disableMouse();
475
+
476
+ if (this.app) {
477
+ this.app.unmount();
478
+ this.app = null;
394
479
  }
395
- }
396
480
 
397
- destroy() {
398
- if (this.isInitialized && this.screen) {
399
- if (this.screen.program) {
400
- this.screen.program.showCursor();
401
- this.screen.program.normalBuffer();
402
- this.screen.program.reset();
403
- }
481
+ if (this._mouseDataHandler && process.stdin) {
482
+ process.stdin.off('data', this._mouseDataHandler);
483
+ this._mouseDataHandler = null;
484
+ }
404
485
 
405
- this.screen.destroy();
406
- this.isInitialized = false;
407
- this.screen = null;
408
- this.headerBox = null;
409
- this.logBox = null;
410
- this.isMouseEnabled = true;
411
-
412
- if (process.stdout.isTTY) {
413
- process.stdout.write('\x1b[?25h');
414
- process.stdout.write('\x1b[0m');
415
- process.stdout.write('\x1b[2J');
416
- process.stdout.write('\x1b[H');
417
- }
486
+ this.setMouseCaptureEnabled(false);
487
+
488
+ this.isInitialized = false;
489
+ this.isMouseEnabled = true;
490
+ this._activePrompt = null;
491
+ this._logScrollOffset = 0;
492
+
493
+ if (process.stdout.isTTY) {
494
+ process.stdout.write('\x1b[?25h');
495
+ process.stdout.write('\x1b[0m');
418
496
  }
419
497
  }
420
498
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdc-build-wp",
3
- "version": "5.5.2",
3
+ "version": "5.6.0",
4
4
  "description": "Custom WordPress build process.",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -26,17 +26,18 @@
26
26
  "@stylistic/stylelint-plugin": "^4.0.0",
27
27
  "@typescript-eslint/eslint-plugin": "^8.48.1",
28
28
  "@typescript-eslint/parser": "^8.48.1",
29
- "@wordpress/scripts": "^31.4.0",
30
29
  "autoprefixer": "^10.4.24",
31
- "blessed": "^0.1.81",
32
30
  "browser-sync": "^3.0.4",
33
31
  "chokidar": "^5.0.0",
34
32
  "esbuild": "^0.27.3",
35
33
  "eslint": "^9.39.1",
34
+ "ink": "^6.8.0",
36
35
  "postcss": "^8.5.6",
37
36
  "postcss-scss": "^4.0.9",
38
37
  "postcss-sort-media-queries": "^5.2.0",
39
38
  "prettier": "^3.8.1",
39
+ "react": "^19.2.4",
40
+ "react-dom": "^19.2.4",
40
41
  "sass": "^1.97.3",
41
42
  "sharp": "^0.34.5",
42
43
  "stylelint": "^16.26.1",
package/webpack.config.js CHANGED
@@ -1,4 +1,11 @@
1
- import defaultConfig from '@wordpress/scripts/config/webpack.config.js';
1
+ let defaultConfig = {};
2
+
3
+ try {
4
+ const wpConfig = await import('@wordpress/scripts/config/webpack.config.js');
5
+ defaultConfig = wpConfig.default || {};
6
+ } catch {
7
+ defaultConfig = {};
8
+ }
2
9
 
3
10
  export default {
4
11
  ...defaultConfig,