@_davideast/stitch-mcp 0.5.3 → 0.5.5

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.
Files changed (78) hide show
  1. package/dist/chunk-18nfnnkg.js +947 -0
  2. package/dist/chunk-18nfnnkg.js.map +28 -0
  3. package/dist/chunk-1sgyj1qf.js +256 -0
  4. package/dist/chunk-1sgyj1qf.js.map +11 -0
  5. package/dist/chunk-1tzaa3zn.js +370 -0
  6. package/dist/chunk-1tzaa3zn.js.map +16 -0
  7. package/dist/chunk-2efzz3tw.js +10 -0
  8. package/dist/chunk-2efzz3tw.js.map +9 -0
  9. package/dist/chunk-2eq8thmz.js +31529 -0
  10. package/dist/chunk-2eq8thmz.js.map +245 -0
  11. package/dist/chunk-4xa2a5hb.js +19 -0
  12. package/dist/chunk-4xa2a5hb.js.map +9 -0
  13. package/dist/chunk-7vdj1qwb.js +2121 -0
  14. package/dist/chunk-7vdj1qwb.js.map +44 -0
  15. package/dist/chunk-7zyv8g2t.js +5216 -0
  16. package/dist/chunk-7zyv8g2t.js.map +67 -0
  17. package/dist/chunk-94xqpnv4.js +7 -0
  18. package/dist/chunk-94xqpnv4.js.map +9 -0
  19. package/dist/chunk-b43pzs3z.js +839 -0
  20. package/dist/chunk-b43pzs3z.js.map +11 -0
  21. package/dist/chunk-byzfppa1.js +759 -0
  22. package/dist/chunk-byzfppa1.js.map +19 -0
  23. package/dist/chunk-cjkw69md.js +94 -0
  24. package/dist/chunk-cjkw69md.js.map +10 -0
  25. package/dist/chunk-d92ngrr6.js +680 -0
  26. package/dist/chunk-d92ngrr6.js.map +17 -0
  27. package/dist/chunk-de74byjc.js +19 -0
  28. package/dist/chunk-de74byjc.js.map +9 -0
  29. package/dist/chunk-ewab4gg0.js +17 -0
  30. package/dist/chunk-ewab4gg0.js.map +9 -0
  31. package/dist/chunk-f0phn3y1.js +1495 -0
  32. package/dist/chunk-f0phn3y1.js.map +23 -0
  33. package/dist/chunk-f398cwqb.js +24 -0
  34. package/dist/chunk-f398cwqb.js.map +9 -0
  35. package/dist/chunk-fkzq5m59.js +111 -0
  36. package/dist/chunk-fkzq5m59.js.map +10 -0
  37. package/dist/chunk-gzk8pt16.js +44184 -0
  38. package/dist/chunk-gzk8pt16.js.map +237 -0
  39. package/dist/chunk-kme6y874.js +125 -0
  40. package/dist/chunk-kme6y874.js.map +12 -0
  41. package/dist/chunk-mw5wn97e.js +109 -0
  42. package/dist/chunk-mw5wn97e.js.map +10 -0
  43. package/dist/chunk-mxcybqhd.js +412 -0
  44. package/dist/chunk-mxcybqhd.js.map +20 -0
  45. package/dist/chunk-nep9nerg.js +137 -0
  46. package/dist/chunk-nep9nerg.js.map +10 -0
  47. package/dist/chunk-nrcb494d.js +50 -0
  48. package/dist/chunk-nrcb494d.js.map +9 -0
  49. package/dist/chunk-p9vvygz4.js +736 -0
  50. package/dist/chunk-p9vvygz4.js.map +16 -0
  51. package/dist/chunk-rd2ye9s7.js +17 -0
  52. package/dist/chunk-rd2ye9s7.js.map +9 -0
  53. package/dist/chunk-svk5y62j.js +164 -0
  54. package/dist/chunk-svk5y62j.js.map +10 -0
  55. package/dist/chunk-w3wh3zkf.js +269 -0
  56. package/dist/chunk-w3wh3zkf.js.map +10 -0
  57. package/dist/chunk-x1tt02n9.js +264 -0
  58. package/dist/chunk-x1tt02n9.js.map +12 -0
  59. package/dist/chunk-x7g5p1gv.js +66 -0
  60. package/dist/chunk-x7g5p1gv.js.map +10 -0
  61. package/dist/chunk-z7b1n864.js +246 -0
  62. package/dist/chunk-z7b1n864.js.map +14 -0
  63. package/dist/chunk-zcc6seqb.js +19132 -0
  64. package/dist/chunk-zcc6seqb.js.map +115 -0
  65. package/dist/commands/doctor/command.js +1 -1
  66. package/dist/commands/init/command.js +1 -1
  67. package/dist/commands/logout/command.js +1 -1
  68. package/dist/commands/proxy/command.js +1 -1
  69. package/dist/commands/screens/command.js +4 -4
  70. package/dist/commands/serve/command.js +5 -5
  71. package/dist/commands/site/command.js +1 -1
  72. package/dist/commands/snapshot/command.js +1 -1
  73. package/dist/commands/tool/command.js +1 -1
  74. package/dist/commands/view/command.js +1 -1
  75. package/dist/index.js +5 -7
  76. package/dist/index.js.map +1 -1
  77. package/dist/ui/copy-behaviors/clipboard.d.ts +0 -7
  78. package/package.json +1 -3
@@ -0,0 +1,736 @@
1
+ import {
2
+ openUrl,
3
+ require_jsx_dev_runtime
4
+ } from "./chunk-x1tt02n9.js";
5
+ import {
6
+ StitchViteServer
7
+ } from "./chunk-gzk8pt16.js";
8
+ import {
9
+ require_lib
10
+ } from "./chunk-7vdj1qwb.js";
11
+ import {
12
+ Box_default,
13
+ Text,
14
+ use_app_default,
15
+ use_input_default,
16
+ use_stdout_default
17
+ } from "./chunk-zcc6seqb.js";
18
+ import {
19
+ require_react
20
+ } from "./chunk-b43pzs3z.js";
21
+ import {
22
+ fetchWithRetry
23
+ } from "./chunk-6gw9apqb.js";
24
+ import {
25
+ pLimit
26
+ } from "./chunk-a5xra9jn.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=BA12672C2AC4B82664756E2164756E21