@_davideast/stitch-mcp 0.7.0 → 0.8.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.
@@ -0,0 +1,736 @@
1
+ import {
2
+ fetchWithRetry
3
+ } from "./chunk-6gw9apqb.js";
4
+ import {
5
+ pLimit
6
+ } from "./chunk-a5xra9jn.js";
7
+ import {
8
+ openUrl,
9
+ require_jsx_dev_runtime
10
+ } from "./chunk-mp1sf8x6.js";
11
+ import {
12
+ StitchViteServer
13
+ } from "./chunk-9ckyz47q.js";
14
+ import {
15
+ require_lib
16
+ } from "./chunk-sqhdg0mf.js";
17
+ import {
18
+ Box_default,
19
+ Text,
20
+ use_app_default,
21
+ use_input_default,
22
+ use_stdout_default
23
+ } from "./chunk-5jbenaez.js";
24
+ import {
25
+ require_react
26
+ } from "./chunk-vcp9fp2w.js";
27
+ import {
28
+ require_cli_spinners
29
+ } from "./chunk-nq68kghz.js";
30
+ import {
31
+ source_default
32
+ } from "./chunk-3sfn889r.js";
33
+ import {
34
+ __toESM
35
+ } from "./chunk-9wyra8hs.js";
36
+
37
+ // src/commands/site/ui/SiteBuilder.tsx
38
+ var import_react4 = __toESM(require_react(), 1);
39
+
40
+ // node_modules/ink-spinner/build/index.js
41
+ var import_react = __toESM(require_react(), 1);
42
+ var import_cli_spinners = __toESM(require_cli_spinners(), 1);
43
+ function Spinner({ type = "dots" }) {
44
+ const [frame, setFrame] = import_react.useState(0);
45
+ const spinner = import_cli_spinners.default[type];
46
+ import_react.useEffect(() => {
47
+ const timer = setInterval(() => {
48
+ setFrame((previousFrame) => {
49
+ const isLastFrame = previousFrame === spinner.frames.length - 1;
50
+ return isLastFrame ? 0 : previousFrame + 1;
51
+ });
52
+ }, spinner.interval);
53
+ return () => {
54
+ clearInterval(timer);
55
+ };
56
+ }, [spinner]);
57
+ return import_react.default.createElement(Text, null, spinner.frames[frame]);
58
+ }
59
+ var build_default = Spinner;
60
+
61
+ // node_modules/ink-text-input/build/index.js
62
+ var import_react2 = __toESM(require_react(), 1);
63
+ function TextInput({ value: originalValue, placeholder = "", focus = true, mask, highlightPastedText = false, showCursor = true, onChange, onSubmit }) {
64
+ const [state, setState] = import_react2.useState({
65
+ cursorOffset: (originalValue || "").length,
66
+ cursorWidth: 0
67
+ });
68
+ const { cursorOffset, cursorWidth } = state;
69
+ import_react2.useEffect(() => {
70
+ setState((previousState) => {
71
+ if (!focus || !showCursor) {
72
+ return previousState;
73
+ }
74
+ const newValue = originalValue || "";
75
+ if (previousState.cursorOffset > newValue.length - 1) {
76
+ return {
77
+ cursorOffset: newValue.length,
78
+ cursorWidth: 0
79
+ };
80
+ }
81
+ return previousState;
82
+ });
83
+ }, [originalValue, focus, showCursor]);
84
+ const cursorActualWidth = highlightPastedText ? cursorWidth : 0;
85
+ const value = mask ? mask.repeat(originalValue.length) : originalValue;
86
+ let renderedValue = value;
87
+ let renderedPlaceholder = placeholder ? source_default.grey(placeholder) : undefined;
88
+ if (showCursor && focus) {
89
+ renderedPlaceholder = placeholder.length > 0 ? source_default.inverse(placeholder[0]) + source_default.grey(placeholder.slice(1)) : source_default.inverse(" ");
90
+ renderedValue = value.length > 0 ? "" : source_default.inverse(" ");
91
+ let i = 0;
92
+ for (const char of value) {
93
+ renderedValue += i >= cursorOffset - cursorActualWidth && i <= cursorOffset ? source_default.inverse(char) : char;
94
+ i++;
95
+ }
96
+ if (value.length > 0 && cursorOffset === value.length) {
97
+ renderedValue += source_default.inverse(" ");
98
+ }
99
+ }
100
+ use_input_default((input, key) => {
101
+ if (key.upArrow || key.downArrow || key.ctrl && input === "c" || key.tab || key.shift && key.tab) {
102
+ return;
103
+ }
104
+ if (key.return) {
105
+ if (onSubmit) {
106
+ onSubmit(originalValue);
107
+ }
108
+ return;
109
+ }
110
+ let nextCursorOffset = cursorOffset;
111
+ let nextValue = originalValue;
112
+ let nextCursorWidth = 0;
113
+ if (key.leftArrow) {
114
+ if (showCursor) {
115
+ nextCursorOffset--;
116
+ }
117
+ } else if (key.rightArrow) {
118
+ if (showCursor) {
119
+ nextCursorOffset++;
120
+ }
121
+ } else if (key.backspace || key.delete) {
122
+ if (cursorOffset > 0) {
123
+ nextValue = originalValue.slice(0, cursorOffset - 1) + originalValue.slice(cursorOffset, originalValue.length);
124
+ nextCursorOffset--;
125
+ }
126
+ } else {
127
+ nextValue = originalValue.slice(0, cursorOffset) + input + originalValue.slice(cursorOffset, originalValue.length);
128
+ nextCursorOffset += input.length;
129
+ if (input.length > 1) {
130
+ nextCursorWidth = input.length;
131
+ }
132
+ }
133
+ if (cursorOffset < 0) {
134
+ nextCursorOffset = 0;
135
+ }
136
+ if (cursorOffset > originalValue.length) {
137
+ nextCursorOffset = originalValue.length;
138
+ }
139
+ setState({
140
+ cursorOffset: nextCursorOffset,
141
+ cursorWidth: nextCursorWidth
142
+ });
143
+ if (nextValue !== originalValue) {
144
+ onChange(nextValue);
145
+ }
146
+ }, { isActive: focus });
147
+ return import_react2.default.createElement(Text, null, placeholder ? value.length > 0 ? renderedValue : renderedPlaceholder : renderedValue);
148
+ }
149
+ var build_default2 = TextInput;
150
+
151
+ // src/commands/site/utils/SiteManifest.ts
152
+ var import_fs_extra = __toESM(require_lib(), 1);
153
+ import path from "path";
154
+ import os from "os";
155
+
156
+ class SiteManifest {
157
+ filePath;
158
+ legacyPath;
159
+ constructor(projectId) {
160
+ const dir = path.join(os.homedir(), ".stitch-mcp", "site", projectId);
161
+ this.filePath = path.join(dir, "site-manifest.json");
162
+ this.legacyPath = path.join(dir, "discarded.json");
163
+ }
164
+ async load() {
165
+ try {
166
+ const data = await import_fs_extra.default.readJson(this.filePath);
167
+ return new Map(Object.entries(data.screens || {}));
168
+ } catch {}
169
+ try {
170
+ const legacy = await import_fs_extra.default.readJson(this.legacyPath);
171
+ const map = new Map;
172
+ for (const id of legacy.discardedScreenIds || []) {
173
+ map.set(id, { status: "discarded" });
174
+ }
175
+ return map;
176
+ } catch {
177
+ return new Map;
178
+ }
179
+ }
180
+ async save(screens) {
181
+ const record = {};
182
+ for (const screen of screens) {
183
+ const entry = {};
184
+ if (screen.status !== "ignored") {
185
+ entry.status = screen.status;
186
+ }
187
+ if (screen.route !== "") {
188
+ entry.route = screen.route;
189
+ }
190
+ if (entry.status || entry.route) {
191
+ record[screen.id] = entry;
192
+ }
193
+ }
194
+ await import_fs_extra.default.ensureDir(path.dirname(this.filePath));
195
+ const data = { screens: record };
196
+ await import_fs_extra.default.writeJson(this.filePath, data, { spaces: 2 });
197
+ }
198
+ }
199
+
200
+ // src/commands/site/ui/components/StatusIcon.tsx
201
+ var jsx_dev_runtime = __toESM(require_jsx_dev_runtime(), 1);
202
+ var StatusIcon = ({ status }) => {
203
+ if (status === "included") {
204
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
205
+ color: "green",
206
+ children: "✔ "
207
+ }, undefined, false, undefined, this);
208
+ }
209
+ if (status === "discarded") {
210
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
211
+ color: "red",
212
+ children: "✖ "
213
+ }, undefined, false, undefined, this);
214
+ }
215
+ return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
216
+ color: "gray",
217
+ children: "- "
218
+ }, undefined, false, undefined, this);
219
+ };
220
+
221
+ // src/commands/site/ui/ScreenList.tsx
222
+ var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
223
+ var ScreenList = ({ items, activeIndex }) => {
224
+ const { stdout } = use_stdout_default();
225
+ const height = stdout ? stdout.rows : 20;
226
+ const LIST_HEIGHT = Math.max(5, height - 10);
227
+ let start = 0;
228
+ if (activeIndex >= LIST_HEIGHT) {
229
+ start = activeIndex - LIST_HEIGHT + 1;
230
+ }
231
+ start = Math.max(0, activeIndex - Math.floor(LIST_HEIGHT / 2));
232
+ const end = Math.min(items.length, start + LIST_HEIGHT);
233
+ if (end - start < LIST_HEIGHT && items.length > LIST_HEIGHT) {
234
+ start = Math.max(0, items.length - LIST_HEIGHT);
235
+ }
236
+ const visibleItems = items.slice(start, end);
237
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
238
+ flexDirection: "column",
239
+ flexGrow: 1,
240
+ borderStyle: "single",
241
+ borderColor: "blue",
242
+ children: [
243
+ start > 0 && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
244
+ paddingLeft: 1,
245
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
246
+ color: "gray",
247
+ children: [
248
+ "... ",
249
+ start,
250
+ " more above ..."
251
+ ]
252
+ }, undefined, true, undefined, this)
253
+ }, undefined, false, undefined, this),
254
+ visibleItems.map((item, i) => {
255
+ const index = start + i;
256
+ const isActive = index === activeIndex;
257
+ const { screen } = item;
258
+ return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
259
+ children: [
260
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
261
+ color: isActive ? "cyan" : undefined,
262
+ children: isActive ? "> " : " "
263
+ }, undefined, false, undefined, this),
264
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(StatusIcon, {
265
+ status: screen.status
266
+ }, undefined, false, undefined, this),
267
+ /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
268
+ color: isActive ? "cyan" : undefined,
269
+ wrap: "truncate",
270
+ children: screen.title
271
+ }, undefined, false, undefined, this),
272
+ screen.route && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
273
+ color: "gray",
274
+ children: [
275
+ " -> ",
276
+ screen.route
277
+ ]
278
+ }, undefined, true, undefined, this)
279
+ ]
280
+ }, screen.id, true, undefined, this);
281
+ }),
282
+ end < items.length && /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Box_default, {
283
+ paddingLeft: 1,
284
+ children: /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Text, {
285
+ color: "gray",
286
+ children: [
287
+ "... ",
288
+ items.length - end,
289
+ " more below ..."
290
+ ]
291
+ }, undefined, true, undefined, this)
292
+ }, undefined, false, undefined, this)
293
+ ]
294
+ }, undefined, true, undefined, this);
295
+ };
296
+
297
+ // src/commands/site/hooks/useProjectHydration.ts
298
+ var import_react3 = __toESM(require_react(), 1);
299
+ function useProjectHydration(screens, server, fetchContent, activeScreenId) {
300
+ const [hydrationStatus, setHydrationStatus] = import_react3.useState("idle");
301
+ const [progress, setProgress] = import_react3.useState(0);
302
+ const contentCache = import_react3.useRef(new Map);
303
+ const [htmlContent, setHtmlContent] = import_react3.useState(new Map);
304
+ import_react3.useEffect(() => {
305
+ if (!server || screens.length === 0)
306
+ return;
307
+ let mounted = true;
308
+ const hydrate = async () => {
309
+ const toDownload = screens.filter((s) => {
310
+ if (contentCache.current.has(s.id))
311
+ return false;
312
+ return s.status === "included" || s.id === activeScreenId;
313
+ });
314
+ if (toDownload.length === 0) {
315
+ if (hydrationStatus === "idle" || hydrationStatus === "downloading") {
316
+ setHydrationStatus("ready");
317
+ setHtmlContent(new Map(contentCache.current));
318
+ }
319
+ if (activeScreenId && contentCache.current.has(activeScreenId)) {
320
+ server.mount(`/_preview/${activeScreenId}`, contentCache.current.get(activeScreenId));
321
+ }
322
+ return;
323
+ }
324
+ setHydrationStatus("downloading");
325
+ const limit = pLimit(3);
326
+ let completed = 0;
327
+ const total = toDownload.length;
328
+ try {
329
+ await Promise.all(toDownload.map((screen) => limit(async () => {
330
+ if (!mounted)
331
+ return;
332
+ if (!screen.downloadUrl)
333
+ return;
334
+ try {
335
+ const html = await fetchContent(screen.downloadUrl);
336
+ if (mounted) {
337
+ contentCache.current.set(screen.id, html);
338
+ server.mount(`/_preview/${screen.id}`, html);
339
+ }
340
+ } catch (e) {
341
+ console.error(`Failed to hydrate ${screen.id}`, e);
342
+ }
343
+ if (mounted) {
344
+ completed++;
345
+ setProgress(completed / total);
346
+ }
347
+ })));
348
+ if (mounted) {
349
+ setHtmlContent(new Map(contentCache.current));
350
+ setHydrationStatus("ready");
351
+ }
352
+ } catch (e) {
353
+ if (mounted)
354
+ setHydrationStatus("error");
355
+ }
356
+ };
357
+ hydrate();
358
+ return () => {
359
+ mounted = false;
360
+ };
361
+ }, [screens, server, fetchContent, activeScreenId]);
362
+ return { hydrationStatus, progress, htmlContent };
363
+ }
364
+
365
+ // src/commands/site/ui/SiteBuilder.tsx
366
+ var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
367
+ var SiteBuilder = ({ projectId, client, onExit }) => {
368
+ const { exit } = use_app_default();
369
+ const [loading, setLoading] = import_react4.useState(true);
370
+ const [error, setError] = import_react4.useState(null);
371
+ const [screens, setScreens] = import_react4.useState([]);
372
+ const [showSelectedOnly, setShowSelectedOnly] = import_react4.useState(false);
373
+ const [activeIndex, setActiveIndex] = import_react4.useState(0);
374
+ const [viewMode, setViewMode] = import_react4.useState("default");
375
+ const siteManifest = import_react4.useMemo(() => new SiteManifest(projectId), [projectId]);
376
+ const [isEditingRoute, setIsEditingRoute] = import_react4.useState(false);
377
+ const [routeValue, setRouteValue] = import_react4.useState("");
378
+ const [followMode, setFollowMode] = import_react4.useState(true);
379
+ const [showAllKeys, setShowAllKeys] = import_react4.useState(false);
380
+ const [serverUrl, setServerUrl] = import_react4.useState(null);
381
+ const [server, setServer] = import_react4.useState(null);
382
+ import_react4.useEffect(() => {
383
+ let mounted = true;
384
+ const srv = new StitchViteServer;
385
+ setServer(srv);
386
+ const init = async () => {
387
+ try {
388
+ const url = await srv.start(0);
389
+ if (mounted)
390
+ setServerUrl(url);
391
+ const project = client.project(projectId);
392
+ const sdkScreens = await project.screens();
393
+ const uiScreens = await Promise.all(sdkScreens.map(async (s) => ({
394
+ id: s.screenId,
395
+ title: s.title ?? s.screenId,
396
+ status: "ignored",
397
+ route: "",
398
+ downloadUrl: await s.getHtml().catch(() => null)
399
+ })));
400
+ const saved = await siteManifest.load();
401
+ for (const screen of uiScreens) {
402
+ const state = saved.get(screen.id);
403
+ if (state?.status)
404
+ screen.status = state.status;
405
+ if (state?.route)
406
+ screen.route = state.route;
407
+ }
408
+ if (mounted) {
409
+ setScreens(uiScreens);
410
+ setLoading(false);
411
+ }
412
+ } catch (e) {
413
+ if (mounted)
414
+ setError(e.message);
415
+ }
416
+ };
417
+ init();
418
+ return () => {
419
+ mounted = false;
420
+ srv.stop();
421
+ };
422
+ }, [projectId, client]);
423
+ const displayList = import_react4.useMemo(() => {
424
+ let list = screens.map((s, i) => ({ screen: s, sourceIndex: i }));
425
+ if (viewMode === "discarded") {
426
+ return list.filter((item) => item.screen.status === "discarded");
427
+ }
428
+ list = list.filter((item) => item.screen.status !== "discarded");
429
+ if (showSelectedOnly) {
430
+ list = list.filter((item) => item.screen.status === "included");
431
+ }
432
+ return list;
433
+ }, [screens, viewMode, showSelectedOnly]);
434
+ import_react4.useEffect(() => {
435
+ setActiveIndex((prev) => {
436
+ if (displayList.length === 0)
437
+ return 0;
438
+ return Math.min(prev, Math.max(0, displayList.length - 1));
439
+ });
440
+ }, [displayList.length]);
441
+ const activeItem = displayList[activeIndex];
442
+ const activeScreenId = activeItem?.screen.id;
443
+ const fetchContent = import_react4.useCallback((url) => fetchWithRetry(url), []);
444
+ const { hydrationStatus, progress, htmlContent } = useProjectHydration(screens, server, fetchContent, activeScreenId);
445
+ import_react4.useEffect(() => {
446
+ if (server && followMode && hydrationStatus === "ready" && activeScreenId) {
447
+ server.navigate(`/_preview/${activeScreenId}`);
448
+ }
449
+ }, [activeScreenId, followMode, server, hydrationStatus]);
450
+ use_input_default((input, key) => {
451
+ if (loading || error)
452
+ return;
453
+ if (isEditingRoute) {
454
+ if (key.escape) {
455
+ setIsEditingRoute(false);
456
+ setRouteValue("");
457
+ }
458
+ return;
459
+ }
460
+ if (key.upArrow) {
461
+ setActiveIndex((prev) => Math.max(0, prev - 1));
462
+ }
463
+ if (key.downArrow) {
464
+ setActiveIndex((prev) => Math.min(displayList.length - 1, prev + 1));
465
+ }
466
+ if (input === " ") {
467
+ if (activeItem) {
468
+ const originalIndex = activeItem.sourceIndex;
469
+ setScreens((prev) => {
470
+ const next = [...prev];
471
+ const s = next[originalIndex];
472
+ if (s) {
473
+ s.status = s.status === "included" ? "ignored" : "included";
474
+ }
475
+ siteManifest.save(next);
476
+ return next;
477
+ });
478
+ }
479
+ }
480
+ if (key.return) {
481
+ if (activeItem) {
482
+ setRouteValue(activeItem.screen.route);
483
+ setIsEditingRoute(true);
484
+ }
485
+ }
486
+ if (input === "t") {
487
+ setShowSelectedOnly((prev) => !prev);
488
+ }
489
+ if (input === "f") {
490
+ setFollowMode((prev) => !prev);
491
+ }
492
+ if (input === "x") {
493
+ const item = displayList[activeIndex];
494
+ if (!item)
495
+ return;
496
+ if (viewMode === "discarded") {
497
+ const idx = item.sourceIndex;
498
+ setScreens((prev) => {
499
+ const next = [...prev];
500
+ if (next[idx])
501
+ next[idx].status = "ignored";
502
+ siteManifest.save(next);
503
+ return next;
504
+ });
505
+ } else {
506
+ const idx = item.sourceIndex;
507
+ setScreens((prev) => {
508
+ const next = [...prev];
509
+ if (next[idx])
510
+ next[idx].status = "discarded";
511
+ siteManifest.save(next);
512
+ return next;
513
+ });
514
+ }
515
+ }
516
+ if (input === "d") {
517
+ setViewMode((prev) => prev === "default" ? "discarded" : "default");
518
+ setActiveIndex(0);
519
+ }
520
+ if (input === "o") {
521
+ if (serverUrl && activeScreenId) {
522
+ const target = `${serverUrl}/_preview/${activeScreenId}`;
523
+ openUrl(target);
524
+ }
525
+ }
526
+ if (input === "g") {
527
+ const included = screens.filter((s) => s.status === "included");
528
+ const invalid = included.find((s) => !s.route || s.route.trim() === "");
529
+ if (invalid) {
530
+ return;
531
+ }
532
+ const finalConfig = {
533
+ projectId,
534
+ routes: included.map((s) => ({
535
+ screenId: s.id,
536
+ route: s.route,
537
+ status: s.status
538
+ }))
539
+ };
540
+ onExit(finalConfig, htmlContent);
541
+ exit();
542
+ }
543
+ if (input === "e") {
544
+ const included = screens.filter((s) => s.status === "included");
545
+ const exportData = {
546
+ projectId,
547
+ routes: included.map((s) => ({
548
+ screenId: s.id,
549
+ route: s.route
550
+ }))
551
+ };
552
+ process.stdout.write(JSON.stringify(exportData, null, 2) + `
553
+ `);
554
+ }
555
+ if (input === "?") {
556
+ setShowAllKeys((prev) => !prev);
557
+ }
558
+ if (input === "q") {
559
+ onExit(null);
560
+ exit();
561
+ }
562
+ });
563
+ const handleRouteSubmit = (val) => {
564
+ if (activeItem) {
565
+ const originalIndex = activeItem.sourceIndex;
566
+ setScreens((prev) => {
567
+ const next = [...prev];
568
+ if (next[originalIndex]) {
569
+ next[originalIndex].route = val;
570
+ }
571
+ siteManifest.save(next);
572
+ return next;
573
+ });
574
+ setIsEditingRoute(false);
575
+ setActiveIndex((prev) => Math.min(displayList.length - 1, prev + 1));
576
+ }
577
+ };
578
+ if (error) {
579
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
580
+ color: "red",
581
+ children: [
582
+ "Error: ",
583
+ error
584
+ ]
585
+ }, undefined, true, undefined, this);
586
+ }
587
+ if (loading) {
588
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
589
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
590
+ color: "green",
591
+ children: [
592
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(build_default, {
593
+ type: "dots"
594
+ }, undefined, false, undefined, this),
595
+ " Loading project..."
596
+ ]
597
+ }, undefined, true, undefined, this)
598
+ }, undefined, false, undefined, this);
599
+ }
600
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
601
+ flexDirection: "column",
602
+ height: "100%",
603
+ children: [
604
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
605
+ borderStyle: "single",
606
+ borderColor: "cyan",
607
+ paddingX: 1,
608
+ children: [
609
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
610
+ children: "Stitch Site Builder"
611
+ }, undefined, false, undefined, this),
612
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
613
+ marginLeft: 2,
614
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
615
+ color: "gray",
616
+ children: serverUrl
617
+ }, undefined, false, undefined, this)
618
+ }, undefined, false, undefined, this),
619
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
620
+ marginLeft: 2,
621
+ children: viewMode === "discarded" ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
622
+ color: "red",
623
+ children: [
624
+ "Viewing Discarded (",
625
+ displayList.length,
626
+ ")"
627
+ ]
628
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
629
+ children: [
630
+ "Filter: ",
631
+ showSelectedOnly ? "Selected" : "All",
632
+ " (",
633
+ displayList.length,
634
+ ")"
635
+ ]
636
+ }, undefined, true, undefined, this)
637
+ }, undefined, false, undefined, this),
638
+ viewMode === "default" && screens.filter((s) => s.status === "discarded").length > 0 && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
639
+ marginLeft: 2,
640
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
641
+ dimColor: true,
642
+ children: [
643
+ screens.filter((s) => s.status === "discarded").length,
644
+ " discarded (press d to view)"
645
+ ]
646
+ }, undefined, true, undefined, this)
647
+ }, undefined, false, undefined, this),
648
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
649
+ marginLeft: 2,
650
+ children: [
651
+ hydrationStatus === "downloading" && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
652
+ color: "yellow",
653
+ children: [
654
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(build_default, {
655
+ type: "dots"
656
+ }, undefined, false, undefined, this),
657
+ " Downloading... ",
658
+ Math.round(progress * 100),
659
+ "%"
660
+ ]
661
+ }, undefined, true, undefined, this),
662
+ hydrationStatus === "ready" && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
663
+ color: "green",
664
+ children: "Ready"
665
+ }, undefined, false, undefined, this)
666
+ ]
667
+ }, undefined, true, undefined, this)
668
+ ]
669
+ }, undefined, true, undefined, this),
670
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(ScreenList, {
671
+ items: displayList,
672
+ activeIndex
673
+ }, undefined, false, undefined, this),
674
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
675
+ borderStyle: "single",
676
+ borderColor: isEditingRoute ? "green" : "gray",
677
+ paddingX: 1,
678
+ flexDirection: "column",
679
+ children: activeItem ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(jsx_dev_runtime3.Fragment, {
680
+ children: [
681
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
682
+ bold: true,
683
+ children: [
684
+ "Route for: ",
685
+ activeItem.screen.title
686
+ ]
687
+ }, undefined, true, undefined, this),
688
+ isEditingRoute ? /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
689
+ children: [
690
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
691
+ color: "green",
692
+ children: "> "
693
+ }, undefined, false, undefined, this),
694
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(build_default2, {
695
+ value: routeValue,
696
+ onChange: setRouteValue,
697
+ onSubmit: handleRouteSubmit
698
+ }, undefined, false, undefined, this)
699
+ ]
700
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
701
+ children: [
702
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
703
+ color: "gray",
704
+ children: activeItem.screen.route || "No route defined"
705
+ }, undefined, false, undefined, this),
706
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
707
+ marginLeft: 2,
708
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
709
+ dimColor: true,
710
+ children: "Press Enter to edit"
711
+ }, undefined, false, undefined, this)
712
+ }, undefined, false, undefined, this)
713
+ ]
714
+ }, undefined, true, undefined, this)
715
+ ]
716
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
717
+ color: "gray",
718
+ children: "No screen selected"
719
+ }, undefined, false, undefined, this)
720
+ }, undefined, false, undefined, this),
721
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
722
+ borderStyle: "single",
723
+ borderColor: "gray",
724
+ paddingX: 1,
725
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
726
+ dimColor: true,
727
+ children: viewMode === "discarded" ? "[x] Undiscard [d] Back to All [q] Quit" : showAllKeys ? `[Space] Toggle [Enter] Edit Route [x] Discard [d] View Discarded [t] Filter [f] Follow: ${followMode ? "ON" : "OFF"} [o] Open [g] Generate [e] Export [q] Quit [?] Less` : "[Space] Toggle [Enter] Edit Route [g] Generate [x] Discard [o] Open [q] Quit [?] More"
728
+ }, undefined, false, undefined, this)
729
+ }, undefined, false, undefined, this)
730
+ ]
731
+ }, undefined, true, undefined, this);
732
+ };
733
+
734
+ export { SiteManifest, SiteBuilder };
735
+
736
+ //# debugId=2DC8BF43EDAF27E364756E2164756E21