@openspecui/web 3.2.1 → 3.2.3

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 (69) hide show
  1. package/dist/assets/CanvasRenderer-D34NqoCB.js +1 -0
  2. package/dist/assets/WebGLRenderer-CYPUFKPG.js +1 -0
  3. package/dist/assets/WebGPURenderer-CGvE0uq_.js +1 -0
  4. package/dist/assets/browserAll-CHRMQEq7.js +1 -0
  5. package/dist/assets/{dist-WL830Xdr.js → dist--uPg93e1.js} +1 -1
  6. package/dist/assets/{dist-Bx_btjfU.js → dist-BPXk6_Po.js} +1 -1
  7. package/dist/assets/{dist--kJS10K4.js → dist-BZHNw6Xc.js} +1 -1
  8. package/dist/assets/dist-Bti1qyw6.js +1 -0
  9. package/dist/assets/{dist-B4Ej2z5p.js → dist-C7cinWvX.js} +1 -1
  10. package/dist/assets/dist-CLiygKv9.js +1 -0
  11. package/dist/assets/dist-CMq7FB-3.js +1 -0
  12. package/dist/assets/{dist-T8yPt5qM.js → dist-CNVRpEmF.js} +1 -1
  13. package/dist/assets/{dist-DedlS1Fr.js → dist-DnbAXUOP.js} +1 -1
  14. package/dist/assets/{dist-CAemHNFv.js → dist-GC7ATPFK.js} +1 -1
  15. package/dist/assets/{dist-Cc4rhz0Q.js → dist-TqyjDo7w.js} +1 -1
  16. package/dist/assets/{dist-ClrYUZj0.js → dist-wjxhg6v3.js} +1 -1
  17. package/dist/assets/{ghostty-web-DVokbZ5P.js → ghostty-web-Dp0tZ6to.js} +1 -1
  18. package/dist/assets/{index-CEq1CSkJ.js → index-BFC8XdGW.js} +115 -122
  19. package/dist/assets/index-qPEQ3Vl6.css +1 -0
  20. package/dist/assets/{init-DxNnipqM.js → init-D9aT2ndj.js} +1 -1
  21. package/dist/assets/trpc-CmIYQbpn.js +1 -0
  22. package/dist/assets/webworkerAll-Bd4-UhgY.js +1 -0
  23. package/dist/index.html +2 -2
  24. package/dist-ssg/client/.vite/ssr-manifest.json +21 -15
  25. package/dist-ssg/client/assets/CanvasRenderer-CahUFf9y.js +1 -0
  26. package/dist-ssg/client/assets/WebGLRenderer-DjfMr_ss.js +1 -0
  27. package/dist-ssg/client/assets/WebGPURenderer-6FoKSIBM.js +1 -0
  28. package/dist-ssg/client/assets/browserAll-rZ7Jxk9e.js +1 -0
  29. package/dist-ssg/client/assets/{dist-Bo53fF5A.js → dist-AFOgdma0.js} +1 -1
  30. package/dist-ssg/client/assets/{dist-QmTcnYGP.js → dist-BOM2m0Gs.js} +1 -1
  31. package/dist-ssg/client/assets/{dist-o5b4RTXe.js → dist-BPJmjpCG.js} +1 -1
  32. package/dist-ssg/client/assets/{dist-D92F7LaW.js → dist-BS1KQU3Q.js} +1 -1
  33. package/dist-ssg/client/assets/{dist-CdX5HK1b.js → dist-BnszlMrK.js} +1 -1
  34. package/dist-ssg/client/assets/{dist-B3BgKjHS.js → dist-CPzxrSXa.js} +1 -1
  35. package/dist-ssg/client/assets/{dist-BpX6HcAh.js → dist-Cd8gsVBM.js} +1 -1
  36. package/dist-ssg/client/assets/{dist-gh87xRoS.js → dist-CkubSHKl.js} +1 -1
  37. package/dist-ssg/client/assets/{dist-BatiVkVi.js → dist-DI25ZjyS.js} +1 -1
  38. package/dist-ssg/client/assets/dist-DJ2qr7pV.js +1 -0
  39. package/dist-ssg/client/assets/dist-DMIlnYL2.js +1 -0
  40. package/dist-ssg/client/assets/dist-d3NYpDgq.js +1 -0
  41. package/dist-ssg/client/assets/{ghostty-web-BfPjk5-h.js → ghostty-web-DtxkIF2P.js} +1 -1
  42. package/dist-ssg/client/assets/index-1iktuOBr.css +2 -0
  43. package/dist-ssg/client/assets/{index.ssg-wxGG39Ri.js → index.ssg-CbuuWCxB.js} +106 -113
  44. package/dist-ssg/client/assets/{init-DnDCMdRA.js → init-DsPXu-RV.js} +1 -1
  45. package/dist-ssg/client/assets/trpc-B08uEHF8.js +1 -0
  46. package/dist-ssg/client/assets/webworkerAll-QQ5uvKva.js +1 -0
  47. package/dist-ssg/client/index.ssg.html +2 -2
  48. package/dist-ssg/server/entry-server.js +744 -558
  49. package/package.json +1 -1
  50. package/dist/assets/CanvasRenderer-DaAtcSpJ.js +0 -1
  51. package/dist/assets/WebGLRenderer-Dw9u4T-1.js +0 -1
  52. package/dist/assets/WebGPURenderer-DZLDcYus.js +0 -1
  53. package/dist/assets/browserAll-DHDY4Lag.js +0 -1
  54. package/dist/assets/dist-Bg53DwSg.js +0 -1
  55. package/dist/assets/dist-CBdQjXWm.js +0 -1
  56. package/dist/assets/dist-CcMtrYGd.js +0 -1
  57. package/dist/assets/index-BIMvgiBn.css +0 -1
  58. package/dist/assets/trpc-BdFwCFp0.js +0 -1
  59. package/dist/assets/webworkerAll-B77YQ4kV.js +0 -1
  60. package/dist-ssg/client/assets/CanvasRenderer-DQhD3mh1.js +0 -1
  61. package/dist-ssg/client/assets/WebGLRenderer-BiZDXqzp.js +0 -1
  62. package/dist-ssg/client/assets/WebGPURenderer-D1nI-2Sp.js +0 -1
  63. package/dist-ssg/client/assets/browserAll-BHwk3te6.js +0 -1
  64. package/dist-ssg/client/assets/dist-BbQ3gKhT.js +0 -1
  65. package/dist-ssg/client/assets/dist-ByDVQI3O.js +0 -1
  66. package/dist-ssg/client/assets/dist-De4GFj_M.js +0 -1
  67. package/dist-ssg/client/assets/index-nIC438iN.css +0 -2
  68. package/dist-ssg/client/assets/trpc-JLvkwF5N.js +0 -1
  69. package/dist-ssg/client/assets/webworkerAll-VgzZQ1wt.js +0 -1
@@ -7433,7 +7433,7 @@ function useSearch(opts) {
7433
7433
  }
7434
7434
  //#endregion
7435
7435
  //#region ../../node_modules/.pnpm/@tanstack+react-router@1.139.3_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/@tanstack/react-router/dist/esm/utils.js
7436
- var useLayoutEffect$7 = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
7436
+ var useLayoutEffect$8 = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
7437
7437
  function usePrevious(value) {
7438
7438
  const ref = import_react.useRef({
7439
7439
  value,
@@ -8353,7 +8353,7 @@ function Transitioner() {
8353
8353
  unsub();
8354
8354
  };
8355
8355
  }, [router, router.history]);
8356
- useLayoutEffect$7(() => {
8356
+ useLayoutEffect$8(() => {
8357
8357
  if (typeof window !== "undefined" && router.ssr || mountLoadForRouter.current.router === router && mountLoadForRouter.current.mounted) return;
8358
8358
  mountLoadForRouter.current = {
8359
8359
  router,
@@ -8368,7 +8368,7 @@ function Transitioner() {
8368
8368
  };
8369
8369
  tryLoad();
8370
8370
  }, [router]);
8371
- useLayoutEffect$7(() => {
8371
+ useLayoutEffect$8(() => {
8372
8372
  if (previousIsLoading && !isLoading) router.emit({
8373
8373
  type: "onLoad",
8374
8374
  ...getLocationChangeInfo(router.state)
@@ -8378,7 +8378,7 @@ function Transitioner() {
8378
8378
  router,
8379
8379
  isLoading
8380
8380
  ]);
8381
- useLayoutEffect$7(() => {
8381
+ useLayoutEffect$8(() => {
8382
8382
  if (previousIsPagePending && !isPagePending) router.emit({
8383
8383
  type: "onBeforeRouteMount",
8384
8384
  ...getLocationChangeInfo(router.state)
@@ -8388,7 +8388,7 @@ function Transitioner() {
8388
8388
  previousIsPagePending,
8389
8389
  router
8390
8390
  ]);
8391
- useLayoutEffect$7(() => {
8391
+ useLayoutEffect$8(() => {
8392
8392
  if (previousIsAnyPending && !isAnyPending) {
8393
8393
  const changeInfo = getLocationChangeInfo(router.state);
8394
8394
  router.emit({
@@ -84161,15 +84161,6 @@ var tabsStyleText = (id) => {
84161
84161
  transform: scaleX(0.5);
84162
84162
  }
84163
84163
 
84164
- #${id}[data-tabs-strip-decoration='on'] .tabs-strip {
84165
- background-image: linear-gradient(
84166
- to bottom,
84167
- transparent,
84168
- transparent calc(100% - 1px),
84169
- var(--border) calc(100% - 1px),
84170
- var(--border)
84171
- );
84172
- }
84173
84164
  `;
84174
84165
  };
84175
84166
  function buildReorderedTabIds(currentTabIds, draggedTabId, targetTabId, position) {
@@ -84192,7 +84183,7 @@ function buildStableContentTabIds(previousTabIds, currentTabIds) {
84192
84183
  * Hidden tabs are pre-rendered at lower priority and preserve their state.
84193
84184
  * Supports both controlled and uncontrolled active tab.
84194
84185
  */
84195
- function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTabOrderChange, actions, onTabBarDoubleClick, className = "", classNames, showHeaderShell = true, showSelectionIndicator = true, decorateStrip = true }, ref) {
84186
+ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTabOrderChange, actions, onTabBarDoubleClick, className = "", classNames, showHeaderShell = true, showSelectionIndicator = true, decorateStrip = true, selectionIndicatorLayout = "underline" }, ref) {
84196
84187
  const [uncontrolled, setUncontrolled] = (0, import_react.useState)(tabs[0]?.id ?? "");
84197
84188
  const [dropIndicator, setDropIndicator] = (0, import_react.useState)(null);
84198
84189
  const dropIndicatorRef = (0, import_react.useRef)(null);
@@ -84201,6 +84192,8 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84201
84192
  const headerRef = (0, import_react.useRef)(null);
84202
84193
  const headerShellRef = (0, import_react.useRef)(null);
84203
84194
  const headerForegroundRef = (0, import_react.useRef)(null);
84195
+ const headerFrameRef = (0, import_react.useRef)(null);
84196
+ const stripRef = (0, import_react.useRef)(null);
84204
84197
  const selectionIndicatorRef = (0, import_react.useRef)(null);
84205
84198
  const tabsButtonRef = (0, import_react.useRef)(null);
84206
84199
  const triggerRefs = (0, import_react.useRef)(/* @__PURE__ */ new Map());
@@ -84229,7 +84222,7 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84229
84222
  return panelRefs.current.get(tabId) ?? null;
84230
84223
  },
84231
84224
  getHeaderShell() {
84232
- return headerShellRef.current;
84225
+ return headerShellRef.current ?? stripRef.current;
84233
84226
  },
84234
84227
  getHeaderForeground() {
84235
84228
  return headerForegroundRef.current;
@@ -84243,23 +84236,39 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84243
84236
  }), [activeTab]);
84244
84237
  const syncSelectionIndicator = (0, import_react.useCallback)(() => {
84245
84238
  const indicator = selectionIndicatorRef.current;
84246
- const header = headerRef.current;
84239
+ const strip = stripRef.current ?? headerFrameRef.current;
84247
84240
  const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
84248
84241
  if (!indicator) return;
84249
- if (!showSelectionIndicator || !header || !activeTrigger) {
84242
+ if (!showSelectionIndicator || !strip || !activeTrigger) {
84250
84243
  indicator.style.opacity = "0";
84251
84244
  indicator.style.width = "0px";
84252
- indicator.style.height = "0px";
84253
- indicator.style.transform = "translate(0px, 0px)";
84245
+ indicator.style.height = selectionIndicatorLayout === "overlay" ? "0px" : "";
84246
+ indicator.style.transform = selectionIndicatorLayout === "overlay" ? "translate(0px, 0px)" : "translateX(0px)";
84254
84247
  return;
84255
84248
  }
84256
- const headerRect = header.getBoundingClientRect();
84249
+ const stripRect = strip.getBoundingClientRect();
84257
84250
  const triggerRect = activeTrigger.getBoundingClientRect();
84251
+ if (selectionIndicatorLayout === "underline") {
84252
+ const indicatorStyle = getComputedStyle(indicator);
84253
+ const inlineInset = parseFloat(indicatorStyle.getPropertyValue("--tabs-selection-inline-inset")) || 10;
84254
+ const minWidth = parseFloat(indicatorStyle.getPropertyValue("--tabs-selection-min-width")) || 40;
84255
+ const width = Math.max(minWidth, triggerRect.width - inlineInset * 2);
84256
+ const translateX = triggerRect.left - stripRect.left + (triggerRect.width - width) / 2;
84257
+ indicator.style.opacity = "1";
84258
+ indicator.style.width = `${width}px`;
84259
+ indicator.style.height = "";
84260
+ indicator.style.transform = `translateX(${translateX}px)`;
84261
+ return;
84262
+ }
84258
84263
  indicator.style.opacity = "1";
84259
84264
  indicator.style.width = `${triggerRect.width}px`;
84260
- indicator.style.height = `${triggerRect.height}px`;
84261
- indicator.style.transform = `translate(${triggerRect.left - headerRect.left}px, ${triggerRect.top - headerRect.top}px)`;
84262
- }, [activeTab, showSelectionIndicator]);
84265
+ indicator.style.height = `${triggerRect.height + 1}px`;
84266
+ indicator.style.transform = `translate(${triggerRect.left - stripRect.left}px, ${triggerRect.top - stripRect.top}px)`;
84267
+ }, [
84268
+ activeTab,
84269
+ selectionIndicatorLayout,
84270
+ showSelectionIndicator
84271
+ ]);
84263
84272
  (0, import_react.useLayoutEffect)(() => {
84264
84273
  syncSelectionIndicator();
84265
84274
  }, [syncSelectionIndicator, tabLayoutSignature]);
@@ -84279,6 +84288,8 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84279
84288
  });
84280
84289
  observer.observe(tabsButton);
84281
84290
  if (headerRef.current) observer.observe(headerRef.current);
84291
+ if (stripRef.current) observer.observe(stripRef.current);
84292
+ if (headerFrameRef.current) observer.observe(headerFrameRef.current);
84282
84293
  const activeTrigger = activeTab ? triggerRefs.current.get(activeTab) : null;
84283
84294
  if (activeTrigger) observer.observe(activeTrigger);
84284
84295
  return () => {
@@ -84371,18 +84382,22 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84371
84382
  }, [reorderable]);
84372
84383
  if (tabs.length === 0) return null;
84373
84384
  const headerClassName = cn$1("tabs-header relative sticky top-0 z-20 flex min-w-0 items-stretch", classNames?.header);
84374
- const headerShellClassName = cn$1("tabs-header-shell bg-card/95 pointer-events-none absolute inset-0 z-0 rounded-md border border-zinc-500/15 shadow-[inset_0_-1px_0_color-mix(in_srgb,var(--border)_85%,transparent)] backdrop-blur-sm", classNames?.headerShell);
84375
- const headerForegroundClassName = cn$1("tabs-header-foreground relative z-20 flex min-w-0 items-stretch", classNames?.headerForeground);
84376
- const stripClassName = cn$1("tabs-strip flex min-w-0 flex-1 items-stretch rounded-l-md px-4", classNames?.strip);
84385
+ const headerShellClassName = cn$1(selectionIndicatorLayout === "underline" ? "tabs-header-shell bg-card/95 pointer-events-none absolute inset-0 z-0 rounded-t-md rounded-b-none border border-b-0 border-zinc-500/15 backdrop-blur-sm" : "tabs-header-shell bg-card/95 pointer-events-none absolute inset-0 z-0 rounded-md border border-zinc-500/15 shadow-[inset_0_-1px_0_color-mix(in_srgb,var(--border)_85%,transparent)] backdrop-blur-sm", classNames?.headerShell);
84386
+ const headerForegroundClassName = cn$1("tabs-header-foreground relative z-20 flex min-w-0 flex-1", classNames?.headerForeground);
84387
+ const headerFrameClassName = cn$1("tabs-header-frame relative flex min-w-0 flex-1 items-stretch", classNames?.headerFrame);
84388
+ const stripClassName = cn$1("tabs-strip relative flex min-w-0 flex-1 items-stretch px-4", classNames?.strip);
84377
84389
  const listClassName = cn$1("tabs-button scrollbar-none flex min-w-0 flex-1 gap-1 overflow-x-auto", classNames?.list);
84378
84390
  const buttonBaseClassName = cn$1("group relative z-10 m-0 flex h-full shrink-0 px-2 py-2 text-sm font-medium transition-colors", classNames?.buttonBase);
84379
84391
  const buttonInnerClassName = cn$1("inline-flex h-full items-center gap-2", classNames?.buttonInner);
84380
84392
  const activeButtonClassName = cn$1("tab-selected text-foreground", classNames?.activeButton);
84381
- const inactiveButtonClassName = cn$1("text-muted-foreground hover:bg-background/35 hover:text-foreground", classNames?.inactiveButton);
84393
+ const inactiveButtonClassName = cn$1("text-muted-foreground hover:text-foreground", classNames?.inactiveButton);
84382
84394
  const activeButtonInnerClassName = cn$1(classNames?.activeButtonInner);
84383
84395
  const inactiveButtonInnerClassName = cn$1(classNames?.inactiveButtonInner);
84384
- const actionsClassName = cn$1("tabs-actions border-zinc-500/15 flex shrink-0 items-center rounded-r-md border-l px-1 h-full", classNames?.actions);
84385
- const selectionIndicatorClassName = cn$1("tabs-selection-indicator border-primary bg-background/70 duration-280 absolute left-0 top-0 border-b-4 opacity-0 transition-[transform,width,height,opacity] ease-[cubic-bezier(0.22,1,0.36,1)]", classNames?.selectionIndicator);
84396
+ const actionsClassName = cn$1("tabs-actions relative flex shrink-0 items-center px-1", classNames?.actions);
84397
+ const actionsDividerClassName = cn$1("tabs-actions-divider bg-border/60 absolute inset-y-0 left-0 w-px", classNames?.actionsDivider);
84398
+ const selectionTrackClassName = cn$1("tabs-selection-track bg-border/85 pointer-events-none absolute inset-x-0 bottom-0 h-px", classNames?.selectionTrack);
84399
+ const selectionIndicatorViewportClassName = cn$1(selectionIndicatorLayout === "underline" ? "pointer-events-none absolute inset-x-0 top-0 bottom-[-1px] z-10 overflow-hidden" : "pointer-events-none absolute inset-0 z-10 overflow-hidden", classNames?.selectionIndicatorViewport);
84400
+ const selectionIndicatorClassName = cn$1(selectionIndicatorLayout === "underline" ? "tabs-selection-indicator absolute bottom-0 left-0 h-[3px] rounded-full bg-primary opacity-0 transition-[transform,width,opacity] duration-280 ease-[cubic-bezier(0.22,1,0.36,1)] [--tabs-selection-inline-inset:10px] [--tabs-selection-min-width:40px]" : "tabs-selection-indicator border-primary bg-background/70 duration-280 absolute left-0 top-0 border-b opacity-0 transition-[transform,width,height,opacity] ease-[cubic-bezier(0.22,1,0.36,1)]", classNames?.selectionIndicator);
84386
84401
  const handleTabBarDoubleClick = (event) => {
84387
84402
  if (!onTabBarDoubleClick) return;
84388
84403
  if (event.target.closest("[data-tab-item=\"true\"]")) return;
@@ -84439,42 +84454,53 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84439
84454
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84440
84455
  ref: headerRef,
84441
84456
  className: headerClassName,
84442
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
84443
- showHeaderShell && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84444
- ref: headerShellRef,
84445
- "data-tabs-header-shell": "true",
84446
- className: headerShellClassName
84447
- }),
84448
- showSelectionIndicator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84449
- className: "pointer-events-none absolute inset-0 z-10",
84450
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84451
- ref: selectionIndicatorRef,
84452
- "data-tabs-selection-indicator": "true",
84453
- "aria-hidden": "true",
84454
- className: selectionIndicatorClassName
84455
- })
84456
- }),
84457
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
84458
- ref: headerForegroundRef,
84459
- "data-tabs-header-foreground": "true",
84460
- className: headerForegroundClassName,
84461
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84462
- className: stripClassName,
84463
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84464
- ref: tabsButtonRef,
84465
- className: listClassName,
84466
- onDoubleClick: handleTabBarDoubleClick,
84467
- onDragOver: handleListDragOver,
84468
- onDrop: handleListDrop,
84469
- children: tabButtons
84457
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [showHeaderShell && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84458
+ ref: headerShellRef,
84459
+ "data-tabs-header-shell": "true",
84460
+ className: headerShellClassName
84461
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84462
+ ref: headerForegroundRef,
84463
+ "data-tabs-header-foreground": "true",
84464
+ className: headerForegroundClassName,
84465
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
84466
+ ref: headerFrameRef,
84467
+ className: headerFrameClassName,
84468
+ children: [
84469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
84470
+ ref: stripRef,
84471
+ className: stripClassName,
84472
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84473
+ ref: tabsButtonRef,
84474
+ className: listClassName,
84475
+ onDoubleClick: handleTabBarDoubleClick,
84476
+ onDragOver: handleListDragOver,
84477
+ onDrop: handleListDrop,
84478
+ children: tabButtons
84479
+ }), showSelectionIndicator && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84480
+ className: selectionIndicatorViewportClassName,
84481
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84482
+ ref: selectionIndicatorRef,
84483
+ "data-tabs-selection-indicator": "true",
84484
+ "aria-hidden": "true",
84485
+ className: selectionIndicatorClassName
84486
+ })
84487
+ })]
84488
+ }),
84489
+ actions && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
84490
+ "data-tabs-actions": "true",
84491
+ className: actionsClassName,
84492
+ children: [decorateStrip && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84493
+ "aria-hidden": "true",
84494
+ className: actionsDividerClassName
84495
+ }), actions]
84496
+ }),
84497
+ decorateStrip && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84498
+ "aria-hidden": "true",
84499
+ className: selectionTrackClassName
84470
84500
  })
84471
- }), actions && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84472
- "data-tabs-actions": "true",
84473
- className: actionsClassName,
84474
- children: actions
84475
- })]
84501
+ ]
84476
84502
  })
84477
- ] })
84503
+ })] })
84478
84504
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
84479
84505
  className: "relative flex min-h-0 flex-1 overflow-hidden",
84480
84506
  children: contentTabs.map((tab) => tab.unmountOnHide ? activeTab === tab.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
@@ -84500,6 +84526,14 @@ function TabsImpl({ tabs, selectedTab: controlled, onTabChange, onTabClose, onTa
84500
84526
  }
84501
84527
  var Tabs = (0, import_react.forwardRef)(TabsImpl);
84502
84528
  //#endregion
84529
+ //#region src/lib/view-transitions/tab-direction.ts
84530
+ function resolveTabCarouselDirection(tabs, currentTabId, nextTabId) {
84531
+ const currentIndex = tabs.findIndex((tab) => tab.id === currentTabId);
84532
+ const nextIndex = tabs.findIndex((tab) => tab.id === nextTabId);
84533
+ if (currentIndex < 0 || nextIndex < 0 || currentIndex === nextIndex) return null;
84534
+ return nextIndex > currentIndex ? "forward" : "backward";
84535
+ }
84536
+ //#endregion
84503
84537
  //#region src/lib/view-transitions/tab-scroll-freeze.ts
84504
84538
  var DATA_VISIBLE_HEIGHT = "tabVisibleHeight";
84505
84539
  var DATA_TOP_INSET = "tabTopInset";
@@ -84554,7 +84588,7 @@ function restoreViewportScroll(viewport, panel, targetScrollTop) {
84554
84588
  };
84555
84589
  requestAnimationFrame(retry);
84556
84590
  }
84557
- function hasVerticalScrollBehavior(overflowY) {
84591
+ function hasVerticalScrollBehavior$1(overflowY) {
84558
84592
  return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
84559
84593
  }
84560
84594
  function findScrollableDescendant(panel) {
@@ -84563,7 +84597,7 @@ function findScrollableDescendant(panel) {
84563
84597
  while (walker.nextNode()) {
84564
84598
  const node = walker.currentNode;
84565
84599
  if (!(node instanceof HTMLElement)) continue;
84566
- if (!hasVerticalScrollBehavior(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
84600
+ if (!hasVerticalScrollBehavior$1(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
84567
84601
  if (node.scrollTop > 0) return node;
84568
84602
  candidate ??= node;
84569
84603
  }
@@ -84646,12 +84680,12 @@ function resolveViewportBoundary(panel, viewportSelector) {
84646
84680
  function resolveScrollViewport(panel, boundary) {
84647
84681
  let current = panel.parentElement;
84648
84682
  while (current) {
84649
- if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY) && current.scrollHeight > current.clientHeight) return current;
84683
+ if (hasVerticalScrollBehavior$1(window.getComputedStyle(current).overflowY) && current.scrollHeight > current.clientHeight) return current;
84650
84684
  if (boundary && current === boundary) break;
84651
84685
  current = current.parentElement;
84652
84686
  }
84653
84687
  if (!boundary) return null;
84654
- if (hasVerticalScrollBehavior(window.getComputedStyle(boundary).overflowY)) return boundary;
84688
+ if (hasVerticalScrollBehavior$1(window.getComputedStyle(boundary).overflowY)) return boundary;
84655
84689
  return null;
84656
84690
  }
84657
84691
  function resolveTabScrollElements(handle, tabId, viewportSelector) {
@@ -85011,11 +85045,16 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
85011
85045
  commitSelection();
85012
85046
  return;
85013
85047
  }
85048
+ const direction = resolveTabCarouselDirection(latestTabs, currentTab, nextTabId);
85049
+ if (!direction) {
85050
+ commitSelection();
85051
+ return;
85052
+ }
85014
85053
  runViewTransition({
85015
85054
  intent: {
85016
85055
  area: resolveTabArea(latestLocation.pathname, latestArea),
85017
85056
  kind: "tab-carousel",
85018
- direction: "forward"
85057
+ direction
85019
85058
  },
85020
85059
  collectBeforeEntries: () => collectTabEntries(tabsRef.current, currentTab),
85021
85060
  collectAfterEntries: () => collectTabEntries(tabsRef.current, nextTabId),
@@ -85023,7 +85062,8 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
85023
85062
  });
85024
85063
  return;
85025
85064
  }
85026
- const runSelectionWithScrollTransfer = (animated) => {
85065
+ const direction = resolveTabCarouselDirection(latestTabs, currentTab, nextTabId);
85066
+ const runSelectionWithScrollTransfer = (animated, direction) => {
85027
85067
  const outgoingSnapshot = captureTabSnapshot(currentTab, latestViewportSelector);
85028
85068
  const incomingSeedSnapshot = scrollMemoryByTabRef.current.get(nextTabId) ?? outgoingSnapshot ?? captureTabSnapshot(nextTabId, latestViewportSelector);
85029
85069
  const outgoingToken = captureOutgoingTab(currentTab, latestViewportSelector, outgoingSnapshot);
@@ -85059,14 +85099,11 @@ function useRoutedCarouselTabs({ queryKey, tabs, initialTab, area, history = "re
85059
85099
  runSelectionWithScrollTransfer(false);
85060
85100
  return;
85061
85101
  }
85062
- const currentIndex = latestTabs.findIndex((tab) => tab.id === currentTab);
85063
- const nextIndex = latestTabs.findIndex((tab) => tab.id === nextTabId);
85064
- if (currentIndex < 0 || nextIndex < 0) {
85102
+ if (!direction) {
85065
85103
  runSelectionWithScrollTransfer(false);
85066
85104
  return;
85067
85105
  }
85068
- const direction = nextIndex >= currentIndex ? "forward" : "backward";
85069
- runSelectionWithScrollTransfer(true);
85106
+ runSelectionWithScrollTransfer(true, direction);
85070
85107
  }, [
85071
85108
  captureOutgoingTab,
85072
85109
  captureTabSnapshot,
@@ -102317,7 +102354,7 @@ function CodeEditor({ value, onChange, readOnly = false, language, filename, lin
102317
102354
  bracketMatching: !readOnly
102318
102355
  },
102319
102356
  extensions,
102320
- className: `scrollbar-thin scrollbar-track-transparent overflow-auto ${className}`,
102357
+ className: `min-h-0 overflow-hidden ${className}`,
102321
102358
  style: {
102322
102359
  fontSize,
102323
102360
  ["--code-editor-min-height"]: editorMinHeight,
@@ -102625,6 +102662,7 @@ var layoutStyles = String.raw`
102625
102662
  display: flex;
102626
102663
  flex-direction: column;
102627
102664
  flex: 1;
102665
+ min-height: 0;
102628
102666
  }
102629
102667
 
102630
102668
  /* 宽屏:grid 布局,文件列表在右侧 */
@@ -102633,6 +102671,7 @@ var layoutStyles = String.raw`
102633
102671
  display: grid;
102634
102672
  grid-template-columns: minmax(0, 1fr) minmax(240px, clamp(240px, 30%, 420px));
102635
102673
  gap: 1rem;
102674
+ min-height: 0;
102636
102675
  }
102637
102676
  .fev-sidebar-tabs {
102638
102677
  display: none;
@@ -102937,21 +102976,110 @@ function FileExplorer({ entries, selectedPath, onSelect, breadcrumbRoot, headerL
102937
102976
  })]
102938
102977
  });
102939
102978
  }
102940
- function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWrapping }) {
102979
+ function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWrapping, editorMinHeight }) {
102941
102980
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
102942
102981
  value,
102943
102982
  filename: file.path,
102944
102983
  readOnly,
102945
102984
  lineWrapping,
102946
102985
  className: "min-h-0 flex-1",
102986
+ editorMinHeight,
102947
102987
  onChange
102948
102988
  }, file.path);
102949
102989
  }
102950
102990
  //#endregion
102991
+ //#region src/components/scroll-spy.ts
102992
+ function hasVerticalScrollBehavior(overflowY) {
102993
+ return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
102994
+ }
102995
+ function findVerticalScrollContainer(node, options = {}) {
102996
+ const { allowNonScrollable = false } = options;
102997
+ let current = node?.parentElement ?? null;
102998
+ while (current) {
102999
+ if (hasVerticalScrollBehavior(window.getComputedStyle(current).overflowY)) {
103000
+ if (allowNonScrollable || current.scrollHeight > current.clientHeight) return current;
103001
+ }
103002
+ current = current.parentElement;
103003
+ }
103004
+ return null;
103005
+ }
103006
+ function scrollViewportBounds(root) {
103007
+ if (root) {
103008
+ const rect = root.getBoundingClientRect();
103009
+ return {
103010
+ top: rect.top,
103011
+ bottom: rect.bottom
103012
+ };
103013
+ }
103014
+ return {
103015
+ top: 0,
103016
+ bottom: window.innerHeight
103017
+ };
103018
+ }
103019
+ function measureAvailableViewportHeight(node, root = findVerticalScrollContainer(node, { allowNonScrollable: true })) {
103020
+ if (typeof window === "undefined" || !node) return null;
103021
+ const nodeRect = node.getBoundingClientRect();
103022
+ const viewport = scrollViewportBounds(root);
103023
+ return Math.max(Math.floor(viewport.bottom - Math.max(nodeRect.top, viewport.top)), 0);
103024
+ }
103025
+ function useViewportConstrainedHeight({ target, enabled = true }) {
103026
+ const [height, setHeight] = (0, import_react.useState)(null);
103027
+ (0, import_react.useLayoutEffect)(() => {
103028
+ if (!enabled || typeof window === "undefined") {
103029
+ setHeight(null);
103030
+ return;
103031
+ }
103032
+ if (!target) {
103033
+ setHeight(null);
103034
+ return;
103035
+ }
103036
+ let resizeObserver = null;
103037
+ let scrollRoot = null;
103038
+ let scrollTarget = window;
103039
+ const setConstrainedHeight = (nextHeight) => {
103040
+ setHeight((currentHeight) => currentHeight === nextHeight ? currentHeight : nextHeight);
103041
+ };
103042
+ const bindScrollRoot = (nextRoot) => {
103043
+ if (scrollRoot === nextRoot) return;
103044
+ scrollTarget.removeEventListener("scroll", handleUpdate);
103045
+ if (resizeObserver && scrollRoot) resizeObserver.unobserve(scrollRoot);
103046
+ scrollRoot = nextRoot;
103047
+ scrollTarget = nextRoot ?? window;
103048
+ scrollTarget.addEventListener("scroll", handleUpdate, { passive: true });
103049
+ if (resizeObserver && scrollRoot) resizeObserver.observe(scrollRoot);
103050
+ };
103051
+ const handleUpdate = () => {
103052
+ const nextRoot = findVerticalScrollContainer(target, { allowNonScrollable: true });
103053
+ bindScrollRoot(nextRoot);
103054
+ setConstrainedHeight(measureAvailableViewportHeight(target, nextRoot));
103055
+ };
103056
+ if (typeof ResizeObserver !== "undefined") {
103057
+ resizeObserver = new ResizeObserver(() => {
103058
+ handleUpdate();
103059
+ });
103060
+ resizeObserver.observe(target);
103061
+ if (target.parentElement) resizeObserver.observe(target.parentElement);
103062
+ }
103063
+ handleUpdate();
103064
+ window.addEventListener("resize", handleUpdate);
103065
+ return () => {
103066
+ window.removeEventListener("resize", handleUpdate);
103067
+ scrollTarget.removeEventListener("scroll", handleUpdate);
103068
+ resizeObserver?.disconnect();
103069
+ };
103070
+ }, [enabled, target]);
103071
+ return height;
103072
+ }
103073
+ //#endregion
102951
103074
  //#region src/components/folder-editor-viewer.tsx
102952
103075
  function FolderEditorViewer({ changeId, archived = false }) {
102953
103076
  const { data: files, isLoading, error } = archived ? useArchiveFilesSubscription(changeId) : useChangeFilesSubscription(changeId);
102954
103077
  const [selectedPath, setSelectedPath] = (0, import_react.useState)(null);
103078
+ const [viewportNode, setViewportNode] = (0, import_react.useState)(null);
103079
+ const viewportHeight = useViewportConstrainedHeight({
103080
+ target: viewportNode,
103081
+ enabled: viewportNode !== null
103082
+ });
102955
103083
  const sortedEntries = (0, import_react.useMemo)(() => {
102956
103084
  if (!files) return [];
102957
103085
  return [...files];
@@ -102971,18 +103099,31 @@ function FolderEditorViewer({ changeId, archived = false }) {
102971
103099
  className: "border-destructive/50 bg-destructive/10 text-destructive rounded-md border p-4 text-sm",
102972
103100
  children: ["Failed to load files: ", error.message]
102973
103101
  });
102974
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
102975
- entries: sortedEntries,
102976
- selectedPath,
102977
- onSelect: setSelectedPath,
102978
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this change." }),
102979
- renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
102980
- file: activeFile,
102981
- value: activeFile.content ?? "",
102982
- readOnly: true
102983
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
102984
- className: "text-muted-foreground flex h-full items-center justify-center",
102985
- children: "Select a file to view"
103102
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
103103
+ "data-tab-scroll-root": "true",
103104
+ className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-auto",
103105
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103106
+ className: "pr-1",
103107
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103108
+ ref: setViewportNode,
103109
+ className: "flex min-h-0 flex-col",
103110
+ style: viewportHeight != null ? { height: `${viewportHeight}px` } : void 0,
103111
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
103112
+ entries: sortedEntries,
103113
+ selectedPath,
103114
+ onSelect: setSelectedPath,
103115
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this change." }),
103116
+ renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
103117
+ file: activeFile,
103118
+ value: activeFile.content ?? "",
103119
+ readOnly: true,
103120
+ editorMinHeight: "0px"
103121
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103122
+ className: "text-muted-foreground flex h-full items-center justify-center",
103123
+ children: "Select a file to view"
103124
+ })
103125
+ })
103126
+ })
102986
103127
  })
102987
103128
  });
102988
103129
  }
@@ -103850,7 +103991,7 @@ function ChangeView() {
103850
103991
  */
103851
103992
  function ButtonGroup({ value, options, onChange, className = "", tone = "default" }) {
103852
103993
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103853
- className: `inline-flex w-fit max-w-full self-start overflow-hidden rounded-md border ${tone === "terminal" ? "border-terminal-foreground/25 bg-terminal/70 text-terminal-foreground" : "border-border bg-card"} ${className}`,
103994
+ className: `inline-flex w-fit max-w-full shrink-0 self-start overflow-hidden rounded-md border ${tone === "terminal" ? "border-terminal-foreground/25 bg-terminal/70 text-terminal-foreground" : "border-border bg-card"} ${className}`,
103854
103995
  children: options.map((option, index) => {
103855
103996
  const active = option.value === value;
103856
103997
  const stateClassName = active ? "bg-primary text-primary-foreground" : tone === "terminal" ? "text-terminal-foreground/72 hover:bg-terminal-foreground/10 hover:text-terminal-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground";
@@ -146295,6 +146436,16 @@ function isCoreWorkflowSelection(workflows) {
146295
146436
  function createRunnerLineId() {
146296
146437
  return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
146297
146438
  }
146439
+ function useTabPanelViewportHeight() {
146440
+ const [target, setTarget] = (0, import_react.useState)(null);
146441
+ return {
146442
+ viewportHeight: useViewportConstrainedHeight({
146443
+ target,
146444
+ enabled: target !== null
146445
+ }),
146446
+ setViewportNode: setTarget
146447
+ };
146448
+ }
146298
146449
  function JsonStructuredValue({ value }) {
146299
146450
  if (value === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
146300
146451
  className: "text-muted-foreground font-mono text-xs",
@@ -146352,6 +146503,8 @@ function JsonStructuredValue({ value }) {
146352
146503
  }
146353
146504
  function Config() {
146354
146505
  const isStatic = isStaticMode();
146506
+ const { viewportHeight: schemaViewportHeight, setViewportNode: setSchemaViewportNode } = useTabPanelViewportHeight();
146507
+ const { viewportHeight: projectConfigViewportHeight, setViewportNode: setProjectConfigViewportNode } = useTabPanelViewportHeight();
146355
146508
  const [schemaMode, setSchemaMode] = (0, import_react.useState)("read");
146356
146509
  const [schemaActionError, setSchemaActionError] = (0, import_react.useState)(null);
146357
146510
  const [schemaEntryError, setSchemaEntryError] = (0, import_react.useState)(null);
@@ -147187,416 +147340,426 @@ function Config() {
147187
147340
  if (isPendingCommandRunning) return;
147188
147341
  setPendingCommandKind(null);
147189
147342
  }, [isPendingCommandRunning]);
147190
- const schemaTabContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147191
- className: "flex min-h-0 flex-1 flex-col gap-4",
147192
- children: [
147193
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147194
- className: "flex flex-wrap items-center justify-between gap-3",
147195
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGroup, {
147196
- value: schemaMode,
147197
- onChange: handleSchemaModeChange,
147198
- options: [
147199
- {
147200
- value: "read",
147201
- label: "Read"
147202
- },
147203
- {
147204
- value: "preview",
147205
- label: "Preview"
147206
- },
147207
- {
147208
- value: "edit",
147209
- label: "Edit",
147210
- disabled: !schemaCanEdit
147211
- }
147212
- ]
147213
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147214
- className: "flex items-center gap-2",
147215
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147216
- type: "button",
147217
- onClick: handleAddSchema,
147218
- disabled: isStatic || createSchemaMutation.isPending,
147219
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147220
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" }), "Add"]
147221
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147222
- type: "button",
147223
- onClick: handleDeleteSchema,
147224
- disabled: !schemaCanEdit || deleteSchemaMutation.isPending,
147225
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147226
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }), "Delete"]
147343
+ const schemaTabContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147344
+ "data-tab-scroll-root": "true",
147345
+ className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-auto",
147346
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147347
+ className: "space-y-4 pr-1",
147348
+ children: [
147349
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147350
+ className: "flex flex-wrap items-center justify-between gap-3",
147351
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGroup, {
147352
+ value: schemaMode,
147353
+ onChange: handleSchemaModeChange,
147354
+ options: [
147355
+ {
147356
+ value: "read",
147357
+ label: "Read"
147358
+ },
147359
+ {
147360
+ value: "preview",
147361
+ label: "Preview"
147362
+ },
147363
+ {
147364
+ value: "edit",
147365
+ label: "Edit",
147366
+ disabled: !schemaCanEdit
147367
+ }
147368
+ ]
147369
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147370
+ className: "flex items-center gap-2",
147371
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147372
+ type: "button",
147373
+ onClick: handleAddSchema,
147374
+ disabled: isStatic || createSchemaMutation.isPending,
147375
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147376
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" }), "Add"]
147377
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147378
+ type: "button",
147379
+ onClick: handleDeleteSchema,
147380
+ disabled: !schemaCanEdit || deleteSchemaMutation.isPending,
147381
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147382
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }), "Delete"]
147383
+ })]
147227
147384
  })]
147228
- })]
147229
- }),
147230
- schemaActionError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147231
- className: "text-destructive text-xs",
147232
- children: schemaActionError
147233
- }),
147234
- schemaEntryError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147235
- className: "text-destructive text-xs",
147236
- children: schemaEntryError
147237
- }),
147238
- schemasError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147239
- className: "text-destructive text-sm",
147240
- children: ["Failed to load schemas: ", schemasError.message]
147241
- }),
147242
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147243
- className: "flex min-h-0 flex-1 flex-col",
147244
- children: [
147245
- schemasLoading && (!schemas || schemas.length === 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147246
- className: "text-muted-foreground mb-3 text-sm",
147247
- children: "Loading schemas…"
147248
- }),
147249
- schemas && schemas.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147250
- className: "text-muted-foreground mb-3 text-sm",
147251
- children: "No schemas available."
147252
- }),
147253
- selectedSchemaInfo ? schemaMode === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147254
- className: "min-h-0 flex-1",
147255
- markdown: ({ H1, H2, H3, Section }) => {
147256
- const anchorBase = `schema-${selectedSchemaInfo.name}`;
147257
- const schemaAnchor = (suffix) => `${anchorBase}-${suffix}`;
147258
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147259
- className: "space-y-6",
147260
- children: [
147261
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H1, {
147262
- id: anchorBase,
147263
- children: selectedSchemaInfo.name
147264
- }), selectedSchemaInfo.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147265
- className: "text-muted-foreground",
147266
- children: selectedSchemaInfo.description
147267
- })] }),
147268
- schemaResolution && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147269
- id: schemaAnchor("resolution"),
147270
- children: "Resolution"
147271
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147272
- className: "text-muted-foreground mt-2 space-y-1 pl-4 text-sm",
147273
- children: [
147274
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: ["Source: ", schemaResolution.source] }),
147275
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147276
- className: "truncate",
147277
- children: ["Path: ", schemaResolution.displayPath ?? schemaResolution.path]
147385
+ }),
147386
+ schemaActionError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147387
+ className: "text-destructive text-xs",
147388
+ children: schemaActionError
147389
+ }),
147390
+ schemaEntryError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147391
+ className: "text-destructive text-xs",
147392
+ children: schemaEntryError
147393
+ }),
147394
+ schemasError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147395
+ className: "text-destructive text-sm",
147396
+ children: ["Failed to load schemas: ", schemasError.message]
147397
+ }),
147398
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147399
+ ref: setSchemaViewportNode,
147400
+ className: "flex min-h-0 flex-col",
147401
+ style: schemaViewportHeight != null ? { height: `${schemaViewportHeight}px` } : void 0,
147402
+ children: [
147403
+ schemasLoading && (!schemas || schemas.length === 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147404
+ className: "text-muted-foreground mb-3 text-sm",
147405
+ children: "Loading schemas…"
147406
+ }),
147407
+ schemas && schemas.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147408
+ className: "text-muted-foreground mb-3 text-sm",
147409
+ children: "No schemas available."
147410
+ }),
147411
+ selectedSchemaInfo ? schemaMode === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147412
+ className: "min-h-0 flex-1",
147413
+ markdown: ({ H1, H2, H3, Section }) => {
147414
+ const anchorBase = `schema-${selectedSchemaInfo.name}`;
147415
+ const schemaAnchor = (suffix) => `${anchorBase}-${suffix}`;
147416
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147417
+ className: "space-y-6",
147418
+ children: [
147419
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H1, {
147420
+ id: anchorBase,
147421
+ children: selectedSchemaInfo.name
147422
+ }), selectedSchemaInfo.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147423
+ className: "text-muted-foreground",
147424
+ children: selectedSchemaInfo.description
147425
+ })] }),
147426
+ schemaResolution && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147427
+ id: schemaAnchor("resolution"),
147428
+ children: "Resolution"
147429
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147430
+ className: "text-muted-foreground mt-2 space-y-1 pl-4 text-sm",
147431
+ children: [
147432
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: ["Source: ", schemaResolution.source] }),
147433
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147434
+ className: "truncate",
147435
+ children: ["Path: ", schemaResolution.displayPath ?? schemaResolution.path]
147436
+ }),
147437
+ schemaResolution.shadows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
147438
+ "Shadows:",
147439
+ " ",
147440
+ schemaResolution.shadows.map((s) => `${s.source}(${s.displayPath ?? s.path})`).join(", ")
147441
+ ] })
147442
+ ]
147443
+ })] }),
147444
+ schemaPreview.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147445
+ id: schemaAnchor("schema-errors"),
147446
+ children: "Schema errors"
147447
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147448
+ className: "border-destructive/40 bg-destructive/10 text-destructive mt-2 rounded-md border px-3 py-2 text-sm",
147449
+ children: ["schema.yaml parse error: ", schemaPreview.error]
147450
+ })] }),
147451
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [
147452
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147453
+ id: schemaAnchor("artifacts"),
147454
+ children: "Artifacts"
147278
147455
  }),
147279
- schemaResolution.shadows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
147280
- "Shadows:",
147281
- " ",
147282
- schemaResolution.shadows.map((s) => `${s.source}(${s.displayPath ?? s.path})`).join(", ")
147283
- ] })
147284
- ]
147285
- })] }),
147286
- schemaPreview.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147287
- id: schemaAnchor("schema-errors"),
147288
- children: "Schema errors"
147289
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147290
- className: "border-destructive/40 bg-destructive/10 text-destructive mt-2 rounded-md border px-3 py-2 text-sm",
147291
- children: ["schema.yaml parse error: ", schemaPreview.error]
147292
- })] }),
147293
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [
147294
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147295
- id: schemaAnchor("artifacts"),
147296
- children: "Artifacts"
147297
- }),
147298
- previewArtifacts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147299
- className: "mt-3 space-y-6",
147300
- children: previewArtifacts.map((artifact) => {
147301
- const rawArtifact = rawArtifactMap.get(artifact.id);
147302
- const templateInfo = templateContents?.[artifact.id] ?? (templates?.[artifact.id] ? {
147303
- ...templates[artifact.id],
147304
- content: null
147305
- } : null);
147306
- const templatePath = templateInfo?.path ?? (typeof rawArtifact?.template === "string" ? rawArtifact.template : void 0);
147307
- const templateDisplayPath = templateInfo?.displayPath ?? templatePath ?? null;
147308
- const draftTemplateContent = templatePath !== void 0 ? draftByPath.get(templatePath) : void 0;
147309
- const templateBody = draftTemplateContent !== void 0 ? draftTemplateContent : templateInfo ? templateInfo.content : null;
147310
- const knownFields = [
147311
- ["id", rawArtifact?.id ?? artifact.id],
147312
- ["generates", rawArtifact?.generates ?? artifact.outputPath],
147313
- ["description", rawArtifact?.description ?? artifact.description],
147314
- ["instruction", rawArtifact?.instruction],
147315
- ["requires", rawArtifact?.requires ?? artifact.requires]
147316
- ].filter((entry) => entry[1] !== void 0);
147317
- const unknownEntries = rawArtifact ? Object.entries(rawArtifact).filter(([key]) => !KNOWN_ARTIFACT_KEYS.has(key)) : [];
147318
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
147319
- className: "space-y-3",
147320
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H3, {
147321
- id: schemaAnchor(`artifact-${artifact.id}`),
147322
- children: artifact.id
147323
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147324
- className: "border-border space-y-4 rounded-lg border px-4 py-4 text-sm",
147325
- children: [
147326
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147327
- className: "space-y-3",
147328
- children: knownFields.map(([key, value]) => {
147329
- const isRequires = key === "requires";
147330
- const requires = isRequires ? Array.isArray(value) ? value.filter((item) => typeof item === "string") : [] : [];
147331
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147456
+ previewArtifacts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147457
+ className: "mt-3 space-y-6",
147458
+ children: previewArtifacts.map((artifact) => {
147459
+ const rawArtifact = rawArtifactMap.get(artifact.id);
147460
+ const templateInfo = templateContents?.[artifact.id] ?? (templates?.[artifact.id] ? {
147461
+ ...templates[artifact.id],
147462
+ content: null
147463
+ } : null);
147464
+ const templatePath = templateInfo?.path ?? (typeof rawArtifact?.template === "string" ? rawArtifact.template : void 0);
147465
+ const templateDisplayPath = templateInfo?.displayPath ?? templatePath ?? null;
147466
+ const draftTemplateContent = templatePath !== void 0 ? draftByPath.get(templatePath) : void 0;
147467
+ const templateBody = draftTemplateContent !== void 0 ? draftTemplateContent : templateInfo ? templateInfo.content : null;
147468
+ const knownFields = [
147469
+ ["id", rawArtifact?.id ?? artifact.id],
147470
+ ["generates", rawArtifact?.generates ?? artifact.outputPath],
147471
+ ["description", rawArtifact?.description ?? artifact.description],
147472
+ ["instruction", rawArtifact?.instruction],
147473
+ ["requires", rawArtifact?.requires ?? artifact.requires]
147474
+ ].filter((entry) => entry[1] !== void 0);
147475
+ const unknownEntries = rawArtifact ? Object.entries(rawArtifact).filter(([key]) => !KNOWN_ARTIFACT_KEYS.has(key)) : [];
147476
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
147477
+ className: "space-y-3",
147478
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H3, {
147479
+ id: schemaAnchor(`artifact-${artifact.id}`),
147480
+ children: artifact.id
147481
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147482
+ className: "border-border space-y-4 rounded-lg border px-4 py-4 text-sm",
147483
+ children: [
147484
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147485
+ className: "space-y-3",
147486
+ children: knownFields.map(([key, value]) => {
147487
+ const isRequires = key === "requires";
147488
+ const requires = isRequires ? Array.isArray(value) ? value.filter((item) => typeof item === "string") : [] : [];
147489
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147490
+ className: "space-y-2",
147491
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147492
+ className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147493
+ children: key
147494
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147495
+ className: "pl-4 text-sm leading-6",
147496
+ children: isRequires ? requires.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147497
+ className: "flex flex-wrap gap-1.5",
147498
+ children: requires.map((requiredArtifactId) => {
147499
+ if (!previewArtifacts.some((candidate) => candidate.id === requiredArtifactId)) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147500
+ className: "bg-muted text-muted-foreground rounded-md px-2 py-0.5 text-xs",
147501
+ children: requiredArtifactId
147502
+ }, requiredArtifactId);
147503
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
147504
+ href: `#${schemaAnchor(`artifact-${requiredArtifactId}`)}`,
147505
+ className: "bg-primary hover:bg-primary/80 text-primary-foreground rounded-md px-2 py-0.5 text-xs transition-colors",
147506
+ children: requiredArtifactId
147507
+ }, requiredArtifactId);
147508
+ })
147509
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147510
+ className: "text-muted-foreground",
147511
+ children: "—"
147512
+ }) : renderFieldValue(key, value)
147513
+ })]
147514
+ }, key);
147515
+ })
147516
+ }),
147517
+ templatePath && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147518
+ className: "space-y-2",
147519
+ children: [
147520
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147521
+ className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147522
+ children: "Template"
147523
+ }),
147524
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147525
+ className: "text-muted-foreground pl-4 text-xs",
147526
+ children: [
147527
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147528
+ className: "mr-1",
147529
+ children: "Template:"
147530
+ }),
147531
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
147532
+ className: "bg-muted rounded px-1",
147533
+ children: templateDisplayPath
147534
+ }),
147535
+ templateInfo?.source ? ` (${templateInfo.source})` : null
147536
+ ]
147537
+ }),
147538
+ templateBody !== null && templateBody !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147539
+ className: "pl-4",
147540
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147541
+ className: "bg-muted/30 rounded-lg p-4 [zoom:0.86]",
147542
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147543
+ markdown: templateBody,
147544
+ collectToc: false
147545
+ })
147546
+ })
147547
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147548
+ className: "text-muted-foreground pl-4 text-sm",
147549
+ children: "Template content unavailable."
147550
+ })
147551
+ ]
147552
+ }),
147553
+ unknownEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147554
+ className: "space-y-3",
147555
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147556
+ className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147557
+ children: "Extra fields"
147558
+ }), unknownEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147332
147559
  className: "space-y-2",
147333
147560
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147334
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147561
+ className: "text-muted-foreground text-xs",
147335
147562
  children: key
147336
147563
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147337
147564
  className: "pl-4 text-sm leading-6",
147338
- children: isRequires ? requires.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147339
- className: "flex flex-wrap gap-1.5",
147340
- children: requires.map((requiredArtifactId) => {
147341
- if (!previewArtifacts.some((candidate) => candidate.id === requiredArtifactId)) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147342
- className: "bg-muted text-muted-foreground rounded-md px-2 py-0.5 text-xs",
147343
- children: requiredArtifactId
147344
- }, requiredArtifactId);
147345
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
147346
- href: `#${schemaAnchor(`artifact-${requiredArtifactId}`)}`,
147347
- className: "bg-primary hover:bg-primary/80 text-primary-foreground rounded-md px-2 py-0.5 text-xs transition-colors",
147348
- children: requiredArtifactId
147349
- }, requiredArtifactId);
147350
- })
147351
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147352
- className: "text-muted-foreground",
147353
- children: "—"
147354
- }) : renderFieldValue(key, value)
147565
+ children: renderFieldValue(key, value)
147355
147566
  })]
147356
- }, key);
147567
+ }, key))]
147357
147568
  })
147358
- }),
147359
- templatePath && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147360
- className: "space-y-2",
147361
- children: [
147362
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147363
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147364
- children: "Template"
147365
- }),
147366
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147367
- className: "text-muted-foreground pl-4 text-xs",
147368
- children: [
147369
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147370
- className: "mr-1",
147371
- children: "Template:"
147372
- }),
147373
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
147374
- className: "bg-muted rounded px-1",
147375
- children: templateDisplayPath
147376
- }),
147377
- templateInfo?.source ? ` (${templateInfo.source})` : null
147378
- ]
147379
- }),
147380
- templateBody !== null && templateBody !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147381
- className: "pl-4",
147382
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147383
- className: "bg-muted/30 rounded-lg p-4 [zoom:0.86]",
147384
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147385
- markdown: templateBody,
147386
- collectToc: false
147387
- })
147388
- })
147389
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147390
- className: "text-muted-foreground pl-4 text-sm",
147391
- children: "Template content unavailable."
147392
- })
147393
- ]
147394
- }),
147395
- unknownEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147396
- className: "space-y-3",
147397
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147398
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147399
- children: "Extra fields"
147400
- }), unknownEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147401
- className: "space-y-2",
147402
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147403
- className: "text-muted-foreground text-xs",
147404
- children: key
147405
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147406
- className: "pl-4 text-sm leading-6",
147407
- children: renderFieldValue(key, value)
147408
- })]
147409
- }, key))]
147410
- })
147411
- ]
147412
- })]
147413
- }, artifact.id);
147414
- })
147415
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147416
- className: "text-muted-foreground text-sm",
147417
- children: "Select a schema to view details."
147418
- }),
147419
- schemaDetail?.applyRequires?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147420
- className: "text-muted-foreground mt-3 text-xs",
147421
- children: ["Apply requires: ", schemaDetail.applyRequires.join(", ")]
147422
- }) : null
147423
- ] }),
147424
- hasDirtyDrafts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147425
- className: "text-muted-foreground text-xs",
147426
- children: "Preview is rendering draft content. Save to persist changes."
147427
- })
147428
- ]
147429
- });
147430
- }
147431
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuWrapper, {
147432
- ref: schemaMenuWrapperRef,
147433
- className: "h-full space-y-4",
147434
- children: [
147435
- schemaFilesError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147436
- className: "text-destructive text-xs",
147437
- children: ["Failed to load schema files: ", schemaFilesError.message]
147438
- }),
147439
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
147440
- entries: schemaEntries,
147441
- selectedPath: selectedSchemaPath,
147442
- onSelect: setSelectedSchemaPath,
147443
- breadcrumbRoot: schemaRootLabel,
147444
- headerLabel: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
147445
- className: "flex min-w-0 items-center gap-2",
147446
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147447
- className: "uppercase tracking-wide",
147448
- children: "Files"
147449
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147450
- className: "text-muted-foreground/80 truncate text-[10px] normal-case",
147451
- title: schemaRootLabel,
147452
- children: schemaRootLabel
147453
- })]
147569
+ ]
147570
+ })]
147571
+ }, artifact.id);
147572
+ })
147573
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147574
+ className: "text-muted-foreground text-sm",
147575
+ children: "Select a schema to view details."
147576
+ }),
147577
+ schemaDetail?.applyRequires?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147578
+ className: "text-muted-foreground mt-3 text-xs",
147579
+ children: ["Apply requires: ", schemaDetail.applyRequires.join(", ")]
147580
+ }) : null
147581
+ ] }),
147582
+ hasDirtyDrafts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147583
+ className: "text-muted-foreground text-xs",
147584
+ children: "Preview is rendering draft content. Save to persist changes."
147585
+ })
147586
+ ]
147587
+ });
147588
+ }
147589
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuWrapper, {
147590
+ ref: schemaMenuWrapperRef,
147591
+ className: "flex min-h-0 flex-1 flex-col gap-4",
147592
+ children: [
147593
+ schemaFilesError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147594
+ className: "text-destructive text-xs",
147595
+ children: ["Failed to load schema files: ", schemaFilesError.message]
147454
147596
  }),
147455
- headerActions: headerMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147456
- type: "button",
147457
- onClick: (event) => {
147458
- setFileMenuAnchor(null);
147459
- setViewMenuAnchor(null);
147460
- setHeaderMenuAnchor({
147461
- type: "target",
147462
- element: event.currentTarget,
147463
- placement: "bottom-end"
147464
- });
147465
- },
147466
- className: "hover:bg-muted rounded-md p-1",
147467
- "aria-label": "Schema menu",
147468
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EllipsisVertical, { className: "h-4 w-4" })
147469
- }) }) : void 0,
147470
- entryActions: (entry) => {
147471
- const propertiesAction = {
147472
- id: "properties",
147473
- label: "Properties",
147474
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Info$1, { className: "h-3.5 w-3.5" }),
147475
- onSelect: () => handleOpenEntryInfo(entry)
147476
- };
147477
- if (schemaMode !== "edit" || !canManageEntries) return [propertiesAction];
147478
- const parent = entry.type === "directory" ? entry.path : getParentPath(entry.path);
147479
- const isDirectory = entry.type === "directory";
147480
- return [
147481
- {
147482
- id: "new-file",
147483
- label: isDirectory ? "New file inside" : "New sibling file",
147484
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePlus, { className: "h-3.5 w-3.5" }),
147485
- onSelect: () => handleOpenCreateEntry("file", parent)
147486
- },
147487
- {
147488
- id: "new-folder",
147489
- label: isDirectory ? "New folder inside" : "New sibling folder",
147490
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderPlus, { className: "h-3.5 w-3.5" }),
147491
- onSelect: () => handleOpenCreateEntry("directory", parent)
147492
- },
147493
- propertiesAction,
147494
- {
147495
- id: "delete",
147496
- label: "Delete",
147497
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }),
147498
- tone: "destructive",
147499
- onSelect: () => handleOpenDeleteEntry(entry)
147500
- }
147501
- ];
147502
- },
147503
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this schema." }),
147504
- renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147505
- className: "flex min-h-0 flex-1 flex-col",
147506
- children: [
147507
- schemaMode === "edit" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147508
- className: "border-border/50 flex items-center justify-between border-b px-3 py-2 text-xs",
147509
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147510
- className: "flex items-center gap-2",
147511
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147512
- type: "button",
147513
- onClick: (event) => {
147514
- setHeaderMenuAnchor(null);
147515
- setViewMenuAnchor(null);
147516
- setFileMenuAnchor({
147517
- type: "target",
147518
- element: event.currentTarget,
147519
- placement: "bottom-start"
147520
- });
147521
- },
147522
- className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147523
- children: "File"
147524
- }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147525
- type: "button",
147526
- onClick: (event) => {
147527
- setHeaderMenuAnchor(null);
147528
- setFileMenuAnchor(null);
147529
- setViewMenuAnchor({
147530
- type: "target",
147531
- element: event.currentTarget,
147532
- placement: "bottom-start"
147533
- });
147534
- },
147535
- className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147536
- children: "View"
147537
- }) })]
147538
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147539
- className: "flex items-center gap-2",
147540
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147541
- type: "button",
147542
- onClick: handleFileCancel,
147543
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147544
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147545
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147546
- type: "button",
147547
- onClick: handleFileSave,
147548
- disabled: !activeSchemaDirty || saveSchemaFileMutation.isPending || !schemaCanEdit,
147549
- className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147550
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" }), saveSchemaFileMutation.isPending ? "Saving…" : "Save"]
147551
- })]
147597
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147598
+ className: "min-h-0 flex-1",
147599
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
147600
+ entries: schemaEntries,
147601
+ selectedPath: selectedSchemaPath,
147602
+ onSelect: setSelectedSchemaPath,
147603
+ breadcrumbRoot: schemaRootLabel,
147604
+ headerLabel: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
147605
+ className: "flex min-w-0 items-center gap-2",
147606
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147607
+ className: "uppercase tracking-wide",
147608
+ children: "Files"
147609
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147610
+ className: "text-muted-foreground/80 truncate text-[10px] normal-case",
147611
+ title: schemaRootLabel,
147612
+ children: schemaRootLabel
147552
147613
  })]
147553
147614
  }),
147554
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
147555
- file: activeFile,
147556
- value: schemaMode === "edit" ? activeSchemaDraft ?? activeFile.content ?? "" : activeFile.content ?? "",
147557
- readOnly: schemaMode !== "edit" || !schemaCanEdit,
147558
- onChange: schemaMode === "edit" ? handleFileChange : void 0,
147559
- lineWrapping: schemaEditorWrap
147560
- }),
147561
- schemaResolution?.source === "package" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147562
- className: "text-muted-foreground border-border/50 border-t px-3 py-2 text-xs",
147563
- children: "Package-provided schemas are read-only."
147615
+ headerActions: headerMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147616
+ type: "button",
147617
+ onClick: (event) => {
147618
+ setFileMenuAnchor(null);
147619
+ setViewMenuAnchor(null);
147620
+ setHeaderMenuAnchor({
147621
+ type: "target",
147622
+ element: event.currentTarget,
147623
+ placement: "bottom-end"
147624
+ });
147625
+ },
147626
+ className: "hover:bg-muted rounded-md p-1",
147627
+ "aria-label": "Schema menu",
147628
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EllipsisVertical, { className: "h-4 w-4" })
147629
+ }) }) : void 0,
147630
+ entryActions: (entry) => {
147631
+ const propertiesAction = {
147632
+ id: "properties",
147633
+ label: "Properties",
147634
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Info$1, { className: "h-3.5 w-3.5" }),
147635
+ onSelect: () => handleOpenEntryInfo(entry)
147636
+ };
147637
+ if (schemaMode !== "edit" || !canManageEntries) return [propertiesAction];
147638
+ const parent = entry.type === "directory" ? entry.path : getParentPath(entry.path);
147639
+ const isDirectory = entry.type === "directory";
147640
+ return [
147641
+ {
147642
+ id: "new-file",
147643
+ label: isDirectory ? "New file inside" : "New sibling file",
147644
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePlus, { className: "h-3.5 w-3.5" }),
147645
+ onSelect: () => handleOpenCreateEntry("file", parent)
147646
+ },
147647
+ {
147648
+ id: "new-folder",
147649
+ label: isDirectory ? "New folder inside" : "New sibling folder",
147650
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderPlus, { className: "h-3.5 w-3.5" }),
147651
+ onSelect: () => handleOpenCreateEntry("directory", parent)
147652
+ },
147653
+ propertiesAction,
147654
+ {
147655
+ id: "delete",
147656
+ label: "Delete",
147657
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }),
147658
+ tone: "destructive",
147659
+ onSelect: () => handleOpenDeleteEntry(entry)
147660
+ }
147661
+ ];
147662
+ },
147663
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this schema." }),
147664
+ renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147665
+ className: "flex min-h-0 flex-1 flex-col",
147666
+ children: [
147667
+ schemaMode === "edit" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147668
+ className: "border-border/50 flex items-center justify-between border-b px-3 py-2 text-xs",
147669
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147670
+ className: "flex items-center gap-2",
147671
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147672
+ type: "button",
147673
+ onClick: (event) => {
147674
+ setHeaderMenuAnchor(null);
147675
+ setViewMenuAnchor(null);
147676
+ setFileMenuAnchor({
147677
+ type: "target",
147678
+ element: event.currentTarget,
147679
+ placement: "bottom-start"
147680
+ });
147681
+ },
147682
+ className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147683
+ children: "File"
147684
+ }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147685
+ type: "button",
147686
+ onClick: (event) => {
147687
+ setHeaderMenuAnchor(null);
147688
+ setFileMenuAnchor(null);
147689
+ setViewMenuAnchor({
147690
+ type: "target",
147691
+ element: event.currentTarget,
147692
+ placement: "bottom-start"
147693
+ });
147694
+ },
147695
+ className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147696
+ children: "View"
147697
+ }) })]
147698
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147699
+ className: "flex items-center gap-2",
147700
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147701
+ type: "button",
147702
+ onClick: handleFileCancel,
147703
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147704
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147705
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147706
+ type: "button",
147707
+ onClick: handleFileSave,
147708
+ disabled: !activeSchemaDirty || saveSchemaFileMutation.isPending || !schemaCanEdit,
147709
+ className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147710
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" }), saveSchemaFileMutation.isPending ? "Saving…" : "Save"]
147711
+ })]
147712
+ })]
147713
+ }),
147714
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
147715
+ file: activeFile,
147716
+ value: schemaMode === "edit" ? activeSchemaDraft ?? activeFile.content ?? "" : activeFile.content ?? "",
147717
+ readOnly: schemaMode !== "edit" || !schemaCanEdit,
147718
+ onChange: schemaMode === "edit" ? handleFileChange : void 0,
147719
+ lineWrapping: schemaEditorWrap,
147720
+ editorMinHeight: "0px"
147721
+ }),
147722
+ schemaResolution?.source === "package" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147723
+ className: "text-muted-foreground border-border/50 border-t px-3 py-2 text-xs",
147724
+ children: "Package-provided schemas are read-only."
147725
+ })
147726
+ ]
147727
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147728
+ className: "text-muted-foreground flex h-full items-center justify-center",
147729
+ children: "Select a file to view"
147564
147730
  })
147565
- ]
147566
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147567
- className: "text-muted-foreground flex h-full items-center justify-center",
147568
- children: "Select a file to view"
147731
+ })
147732
+ }),
147733
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147734
+ open: !!headerMenuAnchor,
147735
+ items: headerMenuItems,
147736
+ anchor: headerMenuAnchor,
147737
+ boundaryElement: schemaMenuWrapperRef.current,
147738
+ onClose: () => setHeaderMenuAnchor(null)
147739
+ }),
147740
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147741
+ open: !!fileMenuAnchor,
147742
+ items: fileMenuItems,
147743
+ anchor: fileMenuAnchor,
147744
+ boundaryElement: schemaMenuWrapperRef.current,
147745
+ onClose: () => setFileMenuAnchor(null)
147746
+ }),
147747
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147748
+ open: !!viewMenuAnchor,
147749
+ items: viewMenuItems,
147750
+ anchor: viewMenuAnchor,
147751
+ boundaryElement: schemaMenuWrapperRef.current,
147752
+ onClose: () => setViewMenuAnchor(null)
147569
147753
  })
147570
- }),
147571
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147572
- open: !!headerMenuAnchor,
147573
- items: headerMenuItems,
147574
- anchor: headerMenuAnchor,
147575
- boundaryElement: schemaMenuWrapperRef.current,
147576
- onClose: () => setHeaderMenuAnchor(null)
147577
- }),
147578
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147579
- open: !!fileMenuAnchor,
147580
- items: fileMenuItems,
147581
- anchor: fileMenuAnchor,
147582
- boundaryElement: schemaMenuWrapperRef.current,
147583
- onClose: () => setFileMenuAnchor(null)
147584
- }),
147585
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147586
- open: !!viewMenuAnchor,
147587
- items: viewMenuItems,
147588
- anchor: viewMenuAnchor,
147589
- boundaryElement: schemaMenuWrapperRef.current,
147590
- onClose: () => setViewMenuAnchor(null)
147591
- })
147592
- ]
147593
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147594
- className: "text-muted-foreground text-sm",
147595
- children: "Select a schema to view details."
147596
- })
147597
- ]
147598
- })
147599
- ]
147754
+ ]
147755
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147756
+ className: "text-muted-foreground text-sm",
147757
+ children: "Select a schema to view details."
147758
+ })
147759
+ ]
147760
+ })
147761
+ ]
147762
+ })
147600
147763
  });
147601
147764
  const schemaTabs = (schemas ?? []).map((schema) => ({
147602
147765
  id: `schema:${schema.name}`,
@@ -147605,79 +147768,101 @@ function Config() {
147605
147768
  content: schemaTabContent
147606
147769
  }));
147607
147770
  const projectConfigTabContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147608
- className: "space-y-4",
147609
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147610
- className: "border-border bg-card space-y-4 rounded-lg border p-4",
147611
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147612
- className: "flex flex-wrap items-center justify-between gap-2",
147613
- children: [
147614
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147615
- className: "text-sm font-semibold",
147616
- children: "OpenSpec Project Config"
147617
- }),
147618
- !isStatic && configYaml && !isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147619
- type: "button",
147620
- onClick: handleConfigEdit,
147621
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147622
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pen, { className: "h-3.5 w-3.5" }), "Edit"]
147623
- }),
147624
- isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147625
- className: "flex items-center gap-2",
147626
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147627
- type: "button",
147628
- onClick: handleConfigCancel,
147629
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147630
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147631
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147771
+ "data-tab-scroll-root": "true",
147772
+ className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-auto",
147773
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147774
+ className: "space-y-4 pr-1",
147775
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147776
+ ref: setProjectConfigViewportNode,
147777
+ className: "flex min-h-0 flex-col",
147778
+ style: projectConfigViewportHeight != null ? { height: `${projectConfigViewportHeight}px` } : void 0,
147779
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147780
+ className: "border-border bg-card flex min-h-0 flex-1 flex-col gap-4 overflow-hidden rounded-lg border p-4",
147781
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147782
+ className: "flex flex-wrap items-center justify-between gap-2",
147783
+ children: [
147784
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147785
+ className: "text-sm font-semibold",
147786
+ children: "OpenSpec Project Config"
147787
+ }),
147788
+ !isStatic && configYaml && !isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147789
+ type: "button",
147790
+ onClick: handleConfigEdit,
147791
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147792
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pen, { className: "h-3.5 w-3.5" }), "Edit"]
147793
+ }),
147794
+ isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147795
+ className: "flex items-center gap-2",
147796
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147797
+ type: "button",
147798
+ onClick: handleConfigCancel,
147799
+ className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147800
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147801
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147802
+ type: "button",
147803
+ onClick: () => saveConfigMutation.mutate(),
147804
+ disabled: !configDirty || saveConfigMutation.isPending,
147805
+ className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147806
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" }), saveConfigMutation.isPending ? "Saving…" : "Save"]
147807
+ })]
147808
+ })
147809
+ ]
147810
+ }), configYaml || isConfigEditing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
147811
+ value: configDraft,
147812
+ onChange: (value) => {
147813
+ setConfigDraft(value);
147814
+ setConfigDirty(true);
147815
+ },
147816
+ readOnly: !isConfigEditing,
147817
+ filename: "config.yaml",
147818
+ className: "min-h-0 flex-1",
147819
+ editorMinHeight: "0px"
147820
+ }) : configLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147821
+ className: "route-loading animate-pulse",
147822
+ children: "Loading config…"
147823
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147824
+ className: "text-muted-foreground rounded-md border border-dashed p-4 text-sm",
147825
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147826
+ className: "mb-3",
147827
+ children: "openspec/config.yaml not found."
147828
+ }), !isStatic && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147632
147829
  type: "button",
147633
- onClick: () => saveConfigMutation.mutate(),
147634
- disabled: !configDirty || saveConfigMutation.isPending,
147635
- className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-50",
147636
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" }), saveConfigMutation.isPending ? "Saving…" : "Save"]
147830
+ onClick: handleConfigEdit,
147831
+ className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium",
147832
+ children: "Create config.yaml"
147637
147833
  })]
147638
- })
147639
- ]
147640
- }), configYaml || isConfigEditing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
147641
- value: configDraft,
147642
- onChange: (value) => {
147643
- setConfigDraft(value);
147644
- setConfigDirty(true);
147645
- },
147646
- readOnly: !isConfigEditing,
147647
- filename: "config.yaml"
147648
- }) : configLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147649
- className: "route-loading animate-pulse",
147650
- children: "Loading config…"
147651
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147652
- className: "text-muted-foreground rounded-md border border-dashed p-4 text-sm",
147653
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147654
- className: "mb-3",
147655
- children: "openspec/config.yaml not found."
147656
- }), !isStatic && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147657
- type: "button",
147658
- onClick: handleConfigEdit,
147659
- className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium",
147660
- children: "Create config.yaml"
147661
- })]
147662
- })]
147834
+ })]
147835
+ })
147836
+ })
147663
147837
  })
147664
147838
  });
147665
- const globalConfigTabContent = isStatic ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147666
- className: "space-y-3",
147667
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147668
- className: "text-sm font-semibold",
147669
- children: "OpenSpec Global Config"
147670
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147671
- className: "text-muted-foreground rounded-md border border-dashed p-4 text-sm",
147672
- children: "Global config commands are unavailable in static export mode."
147673
- })]
147839
+ const globalConfigTabContent = isStatic ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147840
+ "data-tab-scroll-root": "true",
147841
+ className: "scrollbar-thin scrollbar-track-transparent flex min-h-0 flex-1 flex-col overflow-hidden",
147842
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147843
+ className: "border-border bg-card flex min-h-0 flex-1 flex-col gap-4 overflow-hidden rounded-lg border p-4",
147844
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147845
+ className: "flex flex-none items-center justify-between gap-2",
147846
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147847
+ className: "text-sm font-semibold",
147848
+ children: "OpenSpec Global Config"
147849
+ })
147850
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147851
+ className: "text-muted-foreground min-h-0 flex-1 overflow-auto pr-1",
147852
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147853
+ className: "rounded-md border border-dashed p-4 text-sm",
147854
+ children: "Global config commands are unavailable in static export mode."
147855
+ })
147856
+ })]
147857
+ })
147674
147858
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147675
- className: "space-y-4",
147859
+ "data-tab-scroll-root": "true",
147860
+ className: "scrollbar-thin scrollbar-track-transparent flex min-h-0 flex-1 flex-col overflow-hidden",
147676
147861
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147677
- className: "border-border bg-card space-y-4 rounded-lg border p-4",
147862
+ className: "border-border bg-card flex min-h-0 flex-1 flex-col gap-4 overflow-hidden rounded-lg border p-4",
147678
147863
  children: [
147679
147864
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147680
- className: "flex flex-wrap items-center justify-between gap-2",
147865
+ className: "flex flex-none flex-wrap items-center justify-between gap-2",
147681
147866
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147682
147867
  className: "text-sm font-semibold",
147683
147868
  children: "OpenSpec Global Config"
@@ -147707,7 +147892,7 @@ function Config() {
147707
147892
  })]
147708
147893
  }),
147709
147894
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147710
- className: "text-muted-foreground text-xs",
147895
+ className: "text-muted-foreground flex-none text-xs",
147711
147896
  children: [
147712
147897
  "Reads from ",
147713
147898
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "openspec config list --json" }),
@@ -147740,7 +147925,7 @@ function Config() {
147740
147925
  className: "text-muted-foreground text-sm",
147741
147926
  children: "Loading global config…"
147742
147927
  }) : isRecordObject(globalConfigData) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147743
- className: "space-y-3",
147928
+ className: "min-h-0 flex-1 space-y-3 overflow-auto pr-1",
147744
147929
  children: [
147745
147930
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147746
147931
  className: "grid gap-2 sm:grid-cols-2",
@@ -147806,7 +147991,7 @@ function Config() {
147806
147991
  className: "text-muted-foreground text-sm",
147807
147992
  children: "Global config unavailable."
147808
147993
  }) : globalConfigTab === "editor" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147809
- className: "space-y-2",
147994
+ className: "flex min-h-0 flex-1 flex-col gap-2 overflow-hidden",
147810
147995
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
147811
147996
  value: globalConfigDraft,
147812
147997
  onChange: (value) => {
@@ -147817,7 +148002,8 @@ function Config() {
147817
148002
  readOnly: saveGlobalConfigMutation.isPending,
147818
148003
  filename: "openspec.global.config.json",
147819
148004
  language: "json",
147820
- editorMinHeight: "260px"
148005
+ className: "min-h-0 flex-1",
148006
+ editorMinHeight: "0px"
147821
148007
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147822
148008
  className: "flex items-center justify-end gap-2",
147823
148009
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
@@ -147839,9 +148025,9 @@ function Config() {
147839
148025
  })]
147840
148026
  })]
147841
148027
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147842
- className: "grid gap-4 xl:grid-cols-[minmax(18rem,0.9fr)_minmax(0,1.1fr)]",
148028
+ className: "grid min-h-0 flex-1 gap-4 overflow-hidden xl:grid-cols-[minmax(18rem,0.9fr)_minmax(0,1.1fr)]",
147843
148029
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147844
- className: "space-y-4",
148030
+ className: "min-h-0 space-y-4 overflow-auto pr-1",
147845
148031
  children: [
147846
148032
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147847
148033
  className: "grid gap-2 sm:grid-cols-3 xl:grid-cols-1",
@@ -147952,7 +148138,7 @@ function Config() {
147952
148138
  })
147953
148139
  ]
147954
148140
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147955
- className: "space-y-3",
148141
+ className: "space-y-3 overflow-auto pr-1",
147956
148142
  children: [profileEditMode === "both" || profileEditMode === "workflows" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
147957
148143
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147958
148144
  className: "text-muted-foreground text-xs",