vite-plugin-opencode-assistant 1.0.92 → 1.1.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.
@@ -146,6 +146,7 @@ function startOpenCodeWeb(options) {
146
146
  (_b = proc.stderr) == null ? void 0 : _b.on("data", (data) => {
147
147
  const output = data.toString().trim();
148
148
  if (output) {
149
+ if (output.includes("MaxListenersExceededWarning")) return;
149
150
  log.warn("[OpenCode stderr]", { output });
150
151
  (0, import_shared.getProcessLogBuffer)().addOpenCodeStderr(output);
151
152
  }
@@ -75,6 +75,29 @@ function generateBridgeScript(options) {
75
75
  const mergedSettings = mergeSettings(import_shared.DEFAULT_OPENCODE_SETTINGS, settings);
76
76
  return `
77
77
  (function() {
78
+ // === \u52AB\u6301 matchMedia\uFF0C\u5F3A\u5236\u684C\u9762\u7AEF\u5E03\u5C40\u4EE5\u6E32\u67D3\u5BA1\u67E5\u9762\u677F ===
79
+ // \u53EA\u52AB\u6301 opencode \u5224\u65AD\u684C\u9762\u7AEF\u7684\u5A92\u4F53\u67E5\u8BE2 (min-width: 768px)\uFF0C\u4E0D\u5F71\u54CD\u5176\u4ED6\u67E5\u8BE2
80
+ (function() {
81
+ var _origMatchMedia = window.matchMedia.bind(window);
82
+ var DESKTOP_QUERY = '(min-width: 768px)';
83
+ window.matchMedia = function(query) {
84
+ var result = _origMatchMedia(query);
85
+ if (query === DESKTOP_QUERY) {
86
+ return {
87
+ get matches() { return true; },
88
+ get media() { return result.media; },
89
+ onchange: null,
90
+ addListener: function(cb) { result.addListener(cb); },
91
+ removeListener: function(cb) { result.removeListener(cb); },
92
+ addEventListener: function(t, cb) { result.addEventListener(t, cb); },
93
+ removeEventListener: function(t, cb) { result.removeEventListener(t, cb); },
94
+ dispatchEvent: function(e) { return result.dispatchEvent(e); }
95
+ };
96
+ }
97
+ return result;
98
+ };
99
+ })();
100
+
78
101
  const STORAGE_KEYS = ${JSON.stringify(import_shared.OPENCODE_STORAGE_KEYS)};
79
102
  const THEME_KEY = STORAGE_KEYS.COLOR_SCHEME;
80
103
  const SETTINGS_KEY = STORAGE_KEYS.SETTINGS;
@@ -93,7 +116,27 @@ function generateBridgeScript(options) {
93
116
  }
94
117
 
95
118
  // \u521D\u59CB\u5316\u8BBE\u7F6E
96
- localStorage.setItem(SETTINGS_KEY, JSON.stringify(initialConfig.settings));
119
+ // \u6DF1\u5EA6\u5408\u5E76 initialConfig.settings \u5230\u5DF2\u6709\u914D\u7F6E\uFF1A\u53EA\u8986\u76D6\u63D2\u4EF6\u58F0\u660E\u7684\u5B57\u6BB5\uFF0C
120
+ // opencode \u81EA\u5DF1\u7BA1\u7406\u7684\u5176\u4ED6\u914D\u7F6E\u4E0D\u53D7\u5F71\u54CD
121
+ function deepMerge(target, source) {
122
+ for (var key in source) {
123
+ if (!{}.hasOwnProperty.call(source, key)) continue;
124
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
125
+ if (!target[key] || typeof target[key] !== "object") target[key] = {};
126
+ deepMerge(target[key], source[key]);
127
+ } else {
128
+ target[key] = source[key];
129
+ }
130
+ }
131
+ return target;
132
+ }
133
+
134
+ try {
135
+ var existing = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}");
136
+ localStorage.setItem(SETTINGS_KEY, JSON.stringify(deepMerge(existing, initialConfig.settings)));
137
+ } catch {
138
+ localStorage.setItem(SETTINGS_KEY, JSON.stringify(initialConfig.settings));
139
+ }
97
140
 
98
141
  // === \u4E3B\u9898\u540C\u6B65\u51FD\u6570 ===
99
142
  function getTheme() {
@@ -151,6 +194,10 @@ function generateBridgeScript(options) {
151
194
  if (event.data && event.data.type === ${JSON.stringify(import_shared.WIDGET_MSG.SELECT_MODE_CHANGE)}) {
152
195
  handleSelectModeChange(event.data.selectMode);
153
196
  }
197
+
198
+ if (event.data && event.data.type === ${JSON.stringify(import_shared.WIDGET_MSG.REVIEW_PANEL_TOGGLE)}) {
199
+ handleReviewPanelToggle(event.data.visible);
200
+ }
154
201
  });
155
202
 
156
203
  // === \u952E\u76D8\u4E8B\u4EF6\u8F6C\u53D1\uFF08\u7528\u4E8E\u9000\u51FA\u9009\u62E9\u6A21\u5F0F\uFF09 ===
@@ -204,6 +251,94 @@ function generateBridgeScript(options) {
204
251
  button[data-slot="dropdown-menu-trigger"][icon="dot-grid"] {
205
252
  display: none !important;
206
253
  }
254
+ [data-component="icon-button-v2"][aria-label="\u66F4\u591A\u9009\u9879"],
255
+ [data-component="icon-button-v2"][aria-label="More options"] {
256
+ display: none !important;
257
+ }
258
+ \`;
259
+
260
+ // === \u5BA1\u67E5\u9762\u677F\u8986\u76D6\u6837\u5F0F ===
261
+ // \u5BA1\u67E5\u9762\u677F\u5168\u5C4F\uFF0C\u4F1A\u8BDD\u9762\u677F\u6D6E\u5728\u53F3\u4E0B\u89D2\uFF08\u7C7B\u4F3C\u63D2\u4EF6\u6700\u5C0F\u5316\u72B6\u6001\uFF09
262
+ const reviewPanelStyles = \`
263
+ .opencode-review-panel-overlay [data-ref="panel-row"] {
264
+ flex-direction: column !important;
265
+ gap: 8px !important;
266
+ padding: 8px !important;
267
+ }
268
+
269
+ /* \u5BA1\u67E5\u9762\u677F\u5360\u6EE1\u5269\u4F59\u7A7A\u95F4 */
270
+ .opencode-review-panel-overlay [data-ref="side-panel-container"] {
271
+ flex: 1 !important;
272
+ width: 100% !important;
273
+ transition: none !important;
274
+ min-height: 0 !important;
275
+ }
276
+
277
+ /* \u4F1A\u8BDD\u9762\u677F\u6D6E\u5728\u53F3\u4E0B\u89D2 */
278
+ .opencode-review-panel-overlay [data-ref="session-panel"] {
279
+ position: fixed !important;
280
+ bottom: 16px !important;
281
+ right: 16px !important;
282
+ width: 380px !important;
283
+ max-height: 70vh !important;
284
+ display: flex !important;
285
+ flex-direction: column !important;
286
+ z-index: 600 !important;
287
+ border-radius: 12px !important;
288
+ box-shadow:
289
+ 0 0 0 1px rgba(0, 0, 0, 0.04),
290
+ 0 2px 4px rgba(0, 0, 0, 0.04),
291
+ 0 8px 16px rgba(0, 0, 0, 0.08),
292
+ 0 16px 40px rgba(0, 0, 0, 0.12) !important;
293
+ overflow: hidden !important;
294
+ transition: none;
295
+ }
296
+ .opencode-review-panel-overlay [data-ref="session-panel"] * {
297
+ max-width: none !important;
298
+ }
299
+
300
+ /* \u4F1A\u8BDD\u6D6E\u7A97\u5185\u5C42\u80CC\u666F\u62AC\u9AD8\uFF0C\u4E0E\u5BA1\u67E5\u9762\u677F\u5E95\u8272\u5F62\u6210\u5C42\u6B21 */
301
+ .opencode-review-panel-overlay [data-ref="session-panel"] [class*="bg-v2-background-bg-base"] {
302
+ background: color-mix(in srgb, var(--v2-background-bg-base, #1e1e1e) 96%, #fff) !important;
303
+ }
304
+
305
+ /* \u9690\u85CF\u4F1A\u8BDD\u9762\u677F\u5185\u7684\u6807\u9898 */
306
+ .opencode-review-panel-overlay [data-ref="session-panel"] [data-session-title] {
307
+ display: none !important;
308
+ }
309
+
310
+ /* \u9690\u85CF\u6D6E\u52A8\u4F1A\u8BDD\uFF08\u7528 visibility+opacity \u907F\u514D\u5207\u6362\u95EA\u70C1\uFF09 */
311
+ .opencode-review-panel-overlay.hide-chat [data-ref="session-panel"] {
312
+ visibility: hidden !important;
313
+ opacity: 0 !important;
314
+ pointer-events: none !important;
315
+ }
316
+
317
+ /* \u5BA1\u67E5\u9762\u677F\u53F3\u4E0A\u89D2\u60AC\u6D6E\u5207\u6362\u6309\u94AE */
318
+ .opencode-chat-toggle-btn {
319
+ position: fixed !important;
320
+ top: 16px !important;
321
+ right: 16px !important;
322
+ z-index: 700 !important;
323
+ width: 36px !important;
324
+ height: 36px !important;
325
+ border-radius: 8px !important;
326
+ border: none !important;
327
+ background: var(--v2-background-bg-base, #1e1e1e) !important;
328
+ color: var(--v2-icon-icon-base, #ccc) !important;
329
+ cursor: pointer !important;
330
+ display: flex !important;
331
+ align-items: center !important;
332
+ justify-content: center !important;
333
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
334
+ transition: background 0.15s !important;
335
+ }
336
+ .opencode-chat-toggle-btn:hover {
337
+ background: var(--v2-overlay-simple-overlay-hover, #333) !important;
338
+ }
339
+ .opencode-chat-toggle-btn.active {
340
+ background: var(--v2-overlay-simple-overlay-pressed, #444) !important;
341
+ }
207
342
  \`;
208
343
 
209
344
  function injectMinimizeStyles() {
@@ -214,9 +349,18 @@ function generateBridgeScript(options) {
214
349
  document.head.appendChild(style);
215
350
  }
216
351
 
352
+ function injectReviewPanelStyles() {
353
+ if (document.getElementById('opencode-review-panel-styles')) return;
354
+ const style = document.createElement('style');
355
+ style.id = 'opencode-review-panel-styles';
356
+ style.textContent = reviewPanelStyles;
357
+ document.head.appendChild(style);
358
+ }
359
+
217
360
  // === \u6700\u5C0F\u5316\u72B6\u6001\u5904\u7406 ===
218
361
  let savedMinimizedState = null;
219
362
  let savedPromptDockVisibleState = null;
363
+ let savedReviewPanelState = null;
220
364
 
221
365
  function handleMinimizeStateChange(minimized) {
222
366
  savedMinimizedState = minimized;
@@ -236,6 +380,117 @@ function generateBridgeScript(options) {
236
380
  document.documentElement.classList.remove('opencode-prompt-dock-hidden');
237
381
  }
238
382
  }
383
+
384
+ // === \u5BA1\u67E5\u9762\u677F\u8986\u76D6\u72B6\u6001\u5904\u7406 ===
385
+ // \u7B56\u7565\uFF1A\u7EAF CSS class \u63A7\u5236\u3002\u9996\u6B21\u6253\u5F00\u65F6\u7ED9\u5173\u952E\u5143\u7D20\u6253 data-ref \u6807\u8BB0\uFF0C
386
+ // \u540E\u7EED\u53EA\u9700 toggle class\u3002\u5173\u95ED\u65F6\u79FB\u9664 class\uFF0CCSS \u89C4\u5219\u81EA\u52A8\u6062\u590D\u539F\u59CB\u5E03\u5C40\u3002
387
+ // \u4E0D\u4FEE\u6539\u4EFB\u4F55 inline style\uFF0C\u907F\u514D\u4FDD\u5B58/\u6062\u590D\u7684\u65F6\u673A\u548C DOM \u5F15\u7528\u95EE\u9898\u3002
388
+
389
+ function ensureReviewPanelRefs() {
390
+ var reviewPanel = document.querySelector('[data-component="session-review-v2"]')
391
+ || document.querySelector('[data-component="session-review"]');
392
+ if (!reviewPanel) return false;
393
+
394
+ // \u5411\u4E0A\u904D\u5386\u627E\u5230 panelRow
395
+ var panelRow = reviewPanel.parentElement;
396
+ while (panelRow) {
397
+ var cls = panelRow.className || '';
398
+ if (cls.indexOf('flex-col') !== -1 && cls.indexOf('md:flex-row') !== -1) break;
399
+ panelRow = panelRow.parentElement;
400
+ }
401
+ if (!panelRow) return false;
402
+ panelRow.setAttribute('data-ref', 'panel-row');
403
+
404
+ // \u627E\u5230\u4F1A\u8BDD\u9762\u677F\u548C\u4FA7\u8FB9\u9762\u677F\u5BB9\u5668
405
+ for (var i = 0; i < panelRow.children.length; i++) {
406
+ var child = panelRow.children[i];
407
+ if (child.nodeType !== 1) continue;
408
+ var c = child.className || '';
409
+ if (c.indexOf('@container') !== -1) {
410
+ child.setAttribute('data-ref', 'session-panel');
411
+ } else if (c.indexOf('min-w-0') !== -1 && c.indexOf('flex-col') !== -1) {
412
+ child.setAttribute('data-ref', 'side-panel-container');
413
+ }
414
+ }
415
+
416
+ return true;
417
+ }
418
+
419
+ function injectChatToggleBtn() {
420
+ if (document.getElementById('opencode-chat-toggle-btn')) return;
421
+ var btn = document.createElement('button');
422
+ btn.id = 'opencode-chat-toggle-btn';
423
+ btn.className = 'opencode-chat-toggle-btn';
424
+ btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>';
425
+ btn.title = '\u5C55\u5F00\u804A\u5929\u9762\u677F';
426
+ // \u4ECE localStorage \u6062\u590D\u4E0A\u6B21\u7684\u5C55\u5F00/\u6536\u8D77\u72B6\u6001\uFF0C\u9ED8\u8BA4\u6536\u8D77
427
+ var chatVisible = localStorage.getItem('opencode-review-chat-visible');
428
+ if (chatVisible === 'true') {
429
+ document.documentElement.classList.remove('hide-chat');
430
+ btn.classList.add('active');
431
+ btn.title = '\u9690\u85CF\u804A\u5929\u9762\u677F';
432
+ } else {
433
+ document.documentElement.classList.add('hide-chat');
434
+ }
435
+ btn.onclick = function() {
436
+ document.documentElement.classList.toggle('hide-chat');
437
+ btn.classList.toggle('active');
438
+ var isVisible = btn.classList.contains('active');
439
+ btn.title = isVisible ? '\u9690\u85CF\u804A\u5929\u9762\u677F' : '\u5C55\u5F00\u804A\u5929\u9762\u677F';
440
+ localStorage.setItem('opencode-review-chat-visible', isVisible ? 'true' : 'false');
441
+ };
442
+ document.body.appendChild(btn);
443
+ }
444
+
445
+ function removeChatToggleBtn() {
446
+ var btn = document.getElementById('opencode-chat-toggle-btn');
447
+ if (btn) btn.remove();
448
+ }
449
+
450
+ function handleReviewPanelToggle(visible) {
451
+ // \u5982\u679C\u72B6\u6001\u6CA1\u6709\u53D8\u5316\uFF0C\u8DF3\u8FC7\uFF08\u907F\u514D MutationObserver \u91CD\u590D\u89E6\u53D1\uFF09
452
+ if (savedReviewPanelState === visible) return;
453
+ savedReviewPanelState = visible;
454
+
455
+ if (visible) {
456
+ // \u5148\u70B9\u51FB\u539F\u751F\u6309\u94AE\u6253\u5F00\u9762\u677F\uFF0C\u8BA9 DOM \u6E32\u67D3\u51FA\u6765
457
+ var reviewBtn = document.querySelector('[aria-controls="review-panel"]');
458
+ if (reviewBtn && reviewBtn.getAttribute('aria-expanded') !== 'true') {
459
+ reviewBtn.click();
460
+ }
461
+
462
+ // \u7B49 DOM \u5C31\u7EEA\u540E\u6253\u6807\u8BB0\u5E76\u5E94\u7528 CSS
463
+ var attempts = 0;
464
+ function tryApply() {
465
+ if (ensureReviewPanelRefs()) {
466
+ document.documentElement.classList.add('opencode-review-panel-overlay');
467
+ injectChatToggleBtn();
468
+ return;
469
+ }
470
+ attempts++;
471
+ if (attempts < 20) requestAnimationFrame(tryApply);
472
+ }
473
+ requestAnimationFrame(tryApply);
474
+ } else {
475
+ // \u5173\u95ED\u524D\u5148\u5C06\u4F1A\u8BDD\u9762\u677F\u5BBD\u5EA6\u8BBE\u4E3A 100%\uFF0C\u907F\u514D SolidJS \u5F02\u6B65\u6E32\u67D3\u7684\u5BBD\u5EA6\u8DF3\u53D8
476
+ var sessionPanel = document.querySelector('[data-ref="session-panel"]');
477
+ if (sessionPanel) sessionPanel.style.width = '100%';
478
+ document.body.offsetHeight; // \u5F3A\u5236\u56DE\u6D41
479
+
480
+ document.documentElement.classList.remove('opencode-review-panel-overlay');
481
+ document.documentElement.classList.remove('hide-chat');
482
+ removeChatToggleBtn();
483
+
484
+ // \u7B49\u4E00\u5E27\u8BA9 CSS \u5E03\u5C40\u53D8\u5316\u5148\u6E32\u67D3\uFF0C\u518D\u5173\u95ED\u539F\u751F\u9762\u677F
485
+ // \u907F\u514D SolidJS \u5F02\u6B65 DOM \u53D8\u5316\u548C CSS \u5E03\u5C40\u53D8\u5316\u53D1\u751F\u5728\u540C\u4E00\u5E27\u5BFC\u81F4\u89C6\u89C9\u8DF3\u52A8
486
+ requestAnimationFrame(function() {
487
+ var reviewBtn = document.querySelector('[aria-controls="review-panel"]');
488
+ if (reviewBtn && reviewBtn.getAttribute('aria-expanded') === 'true') {
489
+ reviewBtn.click();
490
+ }
491
+ });
492
+ }
493
+ }
239
494
 
240
495
  // === \u5E94\u7528\u4FDD\u5B58\u7684\u72B6\u6001 ===
241
496
  function applySavedStates() {
@@ -245,6 +500,9 @@ function generateBridgeScript(options) {
245
500
  if (savedPromptDockVisibleState !== null) {
246
501
  handlePromptDockVisibilityChange(savedPromptDockVisibleState);
247
502
  }
503
+ if (savedReviewPanelState !== null) {
504
+ handleReviewPanelToggle(savedReviewPanelState);
505
+ }
248
506
  }
249
507
 
250
508
  // === \u4FDD\u5B58\u8F93\u5165\u6846\u5149\u6807\u4F4D\u7F6E ===
@@ -390,6 +648,7 @@ function generateBridgeScript(options) {
390
648
  // === \u5C31\u7EEA\u901A\u77E5 ===
391
649
  function init() {
392
650
  injectMinimizeStyles();
651
+ injectReviewPanelStyles();
393
652
  if (window.parent !== window) {
394
653
  window.parent.postMessage({ type: ${JSON.stringify(import_shared.WIDGET_MSG.READY)} }, "*");
395
654
  }
@@ -183,7 +183,8 @@ Please install OpenCode first:
183
183
  if (((_a = this.webProcess) == null ? void 0 : _a.exitCode) !== null && ((_b = this.webProcess) == null ? void 0 : _b.exitCode) !== void 0) {
184
184
  throw new Error(`OpenCode process exited with code ${this.webProcess.exitCode}`);
185
185
  }
186
- log.info(`OpenCode Web started at ${webUrl}`);
186
+ const version = yield (0, import_system.getOpenCodeVersion)();
187
+ log.info(`OpenCode Web started at ${webUrl}${version ? ` (opencode ${version})` : ""}`);
187
188
  } catch (e) {
188
189
  log.error("OpenCode Web failed to start", { error: e });
189
190
  this.sendTaskUpdate("web_start_timeout");
@@ -50,6 +50,7 @@ __export(system_exports, {
50
50
  checkOpenCodeInstalled: () => checkOpenCodeInstalled,
51
51
  findAvailablePort: () => findAvailablePort,
52
52
  findGitRoot: () => findGitRoot,
53
+ getOpenCodeVersion: () => getOpenCodeVersion,
53
54
  isPortAvailable: () => isPortAvailable,
54
55
  killOrphanOpenCodeProcesses: () => killOrphanOpenCodeProcesses,
55
56
  waitForServer: () => waitForServer
@@ -121,6 +122,26 @@ function checkOpenCodeInstalled() {
121
122
  });
122
123
  });
123
124
  }
125
+ function getOpenCodeVersion() {
126
+ return new Promise((resolve) => {
127
+ var _a;
128
+ const proc = (0, import_child_process.spawn)("opencode", ["--version"], { stdio: "pipe" });
129
+ let output = "";
130
+ (_a = proc.stdout) == null ? void 0 : _a.on("data", (data) => {
131
+ output += data.toString();
132
+ });
133
+ proc.on("close", (code) => {
134
+ if (code === 0 && output.trim()) {
135
+ resolve(output.trim());
136
+ } else {
137
+ resolve(null);
138
+ }
139
+ });
140
+ proc.on("error", () => {
141
+ resolve(null);
142
+ });
143
+ });
144
+ }
124
145
  function isPortAvailable(port, hostname) {
125
146
  return __async(this, null, function* () {
126
147
  return new Promise((resolve) => {
@@ -302,6 +323,7 @@ function killOrphanProcessesOnUnix(resolve, timer) {
302
323
  checkOpenCodeInstalled,
303
324
  findAvailablePort,
304
325
  findGitRoot,
326
+ getOpenCodeVersion,
305
327
  isPortAvailable,
306
328
  killOrphanOpenCodeProcesses,
307
329
  waitForServer
@@ -1,6 +1,7 @@
1
1
  import type { ResultPromise } from "execa";
2
2
  export declare function waitForServer(url: string, timeout?: number, process?: ResultPromise): Promise<void>;
3
3
  export declare function checkOpenCodeInstalled(): Promise<boolean>;
4
+ export declare function getOpenCodeVersion(): Promise<string | null>;
4
5
  export declare function isPortAvailable(port: number, hostname?: string): Promise<boolean>;
5
6
  export declare function findAvailablePort(startPort: number, hostname?: string, maxTries?: number): Promise<number>;
6
7
  export declare function killOrphanOpenCodeProcesses(): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-opencode-assistant",
3
- "version": "1.0.92",
3
+ "version": "1.1.0",
4
4
  "description": "Embed OpenCode Web UI in your Vite dev server for real-time code modification and preview",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
@@ -37,15 +37,15 @@
37
37
  "dependencies": {
38
38
  "unplugin-vue-inspector": "^3.0.0",
39
39
  "execa": "^9.6.1",
40
- "@vite-plugin-opencode-assistant/components": "1.0.92",
41
- "@vite-plugin-opencode-assistant/opencode": "1.0.92",
42
- "@vite-plugin-opencode-assistant/shared": "1.0.92"
40
+ "@vite-plugin-opencode-assistant/opencode": "1.1.0",
41
+ "@vite-plugin-opencode-assistant/shared": "1.1.0",
42
+ "@vite-plugin-opencode-assistant/components": "1.1.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "vite": ">=5.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@vite-plugin-opencode-assistant/client": "1.0.92"
48
+ "@vite-plugin-opencode-assistant/client": "1.1.0"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "pagoda-cli build && vite build -c vite.client.config.ts",