@openspecui/web 3.2.2 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/assets/CanvasRenderer-g_cyCOjQ.js +1 -0
  2. package/dist/assets/WebGLRenderer-D5zhJW6-.js +1 -0
  3. package/dist/assets/WebGPURenderer-y465o0kZ.js +1 -0
  4. package/dist/assets/browserAll-ZgrCJe2c.js +1 -0
  5. package/dist/assets/dist--qv2cAhs.js +1 -0
  6. package/dist/assets/{dist-BPKmDQiw.js → dist-7YtvWBhg.js} +1 -1
  7. package/dist/assets/dist-B2_Y1J95.js +1 -0
  8. package/dist/assets/{dist-DK_RcTzA.js → dist-BAYsiff-.js} +1 -1
  9. package/dist/assets/{dist-BicqBDv3.js → dist-BLVVgEwt.js} +1 -1
  10. package/dist/assets/{dist-F8MUiu4J.js → dist-Bf-Vu6ub.js} +1 -1
  11. package/dist/assets/{dist-CeZGHI2P.js → dist-CG8D-O-S.js} +1 -1
  12. package/dist/assets/{dist-DO6ZBK2U.js → dist-CJOkmDhD.js} +1 -1
  13. package/dist/assets/{dist-Bk4Jg4eO.js → dist-CYOsUeN2.js} +1 -1
  14. package/dist/assets/{dist-DLlwI018.js → dist-CrmJ-_7N.js} +1 -1
  15. package/dist/assets/{dist-Dja1k4z3.js → dist-DuQ36im8.js} +1 -1
  16. package/dist/assets/dist-Dx0i0vMX.js +1 -0
  17. package/dist/assets/{ghostty-web-02Mxn6DW.js → ghostty-web-QjBmc_QD.js} +1 -1
  18. package/dist/assets/{index-BE9UP1rS.js → index-boRy9i0J.js} +137 -135
  19. package/dist/assets/index-qPEQ3Vl6.css +1 -0
  20. package/dist/assets/{init-Dw5X88Rr.js → init-SyMKucz4.js} +1 -1
  21. package/dist/assets/trpc-OMmqAG5X.js +1 -0
  22. package/dist/assets/webworkerAll-DlZFFXWi.js +1 -0
  23. package/dist/index.html +2 -2
  24. package/dist-ssg/client/.vite/ssr-manifest.json +18 -15
  25. package/dist-ssg/client/assets/CanvasRenderer-CCs62JYq.js +1 -0
  26. package/dist-ssg/client/assets/WebGLRenderer-Cysj4hYz.js +1 -0
  27. package/dist-ssg/client/assets/WebGPURenderer-403idKyo.js +1 -0
  28. package/dist-ssg/client/assets/browserAll-CTlyPTsl.js +1 -0
  29. package/dist-ssg/client/assets/{dist-BIpSLpok.js → dist-B3GAAYvL.js} +1 -1
  30. package/dist-ssg/client/assets/dist-Bf2iWG9l.js +1 -0
  31. package/dist-ssg/client/assets/dist-C6cOrzh-.js +1 -0
  32. package/dist-ssg/client/assets/{dist-40xjGIL0.js → dist-CI8YJ7ws.js} +1 -1
  33. package/dist-ssg/client/assets/dist-CKZ5MQSV.js +1 -0
  34. package/dist-ssg/client/assets/{dist-C05OJeJ3.js → dist-Ctnz-UUk.js} +1 -1
  35. package/dist-ssg/client/assets/{dist-7Bvtx_qv.js → dist-D52OfSjR.js} +1 -1
  36. package/dist-ssg/client/assets/{dist-C2-dVfwV.js → dist-DHEkL8qX.js} +1 -1
  37. package/dist-ssg/client/assets/{dist-CHSKhUU7.js → dist-DdhbPe7E.js} +1 -1
  38. package/dist-ssg/client/assets/{dist-DPF79lwo.js → dist-DgMI4_cq.js} +1 -1
  39. package/dist-ssg/client/assets/{dist-BMMg3UNv.js → dist-DsPNn82D.js} +1 -1
  40. package/dist-ssg/client/assets/{dist-DNzIHL_u.js → dist-nAQWF5VV.js} +1 -1
  41. package/dist-ssg/client/assets/{ghostty-web-CdfY5nPg.js → ghostty-web-DzGAsyRe.js} +1 -1
  42. package/dist-ssg/client/assets/index-1iktuOBr.css +2 -0
  43. package/dist-ssg/client/assets/index.ssg-Di9jlRtP.js +1567 -0
  44. package/dist-ssg/client/assets/{init-Bpyko6ax.js → init-C6vJVx3Z.js} +1 -1
  45. package/dist-ssg/client/assets/trpc-CRaxQyVx.js +1 -0
  46. package/dist-ssg/client/assets/webworkerAll-DNlcHyMk.js +1 -0
  47. package/dist-ssg/client/index.ssg.html +2 -2
  48. package/dist-ssg/server/entry-server.js +648 -499
  49. package/package.json +1 -1
  50. package/dist/assets/CanvasRenderer-BtLppj7_.js +0 -1
  51. package/dist/assets/WebGLRenderer-nCk7jk2Z.js +0 -1
  52. package/dist/assets/WebGPURenderer-_UsC4alI.js +0 -1
  53. package/dist/assets/browserAll-DAhverDE.js +0 -1
  54. package/dist/assets/dist-Ac4yA3M_.js +0 -1
  55. package/dist/assets/dist-CGorlcUk.js +0 -1
  56. package/dist/assets/dist-D5vd6U3w.js +0 -1
  57. package/dist/assets/index-CJqeUtB4.css +0 -1
  58. package/dist/assets/trpc-ClVlhSRF.js +0 -1
  59. package/dist/assets/webworkerAll-DyUg89C9.js +0 -1
  60. package/dist-ssg/client/assets/CanvasRenderer-D9X3OXp_.js +0 -1
  61. package/dist-ssg/client/assets/WebGLRenderer-DazMZ-UH.js +0 -1
  62. package/dist-ssg/client/assets/WebGPURenderer-Bdimghfz.js +0 -1
  63. package/dist-ssg/client/assets/browserAll-Dzfxkovh.js +0 -1
  64. package/dist-ssg/client/assets/dist-CwMFPmZN.js +0 -1
  65. package/dist-ssg/client/assets/dist-DQz6qSRZ.js +0 -1
  66. package/dist-ssg/client/assets/dist-D_OdCarj.js +0 -1
  67. package/dist-ssg/client/assets/index-B8AzCEti.css +0 -2
  68. package/dist-ssg/client/assets/index.ssg-BFU9Xt_-.js +0 -1565
  69. package/dist-ssg/client/assets/trpc-DyyVp7PI.js +0 -1
  70. package/dist-ssg/client/assets/webworkerAll-DRi5n8n7.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({
@@ -46317,23 +46317,23 @@ async function getChangeFiles(id) {
46317
46317
  files.push({
46318
46318
  path: "proposal.md",
46319
46319
  type: "file",
46320
- content: change.proposal
46320
+ content: change.sourceProposal ?? change.proposal
46321
46321
  });
46322
46322
  if (change.tasks) files.push({
46323
46323
  path: "tasks.md",
46324
46324
  type: "file",
46325
- content: change.tasks
46325
+ content: change.sourceTasks ?? change.tasks
46326
46326
  });
46327
46327
  if (change.design) files.push({
46328
46328
  path: "design.md",
46329
46329
  type: "file",
46330
- content: change.design
46330
+ content: change.sourceDesign ?? change.design
46331
46331
  });
46332
46332
  change.deltas.forEach((delta) => {
46333
46333
  files.push({
46334
46334
  path: `specs/${delta.capability}/spec.md`,
46335
46335
  type: "file",
46336
- content: delta.content
46336
+ content: delta.sourceContent ?? delta.content
46337
46337
  });
46338
46338
  });
46339
46339
  return files;
@@ -46391,17 +46391,17 @@ async function getArchiveFiles(id) {
46391
46391
  files.push({
46392
46392
  path: "proposal.md",
46393
46393
  type: "file",
46394
- content: archive.proposal
46394
+ content: archive.sourceProposal ?? archive.proposal
46395
46395
  });
46396
46396
  if (archive.tasks) files.push({
46397
46397
  path: "tasks.md",
46398
46398
  type: "file",
46399
- content: archive.tasks
46399
+ content: archive.sourceTasks ?? archive.tasks
46400
46400
  });
46401
46401
  if (archive.design) files.push({
46402
46402
  path: "design.md",
46403
46403
  type: "file",
46404
- content: archive.design
46404
+ content: archive.sourceDesign ?? archive.design
46405
46405
  });
46406
46406
  return files;
46407
46407
  }
@@ -84588,7 +84588,7 @@ function restoreViewportScroll(viewport, panel, targetScrollTop) {
84588
84588
  };
84589
84589
  requestAnimationFrame(retry);
84590
84590
  }
84591
- function hasVerticalScrollBehavior(overflowY) {
84591
+ function hasVerticalScrollBehavior$1(overflowY) {
84592
84592
  return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
84593
84593
  }
84594
84594
  function findScrollableDescendant(panel) {
@@ -84597,7 +84597,7 @@ function findScrollableDescendant(panel) {
84597
84597
  while (walker.nextNode()) {
84598
84598
  const node = walker.currentNode;
84599
84599
  if (!(node instanceof HTMLElement)) continue;
84600
- if (!hasVerticalScrollBehavior(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
84600
+ if (!hasVerticalScrollBehavior$1(window.getComputedStyle(node).overflowY) || node.scrollHeight <= node.clientHeight) continue;
84601
84601
  if (node.scrollTop > 0) return node;
84602
84602
  candidate ??= node;
84603
84603
  }
@@ -84680,12 +84680,12 @@ function resolveViewportBoundary(panel, viewportSelector) {
84680
84680
  function resolveScrollViewport(panel, boundary) {
84681
84681
  let current = panel.parentElement;
84682
84682
  while (current) {
84683
- 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;
84684
84684
  if (boundary && current === boundary) break;
84685
84685
  current = current.parentElement;
84686
84686
  }
84687
84687
  if (!boundary) return null;
84688
- if (hasVerticalScrollBehavior(window.getComputedStyle(boundary).overflowY)) return boundary;
84688
+ if (hasVerticalScrollBehavior$1(window.getComputedStyle(boundary).overflowY)) return boundary;
84689
84689
  return null;
84690
84690
  }
84691
84691
  function resolveTabScrollElements(handle, tabId, viewportSelector) {
@@ -102354,7 +102354,7 @@ function CodeEditor({ value, onChange, readOnly = false, language, filename, lin
102354
102354
  bracketMatching: !readOnly
102355
102355
  },
102356
102356
  extensions,
102357
- className: `scrollbar-thin scrollbar-track-transparent overflow-auto ${className}`,
102357
+ className: `min-h-0 overflow-hidden ${className}`,
102358
102358
  style: {
102359
102359
  fontSize,
102360
102360
  ["--code-editor-min-height"]: editorMinHeight,
@@ -102662,6 +102662,7 @@ var layoutStyles = String.raw`
102662
102662
  display: flex;
102663
102663
  flex-direction: column;
102664
102664
  flex: 1;
102665
+ min-height: 0;
102665
102666
  }
102666
102667
 
102667
102668
  /* 宽屏:grid 布局,文件列表在右侧 */
@@ -102670,6 +102671,7 @@ var layoutStyles = String.raw`
102670
102671
  display: grid;
102671
102672
  grid-template-columns: minmax(0, 1fr) minmax(240px, clamp(240px, 30%, 420px));
102672
102673
  gap: 1rem;
102674
+ min-height: 0;
102673
102675
  }
102674
102676
  .fev-sidebar-tabs {
102675
102677
  display: none;
@@ -102974,21 +102976,110 @@ function FileExplorer({ entries, selectedPath, onSelect, breadcrumbRoot, headerL
102974
102976
  })]
102975
102977
  });
102976
102978
  }
102977
- function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWrapping }) {
102979
+ function FileExplorerCodeEditor({ file, value, readOnly = true, onChange, lineWrapping, editorMinHeight }) {
102978
102980
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
102979
102981
  value,
102980
102982
  filename: file.path,
102981
102983
  readOnly,
102982
102984
  lineWrapping,
102983
102985
  className: "min-h-0 flex-1",
102986
+ editorMinHeight,
102984
102987
  onChange
102985
102988
  }, file.path);
102986
102989
  }
102987
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
102988
103074
  //#region src/components/folder-editor-viewer.tsx
102989
103075
  function FolderEditorViewer({ changeId, archived = false }) {
102990
103076
  const { data: files, isLoading, error } = archived ? useArchiveFilesSubscription(changeId) : useChangeFilesSubscription(changeId);
102991
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
+ });
102992
103083
  const sortedEntries = (0, import_react.useMemo)(() => {
102993
103084
  if (!files) return [];
102994
103085
  return [...files];
@@ -103008,18 +103099,31 @@ function FolderEditorViewer({ changeId, archived = false }) {
103008
103099
  className: "border-destructive/50 bg-destructive/10 text-destructive rounded-md border p-4 text-sm",
103009
103100
  children: ["Failed to load files: ", error.message]
103010
103101
  });
103011
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
103012
- entries: sortedEntries,
103013
- selectedPath,
103014
- onSelect: setSelectedPath,
103015
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this change." }),
103016
- renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
103017
- file: activeFile,
103018
- value: activeFile.content ?? "",
103019
- readOnly: true
103020
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103021
- className: "text-muted-foreground flex h-full items-center justify-center",
103022
- 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
+ })
103023
103127
  })
103024
103128
  });
103025
103129
  }
@@ -103887,7 +103991,7 @@ function ChangeView() {
103887
103991
  */
103888
103992
  function ButtonGroup({ value, options, onChange, className = "", tone = "default" }) {
103889
103993
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
103890
- 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}`,
103891
103995
  children: options.map((option, index) => {
103892
103996
  const active = option.value === value;
103893
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";
@@ -146332,6 +146436,16 @@ function isCoreWorkflowSelection(workflows) {
146332
146436
  function createRunnerLineId() {
146333
146437
  return typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2);
146334
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
+ }
146335
146449
  function JsonStructuredValue({ value }) {
146336
146450
  if (value === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
146337
146451
  className: "text-muted-foreground font-mono text-xs",
@@ -146389,6 +146503,8 @@ function JsonStructuredValue({ value }) {
146389
146503
  }
146390
146504
  function Config() {
146391
146505
  const isStatic = isStaticMode();
146506
+ const { viewportHeight: schemaViewportHeight, setViewportNode: setSchemaViewportNode } = useTabPanelViewportHeight();
146507
+ const { viewportHeight: projectConfigViewportHeight, setViewportNode: setProjectConfigViewportNode } = useTabPanelViewportHeight();
146392
146508
  const [schemaMode, setSchemaMode] = (0, import_react.useState)("read");
146393
146509
  const [schemaActionError, setSchemaActionError] = (0, import_react.useState)(null);
146394
146510
  const [schemaEntryError, setSchemaEntryError] = (0, import_react.useState)(null);
@@ -147224,416 +147340,426 @@ function Config() {
147224
147340
  if (isPendingCommandRunning) return;
147225
147341
  setPendingCommandKind(null);
147226
147342
  }, [isPendingCommandRunning]);
147227
- const schemaTabContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147228
- className: "flex min-h-0 flex-1 flex-col gap-4",
147229
- children: [
147230
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147231
- className: "flex flex-wrap items-center justify-between gap-3",
147232
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonGroup, {
147233
- value: schemaMode,
147234
- onChange: handleSchemaModeChange,
147235
- options: [
147236
- {
147237
- value: "read",
147238
- label: "Read"
147239
- },
147240
- {
147241
- value: "preview",
147242
- label: "Preview"
147243
- },
147244
- {
147245
- value: "edit",
147246
- label: "Edit",
147247
- disabled: !schemaCanEdit
147248
- }
147249
- ]
147250
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147251
- className: "flex items-center gap-2",
147252
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147253
- type: "button",
147254
- onClick: handleAddSchema,
147255
- disabled: isStatic || createSchemaMutation.isPending,
147256
- 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",
147257
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" }), "Add"]
147258
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147259
- type: "button",
147260
- onClick: handleDeleteSchema,
147261
- disabled: !schemaCanEdit || deleteSchemaMutation.isPending,
147262
- 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",
147263
- 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
+ })]
147264
147384
  })]
147265
- })]
147266
- }),
147267
- schemaActionError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147268
- className: "text-destructive text-xs",
147269
- children: schemaActionError
147270
- }),
147271
- schemaEntryError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147272
- className: "text-destructive text-xs",
147273
- children: schemaEntryError
147274
- }),
147275
- schemasError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147276
- className: "text-destructive text-sm",
147277
- children: ["Failed to load schemas: ", schemasError.message]
147278
- }),
147279
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147280
- className: "flex min-h-0 flex-1 flex-col",
147281
- children: [
147282
- schemasLoading && (!schemas || schemas.length === 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147283
- className: "text-muted-foreground mb-3 text-sm",
147284
- children: "Loading schemas…"
147285
- }),
147286
- schemas && schemas.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147287
- className: "text-muted-foreground mb-3 text-sm",
147288
- children: "No schemas available."
147289
- }),
147290
- selectedSchemaInfo ? schemaMode === "preview" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147291
- className: "min-h-0 flex-1",
147292
- markdown: ({ H1, H2, H3, Section }) => {
147293
- const anchorBase = `schema-${selectedSchemaInfo.name}`;
147294
- const schemaAnchor = (suffix) => `${anchorBase}-${suffix}`;
147295
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147296
- className: "space-y-6",
147297
- children: [
147298
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H1, {
147299
- id: anchorBase,
147300
- children: selectedSchemaInfo.name
147301
- }), selectedSchemaInfo.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147302
- className: "text-muted-foreground",
147303
- children: selectedSchemaInfo.description
147304
- })] }),
147305
- schemaResolution && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147306
- id: schemaAnchor("resolution"),
147307
- children: "Resolution"
147308
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147309
- className: "text-muted-foreground mt-2 space-y-1 pl-4 text-sm",
147310
- children: [
147311
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: ["Source: ", schemaResolution.source] }),
147312
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147313
- className: "truncate",
147314
- 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"
147315
147455
  }),
147316
- schemaResolution.shadows.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
147317
- "Shadows:",
147318
- " ",
147319
- schemaResolution.shadows.map((s) => `${s.source}(${s.displayPath ?? s.path})`).join(", ")
147320
- ] })
147321
- ]
147322
- })] }),
147323
- schemaPreview.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147324
- id: schemaAnchor("schema-errors"),
147325
- children: "Schema errors"
147326
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147327
- className: "border-destructive/40 bg-destructive/10 text-destructive mt-2 rounded-md border px-3 py-2 text-sm",
147328
- children: ["schema.yaml parse error: ", schemaPreview.error]
147329
- })] }),
147330
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [
147331
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
147332
- id: schemaAnchor("artifacts"),
147333
- children: "Artifacts"
147334
- }),
147335
- previewArtifacts.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147336
- className: "mt-3 space-y-6",
147337
- children: previewArtifacts.map((artifact) => {
147338
- const rawArtifact = rawArtifactMap.get(artifact.id);
147339
- const templateInfo = templateContents?.[artifact.id] ?? (templates?.[artifact.id] ? {
147340
- ...templates[artifact.id],
147341
- content: null
147342
- } : null);
147343
- const templatePath = templateInfo?.path ?? (typeof rawArtifact?.template === "string" ? rawArtifact.template : void 0);
147344
- const templateDisplayPath = templateInfo?.displayPath ?? templatePath ?? null;
147345
- const draftTemplateContent = templatePath !== void 0 ? draftByPath.get(templatePath) : void 0;
147346
- const templateBody = draftTemplateContent !== void 0 ? draftTemplateContent : templateInfo ? templateInfo.content : null;
147347
- const knownFields = [
147348
- ["id", rawArtifact?.id ?? artifact.id],
147349
- ["generates", rawArtifact?.generates ?? artifact.outputPath],
147350
- ["description", rawArtifact?.description ?? artifact.description],
147351
- ["instruction", rawArtifact?.instruction],
147352
- ["requires", rawArtifact?.requires ?? artifact.requires]
147353
- ].filter((entry) => entry[1] !== void 0);
147354
- const unknownEntries = rawArtifact ? Object.entries(rawArtifact).filter(([key]) => !KNOWN_ARTIFACT_KEYS.has(key)) : [];
147355
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
147356
- className: "space-y-3",
147357
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H3, {
147358
- id: schemaAnchor(`artifact-${artifact.id}`),
147359
- children: artifact.id
147360
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147361
- className: "border-border space-y-4 rounded-lg border px-4 py-4 text-sm",
147362
- children: [
147363
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147364
- className: "space-y-3",
147365
- children: knownFields.map(([key, value]) => {
147366
- const isRequires = key === "requires";
147367
- const requires = isRequires ? Array.isArray(value) ? value.filter((item) => typeof item === "string") : [] : [];
147368
- 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", {
147369
147559
  className: "space-y-2",
147370
147560
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147371
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147561
+ className: "text-muted-foreground text-xs",
147372
147562
  children: key
147373
147563
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147374
147564
  className: "pl-4 text-sm leading-6",
147375
- children: isRequires ? requires.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147376
- className: "flex flex-wrap gap-1.5",
147377
- children: requires.map((requiredArtifactId) => {
147378
- if (!previewArtifacts.some((candidate) => candidate.id === requiredArtifactId)) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147379
- className: "bg-muted text-muted-foreground rounded-md px-2 py-0.5 text-xs",
147380
- children: requiredArtifactId
147381
- }, requiredArtifactId);
147382
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
147383
- href: `#${schemaAnchor(`artifact-${requiredArtifactId}`)}`,
147384
- className: "bg-primary hover:bg-primary/80 text-primary-foreground rounded-md px-2 py-0.5 text-xs transition-colors",
147385
- children: requiredArtifactId
147386
- }, requiredArtifactId);
147387
- })
147388
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147389
- className: "text-muted-foreground",
147390
- children: "—"
147391
- }) : renderFieldValue(key, value)
147565
+ children: renderFieldValue(key, value)
147392
147566
  })]
147393
- }, key);
147567
+ }, key))]
147394
147568
  })
147395
- }),
147396
- templatePath && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147397
- className: "space-y-2",
147398
- children: [
147399
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147400
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147401
- children: "Template"
147402
- }),
147403
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147404
- className: "text-muted-foreground pl-4 text-xs",
147405
- children: [
147406
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147407
- className: "mr-1",
147408
- children: "Template:"
147409
- }),
147410
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
147411
- className: "bg-muted rounded px-1",
147412
- children: templateDisplayPath
147413
- }),
147414
- templateInfo?.source ? ` (${templateInfo.source})` : null
147415
- ]
147416
- }),
147417
- templateBody !== null && templateBody !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147418
- className: "pl-4",
147419
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147420
- className: "bg-muted/30 rounded-lg p-4 [zoom:0.86]",
147421
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
147422
- markdown: templateBody,
147423
- collectToc: false
147424
- })
147425
- })
147426
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147427
- className: "text-muted-foreground pl-4 text-sm",
147428
- children: "Template content unavailable."
147429
- })
147430
- ]
147431
- }),
147432
- unknownEntries.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147433
- className: "space-y-3",
147434
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147435
- className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide",
147436
- children: "Extra fields"
147437
- }), unknownEntries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147438
- className: "space-y-2",
147439
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147440
- className: "text-muted-foreground text-xs",
147441
- children: key
147442
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147443
- className: "pl-4 text-sm leading-6",
147444
- children: renderFieldValue(key, value)
147445
- })]
147446
- }, key))]
147447
- })
147448
- ]
147449
- })]
147450
- }, artifact.id);
147451
- })
147452
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147453
- className: "text-muted-foreground text-sm",
147454
- children: "Select a schema to view details."
147455
- }),
147456
- schemaDetail?.applyRequires?.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147457
- className: "text-muted-foreground mt-3 text-xs",
147458
- children: ["Apply requires: ", schemaDetail.applyRequires.join(", ")]
147459
- }) : null
147460
- ] }),
147461
- hasDirtyDrafts && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147462
- className: "text-muted-foreground text-xs",
147463
- children: "Preview is rendering draft content. Save to persist changes."
147464
- })
147465
- ]
147466
- });
147467
- }
147468
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuWrapper, {
147469
- ref: schemaMenuWrapperRef,
147470
- className: "h-full space-y-4",
147471
- children: [
147472
- schemaFilesError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147473
- className: "text-destructive text-xs",
147474
- children: ["Failed to load schema files: ", schemaFilesError.message]
147475
- }),
147476
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorer, {
147477
- entries: schemaEntries,
147478
- selectedPath: selectedSchemaPath,
147479
- onSelect: setSelectedSchemaPath,
147480
- breadcrumbRoot: schemaRootLabel,
147481
- headerLabel: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
147482
- className: "flex min-w-0 items-center gap-2",
147483
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147484
- className: "uppercase tracking-wide",
147485
- children: "Files"
147486
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
147487
- className: "text-muted-foreground/80 truncate text-[10px] normal-case",
147488
- title: schemaRootLabel,
147489
- children: schemaRootLabel
147490
- })]
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]
147491
147596
  }),
147492
- headerActions: headerMenuItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147493
- type: "button",
147494
- onClick: (event) => {
147495
- setFileMenuAnchor(null);
147496
- setViewMenuAnchor(null);
147497
- setHeaderMenuAnchor({
147498
- type: "target",
147499
- element: event.currentTarget,
147500
- placement: "bottom-end"
147501
- });
147502
- },
147503
- className: "hover:bg-muted rounded-md p-1",
147504
- "aria-label": "Schema menu",
147505
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EllipsisVertical, { className: "h-4 w-4" })
147506
- }) }) : void 0,
147507
- entryActions: (entry) => {
147508
- const propertiesAction = {
147509
- id: "properties",
147510
- label: "Properties",
147511
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Info$1, { className: "h-3.5 w-3.5" }),
147512
- onSelect: () => handleOpenEntryInfo(entry)
147513
- };
147514
- if (schemaMode !== "edit" || !canManageEntries) return [propertiesAction];
147515
- const parent = entry.type === "directory" ? entry.path : getParentPath(entry.path);
147516
- const isDirectory = entry.type === "directory";
147517
- return [
147518
- {
147519
- id: "new-file",
147520
- label: isDirectory ? "New file inside" : "New sibling file",
147521
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilePlus, { className: "h-3.5 w-3.5" }),
147522
- onSelect: () => handleOpenCreateEntry("file", parent)
147523
- },
147524
- {
147525
- id: "new-folder",
147526
- label: isDirectory ? "New folder inside" : "New sibling folder",
147527
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderPlus, { className: "h-3.5 w-3.5" }),
147528
- onSelect: () => handleOpenCreateEntry("directory", parent)
147529
- },
147530
- propertiesAction,
147531
- {
147532
- id: "delete",
147533
- label: "Delete",
147534
- icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2, { className: "h-3.5 w-3.5" }),
147535
- tone: "destructive",
147536
- onSelect: () => handleOpenDeleteEntry(entry)
147537
- }
147538
- ];
147539
- },
147540
- emptyState: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "No files found for this schema." }),
147541
- renderEditor: (activeFile) => activeFile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147542
- className: "flex min-h-0 flex-1 flex-col",
147543
- children: [
147544
- schemaMode === "edit" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147545
- className: "border-border/50 flex items-center justify-between border-b px-3 py-2 text-xs",
147546
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147547
- className: "flex items-center gap-2",
147548
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147549
- type: "button",
147550
- onClick: (event) => {
147551
- setHeaderMenuAnchor(null);
147552
- setViewMenuAnchor(null);
147553
- setFileMenuAnchor({
147554
- type: "target",
147555
- element: event.currentTarget,
147556
- placement: "bottom-start"
147557
- });
147558
- },
147559
- className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147560
- children: "File"
147561
- }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTargeter, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147562
- type: "button",
147563
- onClick: (event) => {
147564
- setHeaderMenuAnchor(null);
147565
- setFileMenuAnchor(null);
147566
- setViewMenuAnchor({
147567
- type: "target",
147568
- element: event.currentTarget,
147569
- placement: "bottom-start"
147570
- });
147571
- },
147572
- className: "hover:bg-muted rounded-md px-2 py-1 text-xs font-semibold",
147573
- children: "View"
147574
- }) })]
147575
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147576
- className: "flex items-center gap-2",
147577
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147578
- type: "button",
147579
- onClick: handleFileCancel,
147580
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147581
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147582
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147583
- type: "button",
147584
- onClick: handleFileSave,
147585
- disabled: !activeSchemaDirty || saveSchemaFileMutation.isPending || !schemaCanEdit,
147586
- 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",
147587
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Save, { className: "h-3.5 w-3.5" }), saveSchemaFileMutation.isPending ? "Saving…" : "Save"]
147588
- })]
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
147589
147613
  })]
147590
147614
  }),
147591
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileExplorerCodeEditor, {
147592
- file: activeFile,
147593
- value: schemaMode === "edit" ? activeSchemaDraft ?? activeFile.content ?? "" : activeFile.content ?? "",
147594
- readOnly: schemaMode !== "edit" || !schemaCanEdit,
147595
- onChange: schemaMode === "edit" ? handleFileChange : void 0,
147596
- lineWrapping: schemaEditorWrap
147597
- }),
147598
- schemaResolution?.source === "package" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147599
- className: "text-muted-foreground border-border/50 border-t px-3 py-2 text-xs",
147600
- 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"
147601
147730
  })
147602
- ]
147603
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147604
- className: "text-muted-foreground flex h-full items-center justify-center",
147605
- 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)
147606
147753
  })
147607
- }),
147608
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147609
- open: !!headerMenuAnchor,
147610
- items: headerMenuItems,
147611
- anchor: headerMenuAnchor,
147612
- boundaryElement: schemaMenuWrapperRef.current,
147613
- onClose: () => setHeaderMenuAnchor(null)
147614
- }),
147615
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147616
- open: !!fileMenuAnchor,
147617
- items: fileMenuItems,
147618
- anchor: fileMenuAnchor,
147619
- boundaryElement: schemaMenuWrapperRef.current,
147620
- onClose: () => setFileMenuAnchor(null)
147621
- }),
147622
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenu, {
147623
- open: !!viewMenuAnchor,
147624
- items: viewMenuItems,
147625
- anchor: viewMenuAnchor,
147626
- boundaryElement: schemaMenuWrapperRef.current,
147627
- onClose: () => setViewMenuAnchor(null)
147628
- })
147629
- ]
147630
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147631
- className: "text-muted-foreground text-sm",
147632
- children: "Select a schema to view details."
147633
- })
147634
- ]
147635
- })
147636
- ]
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
+ })
147637
147763
  });
147638
147764
  const schemaTabs = (schemas ?? []).map((schema) => ({
147639
147765
  id: `schema:${schema.name}`,
@@ -147642,79 +147768,101 @@ function Config() {
147642
147768
  content: schemaTabContent
147643
147769
  }));
147644
147770
  const projectConfigTabContent = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147645
- className: "space-y-4",
147646
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147647
- className: "border-border bg-card space-y-4 rounded-lg border p-4",
147648
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147649
- className: "flex flex-wrap items-center justify-between gap-2",
147650
- children: [
147651
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147652
- className: "text-sm font-semibold",
147653
- children: "OpenSpec Project Config"
147654
- }),
147655
- !isStatic && configYaml && !isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147656
- type: "button",
147657
- onClick: handleConfigEdit,
147658
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147659
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pen, { className: "h-3.5 w-3.5" }), "Edit"]
147660
- }),
147661
- isConfigEditing && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147662
- className: "flex items-center gap-2",
147663
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
147664
- type: "button",
147665
- onClick: handleConfigCancel,
147666
- className: "border-border hover:bg-muted inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-xs font-medium",
147667
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(X$2, { className: "h-3.5 w-3.5" }), "Cancel"]
147668
- }), /* @__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", {
147669
147829
  type: "button",
147670
- onClick: () => saveConfigMutation.mutate(),
147671
- disabled: !configDirty || saveConfigMutation.isPending,
147672
- 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",
147673
- 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"
147674
147833
  })]
147675
- })
147676
- ]
147677
- }), configYaml || isConfigEditing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
147678
- value: configDraft,
147679
- onChange: (value) => {
147680
- setConfigDraft(value);
147681
- setConfigDirty(true);
147682
- },
147683
- readOnly: !isConfigEditing,
147684
- filename: "config.yaml"
147685
- }) : configLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147686
- className: "route-loading animate-pulse",
147687
- children: "Loading config…"
147688
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147689
- className: "text-muted-foreground rounded-md border border-dashed p-4 text-sm",
147690
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
147691
- className: "mb-3",
147692
- children: "openspec/config.yaml not found."
147693
- }), !isStatic && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
147694
- type: "button",
147695
- onClick: handleConfigEdit,
147696
- className: "bg-primary text-primary-foreground inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium",
147697
- children: "Create config.yaml"
147698
- })]
147699
- })]
147834
+ })]
147835
+ })
147836
+ })
147700
147837
  })
147701
147838
  });
147702
- const globalConfigTabContent = isStatic ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147703
- className: "space-y-3",
147704
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147705
- className: "text-sm font-semibold",
147706
- children: "OpenSpec Global Config"
147707
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147708
- className: "text-muted-foreground rounded-md border border-dashed p-4 text-sm",
147709
- children: "Global config commands are unavailable in static export mode."
147710
- })]
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
+ })
147711
147858
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
147712
- 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",
147713
147861
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147714
- 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",
147715
147863
  children: [
147716
147864
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147717
- className: "flex flex-wrap items-center justify-between gap-2",
147865
+ className: "flex flex-none flex-wrap items-center justify-between gap-2",
147718
147866
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
147719
147867
  className: "text-sm font-semibold",
147720
147868
  children: "OpenSpec Global Config"
@@ -147744,7 +147892,7 @@ function Config() {
147744
147892
  })]
147745
147893
  }),
147746
147894
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147747
- className: "text-muted-foreground text-xs",
147895
+ className: "text-muted-foreground flex-none text-xs",
147748
147896
  children: [
147749
147897
  "Reads from ",
147750
147898
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "openspec config list --json" }),
@@ -147777,7 +147925,7 @@ function Config() {
147777
147925
  className: "text-muted-foreground text-sm",
147778
147926
  children: "Loading global config…"
147779
147927
  }) : isRecordObject(globalConfigData) ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147780
- className: "space-y-3",
147928
+ className: "min-h-0 flex-1 space-y-3 overflow-auto pr-1",
147781
147929
  children: [
147782
147930
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147783
147931
  className: "grid gap-2 sm:grid-cols-2",
@@ -147843,7 +147991,7 @@ function Config() {
147843
147991
  className: "text-muted-foreground text-sm",
147844
147992
  children: "Global config unavailable."
147845
147993
  }) : globalConfigTab === "editor" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147846
- className: "space-y-2",
147994
+ className: "flex min-h-0 flex-1 flex-col gap-2 overflow-hidden",
147847
147995
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CodeEditor, {
147848
147996
  value: globalConfigDraft,
147849
147997
  onChange: (value) => {
@@ -147854,7 +148002,8 @@ function Config() {
147854
148002
  readOnly: saveGlobalConfigMutation.isPending,
147855
148003
  filename: "openspec.global.config.json",
147856
148004
  language: "json",
147857
- editorMinHeight: "260px"
148005
+ className: "min-h-0 flex-1",
148006
+ editorMinHeight: "0px"
147858
148007
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147859
148008
  className: "flex items-center justify-end gap-2",
147860
148009
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
@@ -147876,9 +148025,9 @@ function Config() {
147876
148025
  })]
147877
148026
  })]
147878
148027
  }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147879
- 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)]",
147880
148029
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147881
- className: "space-y-4",
148030
+ className: "min-h-0 space-y-4 overflow-auto pr-1",
147882
148031
  children: [
147883
148032
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
147884
148033
  className: "grid gap-2 sm:grid-cols-3 xl:grid-cols-1",
@@ -147989,7 +148138,7 @@ function Config() {
147989
148138
  })
147990
148139
  ]
147991
148140
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
147992
- className: "space-y-3",
148141
+ className: "space-y-3 overflow-auto pr-1",
147993
148142
  children: [profileEditMode === "both" || profileEditMode === "workflows" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
147994
148143
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
147995
148144
  className: "text-muted-foreground text-xs",