@tangle-network/agent-app 0.49.27 → 0.49.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ import {
2
+ VaultPane
3
+ } from "./chunk-FCUWRMAF.js";
4
+ export {
5
+ VaultPane
6
+ };
7
+ //# sourceMappingURL=VaultPane-32HVWZ6A.js.map
@@ -310,6 +310,22 @@ function VaultPane(props) {
310
310
  const [treeError, setTreeError] = useState(null);
311
311
  const [internalPath, setInternalPath] = useState(null);
312
312
  const selectedPath = controlled ? controlledPath ?? null : internalPath;
313
+ const [filesOpen, setFilesOpen] = useState(false);
314
+ const showFiles = filesOpen || !selectedPath;
315
+ const searchRef = useRef2(null);
316
+ const documentRef = useRef2(null);
317
+ useEffect2(() => {
318
+ setFilesOpen(false);
319
+ }, [selectedPath]);
320
+ const showDocument = useCallback(() => {
321
+ const focused = document.activeElement;
322
+ setFilesOpen(false);
323
+ requestAnimationFrame(() => {
324
+ if (document.activeElement === focused || document.activeElement === document.body) {
325
+ documentRef.current?.focus({ preventScroll: true });
326
+ }
327
+ });
328
+ }, []);
313
329
  const [selectedFile, setSelectedFile] = useState(null);
314
330
  const [fileLoading, setFileLoading] = useState(false);
315
331
  const [readError, setReadError] = useState(null);
@@ -490,14 +506,18 @@ function VaultPane(props) {
490
506
  }, [selectedFile?.path, selectedFile?.content, activeCodec]);
491
507
  const guardedOpen = useCallback(
492
508
  (path) => {
493
- if (path === selectedPath) return;
509
+ if (path === selectedPath) {
510
+ showDocument();
511
+ return;
512
+ }
494
513
  if (isDirty) {
495
514
  setPendingNav({ type: "open", path });
496
515
  return;
497
516
  }
517
+ showDocument();
498
518
  commitPath(path);
499
519
  },
500
- [isDirty, selectedPath, commitPath]
520
+ [isDirty, selectedPath, commitPath, showDocument]
501
521
  );
502
522
  const toggleFolder = useCallback((path) => {
503
523
  setFolderPath((current) => current === path ? null : path);
@@ -528,12 +548,13 @@ function VaultPane(props) {
528
548
  setIsDirty(false);
529
549
  if (!nav) return;
530
550
  if (nav.type === "open") {
551
+ showDocument();
531
552
  commitPath(nav.path);
532
553
  } else {
533
554
  commitPath(null);
534
555
  setSelectedFile(null);
535
556
  }
536
- }, [pendingNav, commitPath]);
557
+ }, [pendingNav, commitPath, showDocument]);
537
558
  const showRichMode = useCallback(() => {
538
559
  setEditorMode((mode) => {
539
560
  if (mode === "rich") return mode;
@@ -646,180 +667,226 @@ function VaultPane(props) {
646
667
  return /* @__PURE__ */ jsx2(EditorErrorBoundary, { onReset: () => {
647
668
  commitPath(null);
648
669
  setSelectedFile(null);
649
- }, children: /* @__PURE__ */ jsxs2("div", { className: `flex min-h-0 flex-1 overflow-hidden ${className ?? ""}`, children: [
650
- /* @__PURE__ */ jsxs2("div", { className: "flex w-[23rem] min-w-[23rem] flex-col border-r border-border bg-background", children: [
651
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
652
- /* @__PURE__ */ jsx2("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx2(
653
- "input",
670
+ }, children: /* @__PURE__ */ jsxs2("div", { className: `flex min-h-0 min-w-0 flex-1 overflow-hidden ${className ?? ""}`, children: [
671
+ /* @__PURE__ */ jsxs2("div", { className: "@container/vault flex min-w-0 flex-1 flex-col", children: [
672
+ /* @__PURE__ */ jsxs2("nav", { "aria-label": "Vault navigation", className: "flex shrink-0 items-center gap-1 border-b border-border p-2 @[45rem]/vault:hidden", children: [
673
+ /* @__PURE__ */ jsx2(
674
+ "button",
654
675
  {
655
- type: "text",
656
- value: query,
657
- onChange: (e) => setQuery(e.target.value),
658
- placeholder: activeFolder ? `Search ${activeFolder}\u2026` : "Search\u2026",
659
- "aria-label": "Search vault",
660
- className: "h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground"
676
+ type: "button",
677
+ "aria-pressed": showFiles,
678
+ onClick: () => {
679
+ const focused = document.activeElement;
680
+ setFilesOpen(true);
681
+ requestAnimationFrame(() => {
682
+ if (document.activeElement === focused || document.activeElement === document.body) {
683
+ searchRef.current?.focus();
684
+ }
685
+ });
686
+ },
687
+ className: `shrink-0 rounded-md px-3 py-2 text-sm ${showFiles ? "bg-muted font-medium text-foreground" : "text-muted-foreground hover:bg-muted"}`,
688
+ children: "Files"
661
689
  }
662
- ) }),
663
- /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1", children: [
664
- headerActions,
665
- /* @__PURE__ */ jsx2(
666
- "button",
667
- {
668
- type: "button",
669
- "aria-label": "Refresh vault",
670
- onClick: () => void refresh(),
671
- className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
672
- children: "\u21BB"
673
- }
674
- ),
675
- canWrite && /* @__PURE__ */ jsx2(
676
- "button",
677
- {
678
- type: "button",
679
- "aria-label": activeFolder ? `New vault file in ${activeFolder}` : "New vault file",
680
- onClick: () => {
681
- setCreateError(null);
682
- setNewPath(activeFolder ? `${activeFolder}/` : "");
683
- setCreateOpen(true);
684
- },
685
- className: "inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
686
- children: "+"
687
- }
688
- )
689
- ] })
690
- ] }),
691
- activeFolder && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 border-b border-border bg-muted/40 px-4 py-1.5 text-xs", children: [
692
- /* @__PURE__ */ jsx2(Folder, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
693
- /* @__PURE__ */ jsx2("span", { "data-vault-folder": true, className: "min-w-0 flex-1 truncate font-medium text-foreground", title: activeFolder, children: activeFolder }),
694
- /* @__PURE__ */ jsx2(
690
+ ),
691
+ selectedPath && /* @__PURE__ */ jsx2(
695
692
  "button",
696
693
  {
697
694
  type: "button",
698
- "aria-label": "Clear the active folder",
699
- onClick: () => setFolderPath(null),
700
- className: "shrink-0 rounded px-1 text-muted-foreground underline-offset-2 transition-colors hover:text-foreground hover:underline",
701
- children: "Clear"
695
+ "aria-pressed": !showFiles,
696
+ onClick: showDocument,
697
+ title: selectedPath,
698
+ className: `min-w-0 truncate rounded-md px-3 py-2 text-sm ${!showFiles ? "bg-muted font-medium text-foreground" : "text-muted-foreground hover:bg-muted"}`,
699
+ children: selectedPath.split("/").pop()
702
700
  }
703
701
  )
704
702
  ] }),
705
- /* @__PURE__ */ jsx2(
706
- "div",
707
- {
708
- className: "flex-1 overflow-y-auto",
709
- onClickCapture: (event) => {
710
- const target = treeClickTarget(event);
711
- if (target) handleTreeSelect(target.path);
712
- },
713
- children: treeContent
714
- }
715
- )
716
- ] }),
717
- /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", children: [
718
- selectedFile && /* @__PURE__ */ jsxs2("div", { className: `flex shrink-0 items-center justify-between border-b border-border px-4 py-1.5 ${pathBarClassName ?? "bg-card"}`, children: [
719
- /* @__PURE__ */ jsx2("span", { "data-vault-path": true, className: "truncate text-xs font-medium text-foreground", children: selectedFile.path }),
720
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1", children: [
721
- canWrite && isMarkdownCapable && /* @__PURE__ */ jsxs2("div", { className: "mr-1 flex items-center gap-1", children: [
722
- /* @__PURE__ */ jsx2(
723
- "button",
703
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-h-0 min-w-0 flex-1", children: [
704
+ /* @__PURE__ */ jsxs2("div", { "data-vault-tree": true, className: `${showFiles ? "flex" : "hidden"} min-w-0 flex-1 flex-col border-r border-border bg-background @[45rem]/vault:flex @[45rem]/vault:w-[23rem] @[45rem]/vault:min-w-[23rem] @[45rem]/vault:flex-none`, children: [
705
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
706
+ /* @__PURE__ */ jsx2("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx2(
707
+ "input",
724
708
  {
725
- type: "button",
726
- "aria-label": "Edit as rich text",
727
- "aria-pressed": editorMode === "rich",
728
- onClick: showRichMode,
729
- className: `inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${editorMode === "rich" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
730
- children: "Rich"
709
+ ref: searchRef,
710
+ type: "text",
711
+ value: query,
712
+ onChange: (e) => setQuery(e.target.value),
713
+ placeholder: activeFolder ? `Search ${activeFolder}\u2026` : "Search\u2026",
714
+ "aria-label": "Search vault",
715
+ className: "h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground"
731
716
  }
732
- ),
717
+ ) }),
718
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1", children: [
719
+ headerActions,
720
+ /* @__PURE__ */ jsx2(
721
+ "button",
722
+ {
723
+ type: "button",
724
+ "aria-label": "Refresh vault",
725
+ onClick: () => void refresh(),
726
+ className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
727
+ children: "\u21BB"
728
+ }
729
+ ),
730
+ canWrite && /* @__PURE__ */ jsx2(
731
+ "button",
732
+ {
733
+ type: "button",
734
+ "aria-label": activeFolder ? `New vault file in ${activeFolder}` : "New vault file",
735
+ onClick: () => {
736
+ setCreateError(null);
737
+ setNewPath(activeFolder ? `${activeFolder}/` : "");
738
+ setCreateOpen(true);
739
+ },
740
+ className: "inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
741
+ children: "+"
742
+ }
743
+ )
744
+ ] })
745
+ ] }),
746
+ activeFolder && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 border-b border-border bg-muted/40 px-4 py-1.5 text-xs", children: [
747
+ /* @__PURE__ */ jsx2(Folder, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
748
+ /* @__PURE__ */ jsx2("span", { "data-vault-folder": true, className: "min-w-0 flex-1 truncate font-medium text-foreground", title: activeFolder, children: activeFolder }),
733
749
  /* @__PURE__ */ jsx2(
734
750
  "button",
735
751
  {
736
752
  type: "button",
737
- "aria-label": "Edit as source",
738
- "aria-pressed": editorMode === "source",
739
- onClick: showSourceMode,
740
- className: `inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${editorMode === "source" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
741
- children: "Source"
753
+ "aria-label": "Clear the active folder",
754
+ onClick: () => setFolderPath(null),
755
+ className: "shrink-0 rounded px-1 text-muted-foreground underline-offset-2 transition-colors hover:text-foreground hover:underline",
756
+ children: "Clear"
742
757
  }
743
758
  )
744
759
  ] }),
745
- renderDock && !persistentDock && /* @__PURE__ */ jsx2(
746
- "button",
747
- {
748
- type: "button",
749
- "aria-label": dockToggleCfg.label,
750
- "aria-pressed": dockOpen,
751
- disabled: (dockToggleCfg.disabledWhenDirty ?? true) && isDirty,
752
- title: (dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? "Save your changes first" : dockToggleCfg.title ?? dockToggleCfg.label,
753
- onClick: () => setDockOpen((v) => !v),
754
- className: `inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${dockOpen ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
755
- children: dockToggleCfg.label
756
- }
757
- ),
758
- onDownloadFile && /* @__PURE__ */ jsx2(
759
- "button",
760
- {
761
- type: "button",
762
- "aria-label": "Download this file",
763
- title: "Download file",
764
- onClick: () => onDownloadFile(selectedFile),
765
- className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
766
- children: /* @__PURE__ */ jsx2(Download, { className: "h-4 w-4" })
767
- }
768
- ),
769
- canWrite && /* @__PURE__ */ jsx2(
770
- "button",
760
+ /* @__PURE__ */ jsx2(
761
+ "div",
771
762
  {
772
- type: "button",
773
- "aria-label": "Delete this file",
774
- title: "Delete file",
775
- onClick: () => {
776
- setDeleteError(null);
777
- setDeleteOpen(true);
763
+ className: "flex-1 overflow-y-auto",
764
+ onClickCapture: (event) => {
765
+ const target = treeClickTarget(event);
766
+ if (target) handleTreeSelect(target.path);
778
767
  },
779
- className: "inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive",
780
- children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" })
768
+ children: treeContent
781
769
  }
782
770
  )
783
- ] })
784
- ] }),
785
- selectedFile && saveError && /* @__PURE__ */ jsx2(
786
- OperationErrorAlert,
787
- {
788
- message: saveError.message,
789
- retryLabel: "Retry save",
790
- onRetry: () => void saveCurrent(),
791
- onDismiss: () => setSaveError(null)
792
- }
793
- ),
794
- readError && selectedFile?.path === resolvedSelectedPath && /* @__PURE__ */ jsx2(
795
- OperationErrorAlert,
796
- {
797
- message: readError,
798
- retryLabel: "Retry file refresh",
799
- onRetry: () => setReloadNonce((n) => n + 1),
800
- onDismiss: () => setReadError(null)
801
- }
802
- ),
803
- /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-hidden", children: fileLoading && selectedFile?.path !== resolvedSelectedPath ? /* @__PURE__ */ jsx2(EditorSkeleton, {}) : readError && selectedFile?.path !== resolvedSelectedPath ? /* @__PURE__ */ jsx2(ReadErrorState, { message: readError, onRetry: () => setReloadNonce((n) => n + 1) }) : selectedFile && canWrite && isMarkdownCapable && editorMode === "source" ? /* @__PURE__ */ jsx2(
804
- SourceEditor,
805
- {
806
- path: selectedFile.path,
807
- content: sourceDraft,
808
- saving,
809
- dirty: isDirty,
810
- onChange: onSourceChange,
811
- onSave: () => void saveCurrent()
812
- }
813
- ) : selectedFile ? renderArtifact({
814
- file: selectedFile,
815
- loading: false,
816
- mode: editorMode,
817
- canWrite,
818
- richDraft,
819
- dirty: isDirty,
820
- onRichChange,
821
- onSave: () => void saveCurrent()
822
- }) : null })
771
+ ] }),
772
+ /* @__PURE__ */ jsxs2(
773
+ "div",
774
+ {
775
+ ref: documentRef,
776
+ role: "region",
777
+ "aria-label": "Vault document",
778
+ tabIndex: -1,
779
+ className: `${showFiles ? "hidden" : "flex"} min-w-0 flex-1 flex-col overflow-hidden @[45rem]/vault:flex`,
780
+ children: [
781
+ selectedFile && /* @__PURE__ */ jsxs2("div", { className: `flex shrink-0 items-center justify-between gap-2 border-b border-border px-4 py-1.5 ${pathBarClassName ?? "bg-card"}`, children: [
782
+ /* @__PURE__ */ jsx2("span", { "data-vault-path": true, className: "min-w-0 flex-1 truncate text-xs font-medium text-foreground", children: selectedFile.path }),
783
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1", children: [
784
+ canWrite && isMarkdownCapable && /* @__PURE__ */ jsxs2("div", { className: "mr-1 flex items-center gap-1", children: [
785
+ /* @__PURE__ */ jsx2(
786
+ "button",
787
+ {
788
+ type: "button",
789
+ "aria-label": "Edit as rich text",
790
+ "aria-pressed": editorMode === "rich",
791
+ onClick: showRichMode,
792
+ className: `inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${editorMode === "rich" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
793
+ children: "Rich"
794
+ }
795
+ ),
796
+ /* @__PURE__ */ jsx2(
797
+ "button",
798
+ {
799
+ type: "button",
800
+ "aria-label": "Edit as source",
801
+ "aria-pressed": editorMode === "source",
802
+ onClick: showSourceMode,
803
+ className: `inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${editorMode === "source" ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
804
+ children: "Source"
805
+ }
806
+ )
807
+ ] }),
808
+ renderDock && !persistentDock && /* @__PURE__ */ jsx2(
809
+ "button",
810
+ {
811
+ type: "button",
812
+ "aria-label": dockToggleCfg.label,
813
+ "aria-pressed": dockOpen,
814
+ disabled: (dockToggleCfg.disabledWhenDirty ?? true) && isDirty,
815
+ title: (dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? "Save your changes first" : dockToggleCfg.title ?? dockToggleCfg.label,
816
+ onClick: () => setDockOpen((v) => !v),
817
+ className: `inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${dockOpen ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
818
+ children: dockToggleCfg.label
819
+ }
820
+ ),
821
+ onDownloadFile && /* @__PURE__ */ jsx2(
822
+ "button",
823
+ {
824
+ type: "button",
825
+ "aria-label": "Download this file",
826
+ title: "Download file",
827
+ onClick: () => onDownloadFile(selectedFile),
828
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
829
+ children: /* @__PURE__ */ jsx2(Download, { className: "h-4 w-4" })
830
+ }
831
+ ),
832
+ canWrite && /* @__PURE__ */ jsx2(
833
+ "button",
834
+ {
835
+ type: "button",
836
+ "aria-label": "Delete this file",
837
+ title: "Delete file",
838
+ onClick: () => {
839
+ setDeleteError(null);
840
+ setDeleteOpen(true);
841
+ },
842
+ className: "inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive",
843
+ children: /* @__PURE__ */ jsx2(Trash2, { className: "h-4 w-4" })
844
+ }
845
+ )
846
+ ] })
847
+ ] }),
848
+ selectedFile && saveError && /* @__PURE__ */ jsx2(
849
+ OperationErrorAlert,
850
+ {
851
+ message: saveError.message,
852
+ retryLabel: "Retry save",
853
+ onRetry: () => void saveCurrent(),
854
+ onDismiss: () => setSaveError(null)
855
+ }
856
+ ),
857
+ readError && selectedFile?.path === resolvedSelectedPath && /* @__PURE__ */ jsx2(
858
+ OperationErrorAlert,
859
+ {
860
+ message: readError,
861
+ retryLabel: "Retry file refresh",
862
+ onRetry: () => setReloadNonce((n) => n + 1),
863
+ onDismiss: () => setReadError(null)
864
+ }
865
+ ),
866
+ /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-hidden", children: fileLoading && selectedFile?.path !== resolvedSelectedPath ? /* @__PURE__ */ jsx2(EditorSkeleton, {}) : readError && selectedFile?.path !== resolvedSelectedPath ? /* @__PURE__ */ jsx2(ReadErrorState, { message: readError, onRetry: () => setReloadNonce((n) => n + 1) }) : selectedFile && canWrite && isMarkdownCapable && editorMode === "source" ? /* @__PURE__ */ jsx2(
867
+ SourceEditor,
868
+ {
869
+ path: selectedFile.path,
870
+ content: sourceDraft,
871
+ saving,
872
+ dirty: isDirty,
873
+ onChange: onSourceChange,
874
+ onSave: () => void saveCurrent()
875
+ }
876
+ ) : selectedFile ? renderArtifact({
877
+ file: selectedFile,
878
+ loading: false,
879
+ mode: editorMode,
880
+ canWrite,
881
+ richDraft,
882
+ dirty: isDirty,
883
+ onRichChange,
884
+ onSave: () => void saveCurrent()
885
+ }) : null })
886
+ ]
887
+ }
888
+ )
889
+ ] })
823
890
  ] }),
824
891
  renderDock && selectedFile && renderDock({
825
892
  file: selectedFile,
@@ -930,4 +997,4 @@ export {
930
997
  ConfirmDialog,
931
998
  VaultPane
932
999
  };
933
- //# sourceMappingURL=chunk-ZNLASEO3.js.map
1000
+ //# sourceMappingURL=chunk-FCUWRMAF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vault/VaultPane.tsx","../src/vault/ConfirmDialog.tsx"],"sourcesContent":["/**\n * The shared 3-pane vault: tree | artifact viewer | optional agent dock. This is\n * pure shell MECHANISM — selection, the dirty-guard + pending-nav state machine,\n * rich/source editor modes, create/delete/refresh, skeletons, and an error\n * boundary. It renders NO file tree and NO artifact viewer of its own:\n * those arrive through the `renderTree` / `renderArtifact` / `renderDock` seams,\n * so a product wires sandbox-ui's RichFileTree + FileArtifactPane in ~10 lines.\n *\n * Data flows exclusively through `port` (a `VaultDataPort`). The pane never\n * imports a fetch client, a router, a toast system, or a markdown library — the\n * optional `codec` seam supplies rich/source parsing (identity passthrough by\n * default). Chrome uses the shared theme tokens (bg-card, border-border, …).\n */\n\nimport {\n Component,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ErrorInfo,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { Download, Folder, Trash2 } from 'lucide-react'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type {\n VaultEditorMode,\n VaultFile,\n VaultMarkdownCodec,\n VaultOperation,\n VaultOperationFailure,\n VaultOperationPhase,\n VaultPaneProps,\n VaultRichParts,\n VaultTreeNode,\n} from './contracts'\n\nconst IDENTITY_CODEC: VaultMarkdownCodec = {\n parse: (raw) => raw,\n serialize: (parts) => (typeof parts === 'string' ? parts : String(parts ?? '')),\n}\n\ntype PendingNav = { type: 'open'; path: string } | { type: 'close' } | null\n\ninterface TreeRefreshContext {\n operation: Extract<VaultOperation, 'list' | 'create' | 'delete'>\n phase: VaultOperationPhase\n path?: string\n selectAfterRecovery?: string\n}\n\ninterface TreeFailureState {\n failure: VaultOperationFailure\n context: TreeRefreshContext\n}\n\nconst LIST_CONTEXT: TreeRefreshContext = { operation: 'list', phase: 'operation' }\n\nfunction operationMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback\n}\n\nfunction treeFailureMessage(failure: VaultOperationFailure): string {\n if (failure.phase !== 'post-mutation-refresh') return failure.message\n const completed = failure.operation === 'create' ? 'created' : 'deleted'\n return `The file was ${completed}, but the Vault couldn't refresh. ${failure.message}`\n}\n\ninterface TreePaths {\n files: Set<string>\n directories: Set<string>\n}\n\n// Directories are collected alongside files because a click on one has to be\n// RECOGNIZED to be answered — dropping them here is what made a folder row a\n// dead target: the path resolved to nothing and every downstream branch was\n// keyed on a file.\nfunction collectTreePaths(nodes: VaultTreeNode[], into: TreePaths): TreePaths {\n for (const node of nodes) {\n if (node.type === 'file') into.files.add(node.path)\n else into.directories.add(node.path)\n if (node.children) collectTreePaths(node.children, into)\n }\n return into\n}\n\nfunction resolveFilePath(rawPath: string, filePaths: Set<string>): string | null {\n if (filePaths.has(rawPath)) return rawPath\n const path = rawPath.replace(/^\\/+|\\/+$/g, '')\n return filePaths.has(path) ? path : null\n}\n\nfunction resolveTreePath(rawPath: string, paths: TreePaths): { path: string; type: 'file' | 'directory' } | null {\n const file = resolveFilePath(rawPath, paths.files)\n if (file) return { path: file, type: 'file' }\n if (paths.directories.has(rawPath)) return { path: rawPath, type: 'directory' }\n const trimmed = rawPath.replace(/^\\/+|\\/+$/g, '')\n return paths.directories.has(trimmed) ? { path: trimmed, type: 'directory' } : null\n}\n\nfunction findDirectory(nodes: VaultTreeNode[], path: string): VaultTreeNode | null {\n for (const node of nodes) {\n if (node.type === 'directory' && node.path === path) return node\n const found = node.children ? findDirectory(node.children, path) : null\n if (found) return found\n }\n return null\n}\n\n/** The clicked tree row, files and directories alike. The type travels with the\n * path so the caller routes on it instead of discarding everything that is not\n * a file. */\nfunction treeClickTarget(event: MouseEvent<HTMLElement>): { path: string; type: string } | null {\n const read = (el: HTMLElement) => {\n const path = el.dataset.itemPath\n return path ? { path, type: el.dataset.itemType ?? '' } : null\n }\n\n const path = event.nativeEvent.composedPath?.() ?? []\n for (const item of path) {\n if (!(item instanceof HTMLElement)) continue\n if (item.dataset.type !== 'item') continue\n return read(item)\n }\n\n const target = event.target instanceof HTMLElement\n ? event.target.closest('[data-type=\"item\"]')\n : null\n return target instanceof HTMLElement ? read(target) : null\n}\n\n// Case-insensitive name filter over the tree: files survive when their name\n// matches; a directory survives whole (with all its children) when its own name\n// matches, otherwise only when some descendant survives.\nfunction filterNodes(nodes: VaultTreeNode[], q: string): VaultTreeNode[] {\n const out: VaultTreeNode[] = []\n for (const node of nodes) {\n if (node.type === 'file') {\n if (node.name.toLowerCase().includes(q)) out.push(node)\n } else if (node.name.toLowerCase().includes(q)) {\n out.push(node)\n } else {\n const children = filterNodes(node.children ?? [], q)\n if (children.length > 0) out.push({ ...node, children })\n }\n }\n return out\n}\n\nclass EditorErrorBoundary extends Component<{ children: ReactNode; onReset?: () => void }, { error: unknown }> {\n state: { error: unknown } = { error: null }\n static getDerivedStateFromError(error: unknown) {\n return { error }\n }\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error('Vault crashed:', error, info)\n }\n render() {\n if (this.state.error) {\n const msg = this.state.error instanceof Error\n ? this.state.error.message\n : typeof this.state.error === 'string'\n ? this.state.error\n : 'Something went wrong loading the vault'\n return (\n <div className=\"flex h-full flex-1 flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"mb-1 text-sm font-medium text-foreground\">Vault failed to load</h3>\n <p className=\"mb-4 max-w-xs text-xs text-muted-foreground\">{String(msg)}</p>\n <button\n type=\"button\"\n onClick={() => { this.setState({ error: null }); this.props.onReset?.() }}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Try again\n </button>\n </div>\n )\n }\n return this.props.children\n }\n}\n\n/**\n * A skeleton is a picture of a wait, and a picture is exactly what a screen\n * reader cannot see. `aria-hidden` on the shimmer bars is right — they carry no\n * information — but hiding them without saying anything else is what left the\n * whole load silent. The container announces the wait instead: `aria-busy` for\n * the state, a `status` live region so arrival is reported, and a real text\n * label, since a live region with only decorative children announces nothing.\n */\nfunction SkeletonRegion({ label, className, children }: { label: string; className: string; children: ReactNode }) {\n // The live region is a SIBLING of the shimmer, not a wrapper around it: the\n // shimmer container keeps its exact classes and its exact position in the\n // parent's layout, so adding the announcement cannot move a pixel. Wrapping\n // it would put a new box between `space-y-*` and the bars it spaces.\n return (\n <>\n <span role=\"status\" aria-live=\"polite\" aria-busy={true} className=\"sr-only\">\n {label}\n </span>\n <div className={className} aria-hidden=\"true\">\n {children}\n </div>\n </>\n )\n}\n\nfunction TreeSkeleton() {\n return (\n <SkeletonRegion label=\"Loading files…\" className=\"space-y-2 p-4\">\n {[32, 48, 40, 52].map((w, i) => (\n <div key={i} className=\"h-4 animate-pulse rounded bg-muted\" style={{ width: `${w * 4}px` }} />\n ))}\n </SkeletonRegion>\n )\n}\n\nfunction EditorSkeleton() {\n return (\n <SkeletonRegion label=\"Loading file…\" className=\"space-y-3 p-8\">\n <div className=\"h-5 w-1/2 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-muted\" />\n </SkeletonRegion>\n )\n}\n\nfunction ReadErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-8 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't open this file</h3>\n <p className=\"mt-1 max-w-md text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction TreeErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div role=\"alert\" className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't load the Vault</h3>\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction OperationErrorAlert({\n message,\n retryLabel,\n onRetry,\n onDismiss,\n}: {\n message: string\n retryLabel: string\n onRetry: () => void\n onDismiss: () => void\n}) {\n return (\n <div\n role=\"alert\"\n className=\"flex shrink-0 items-center justify-between gap-3 border-b border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n <span className=\"min-w-0 flex-1\">{message}</span>\n <div className=\"flex shrink-0 items-center gap-3\">\n <button type=\"button\" aria-label={retryLabel} onClick={onRetry} className=\"font-medium underline-offset-2 hover:underline\">\n Retry\n </button>\n <button type=\"button\" onClick={onDismiss} className=\"underline-offset-2 hover:underline\">\n Dismiss\n </button>\n </div>\n </div>\n )\n}\n\n/**\n * Browse and edit files in the available pane width.\n * Below 45rem, Files and the selected document share one pane.\n * Switching panes keeps the editor mounted and preserves unsaved changes.\n */\nexport function VaultPane(props: VaultPaneProps) {\n const {\n port,\n renderTree,\n renderArtifact,\n renderDock,\n canWrite = true,\n selectedPath: controlledPath,\n onSelectedPathChange,\n onOperationError,\n codec,\n className,\n dockToggle,\n refreshKey,\n headerActions,\n onDownloadFile,\n pathBarClassName,\n } = props\n\n const activeCodec = codec ?? IDENTITY_CODEC\n const controlled = controlledPath !== undefined\n const isMarkdownCapable = codec !== undefined\n // `false` → a persistent dock (no toggle, always open with the selected file).\n const persistentDock = dockToggle === false\n const dockToggleCfg = dockToggle ? dockToggle : { label: 'Discuss', disabledWhenDirty: true }\n\n const [tree, setTree] = useState<VaultTreeNode[]>([])\n const [treeLoading, setTreeLoading] = useState(true)\n const [treeLoaded, setTreeLoaded] = useState(false)\n const [treeError, setTreeError] = useState<TreeFailureState | null>(null)\n const [internalPath, setInternalPath] = useState<string | null>(null)\n const selectedPath = controlled ? (controlledPath ?? null) : internalPath\n const [filesOpen, setFilesOpen] = useState(false)\n const showFiles = filesOpen || !selectedPath\n const searchRef = useRef<HTMLInputElement>(null)\n const documentRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n setFilesOpen(false)\n }, [selectedPath])\n\n const showDocument = useCallback(() => {\n const focused = document.activeElement\n setFilesOpen(false)\n requestAnimationFrame(() => {\n if (document.activeElement === focused || document.activeElement === document.body) {\n documentRef.current?.focus({ preventScroll: true })\n }\n })\n }, [])\n\n const [selectedFile, setSelectedFile] = useState<VaultFile | null>(null)\n const [fileLoading, setFileLoading] = useState(false)\n const [readError, setReadError] = useState<string | null>(null)\n const [reloadNonce, setReloadNonce] = useState(0)\n const [saving, setSaving] = useState(false)\n const [saveError, setSaveError] = useState<VaultOperationFailure | null>(null)\n\n const [editorMode, setEditorMode] = useState<VaultEditorMode>('rich')\n const [richDraft, setRichDraft] = useState<VaultRichParts>('')\n const [sourceDraft, setSourceDraft] = useState('')\n const [isDirty, setIsDirty] = useState(false)\n\n const [createOpen, setCreateOpen] = useState(false)\n const [newPath, setNewPath] = useState('')\n const [creating, setCreating] = useState(false)\n const [createError, setCreateError] = useState<VaultOperationFailure | null>(null)\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [deleteError, setDeleteError] = useState<VaultOperationFailure | null>(null)\n const [dockOpen, setDockOpen] = useState(false)\n const [pendingNav, setPendingNav] = useState<PendingNav>(null)\n const [query, setQuery] = useState('')\n const [folderPath, setFolderPath] = useState<string | null>(null)\n\n const dirtyRef = useRef(isDirty)\n dirtyRef.current = isDirty\n const treeRequestRef = useRef(0)\n const savedContentRef = useRef('')\n const loadedPathRef = useRef<string | null>(null)\n const onOperationErrorRef = useRef(onOperationError)\n onOperationErrorRef.current = onOperationError\n\n const treePaths = useMemo(\n () => collectTreePaths(tree, { files: new Set<string>(), directories: new Set<string>() }),\n [tree],\n )\n const filePaths = treePaths.files\n const resolvedSelectedPath = useMemo(\n () => selectedPath ? resolveFilePath(selectedPath, filePaths) : null,\n [selectedPath, filePaths],\n )\n // The clicked folder, resolved against the CURRENT tree — a folder that a\n // refresh removed stops being the active one on its own, so neither the\n // search scope nor the create target can point at a directory that is gone.\n const activeFolderNode = useMemo(\n () => (folderPath ? findDirectory(tree, folderPath) : null),\n [tree, folderPath],\n )\n const activeFolder = activeFolderNode?.path ?? null\n const treeRoot = useMemo<VaultTreeNode>(\n () => ({ name: 'Vault', path: '', type: 'directory', children: tree }),\n [tree],\n )\n // With no query the whole vault stays on screen: the tree renderer owns\n // expansion (both sandbox-ui trees keep it internal), so re-rooting on a\n // plain folder click would fight the expand the click already performs. The\n // folder scopes the SEARCH, which is where a narrowed list is what the reader\n // asked for.\n const visibleRoot = useMemo<VaultTreeNode>(() => {\n const q = query.trim().toLowerCase()\n if (!q) return treeRoot\n const base = activeFolderNode ?? treeRoot\n return { ...base, children: filterNodes(base.children ?? [], q) }\n }, [treeRoot, activeFolderNode, query])\n\n const commitPath = useCallback(\n (next: string | null) => {\n if (!controlled) setInternalPath(next)\n onSelectedPathChange?.(next)\n },\n [controlled, onSelectedPathChange],\n )\n\n const reportFailure = useCallback((\n operation: VaultOperation,\n phase: VaultOperationPhase,\n error: unknown,\n fallback: string,\n path?: string,\n ): VaultOperationFailure => {\n const failure: VaultOperationFailure = {\n operation,\n phase,\n path,\n message: operationMessage(error, fallback),\n cause: error,\n }\n try {\n onOperationErrorRef.current?.(failure)\n } catch (callbackError) {\n console.error('Vault onOperationError callback failed:', callbackError)\n }\n return failure\n }, [])\n\n const refresh = useCallback(async (context: TreeRefreshContext = LIST_CONTEXT): Promise<boolean> => {\n const request = ++treeRequestRef.current\n setTreeLoading(true)\n setTreeError(null)\n try {\n const nextTree = await port.listTree()\n if (request !== treeRequestRef.current) return false\n setTree(nextTree)\n setTreeLoaded(true)\n return true\n } catch (error) {\n if (request !== treeRequestRef.current) return false\n const failure = reportFailure(\n context.operation,\n context.phase,\n error,\n 'Failed to load the Vault',\n context.path,\n )\n setTreeError({ failure, context })\n return false\n } finally {\n if (request === treeRequestRef.current) setTreeLoading(false)\n }\n }, [port, reportFailure])\n\n useEffect(() => {\n setTree([])\n setTreeLoaded(false)\n setTreeError(null)\n setSelectedFile(null)\n }, [port])\n\n useEffect(() => {\n void refresh()\n return () => { treeRequestRef.current += 1 }\n }, [refresh, refreshKey])\n\n const retryTree = useCallback(async () => {\n if (!treeError) return\n const { context } = treeError\n const recovered = await refresh(context)\n if (recovered && context.selectAfterRecovery) commitPath(context.selectAfterRecovery)\n }, [treeError, refresh, commitPath])\n\n useEffect(() => {\n if (!selectedPath) {\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n if (treeLoading || !treeLoaded || isDirty || saving) return\n if (!resolvedSelectedPath) {\n commitPath(null)\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n let cancelled = false\n const path = resolvedSelectedPath\n if (path !== selectedPath) commitPath(path)\n setFileLoading(true)\n setReadError(null)\n void (async () => {\n try {\n const file = await port.readFile(path)\n if (!cancelled && !dirtyRef.current) setSelectedFile(file)\n } catch (err) {\n // Surface read failures instead of making them indistinguishable from\n // the intentionally empty \"no file selected\" state.\n if (!cancelled) {\n const failure = reportFailure('read', 'operation', err, 'Failed to read file', path)\n setSelectedFile((current) => current?.path === path ? current : null)\n setReadError(failure.message)\n }\n } finally {\n if (!cancelled) setFileLoading(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [port, selectedPath, resolvedSelectedPath, treeLoading, treeLoaded, isDirty, saving, reloadNonce, commitPath, reportFailure])\n\n useEffect(() => {\n if (!selectedFile) {\n loadedPathRef.current = null\n savedContentRef.current = ''\n setRichDraft('')\n setSourceDraft('')\n setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n return\n }\n const pathChanged = loadedPathRef.current !== selectedFile.path\n loadedPathRef.current = selectedFile.path\n savedContentRef.current = selectedFile.content\n setRichDraft(activeCodec.parse(selectedFile.content))\n setSourceDraft(selectedFile.content)\n if (pathChanged) setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n setDockOpen(false)\n }, [selectedFile?.path, selectedFile?.content, activeCodec])\n\n const guardedOpen = useCallback(\n (path: string) => {\n if (path === selectedPath) {\n showDocument()\n return\n }\n if (isDirty) {\n setPendingNav({ type: 'open', path })\n return\n }\n showDocument()\n commitPath(path)\n },\n [isDirty, selectedPath, commitPath, showDocument],\n )\n\n // Clicking a folder makes it the vault's active folder: the search narrows to\n // it and a new file lands inside it. Clicking it again clears that — the same\n // row is the way back out, so the gesture is reversible where it was made.\n const toggleFolder = useCallback((path: string) => {\n setFolderPath((current) => (current === path ? null : path))\n }, [])\n\n // Some tree models keep their original selection callback while resetting\n // paths internally. Keep the callable stable, but have it execute the latest\n // path validation and dirty-guard logic.\n const selectFileRef = useRef<(path: string) => void>(() => {})\n selectFileRef.current = (rawPath: string) => {\n const target = resolveTreePath(rawPath, treePaths)\n if (!target) return\n if (target.type === 'file') {\n guardedOpen(target.path)\n return\n }\n toggleFolder(target.path)\n }\n const handleTreeSelect = useCallback((path: string) => selectFileRef.current(path), [])\n\n const guardedClose = useCallback(() => {\n if (isDirty) {\n setPendingNav({ type: 'close' })\n return\n }\n commitPath(null)\n setSelectedFile(null)\n }, [isDirty, commitPath])\n\n const confirmDiscard = useCallback(() => {\n const nav = pendingNav\n setPendingNav(null)\n setIsDirty(false)\n if (!nav) return\n if (nav.type === 'open') {\n showDocument()\n commitPath(nav.path)\n } else {\n commitPath(null)\n setSelectedFile(null)\n }\n }, [pendingNav, commitPath, showDocument])\n\n const showRichMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'rich') return mode\n setRichDraft(activeCodec.parse(sourceDraft))\n setIsDirty(sourceDraft !== savedContentRef.current)\n return 'rich'\n })\n }, [activeCodec, sourceDraft])\n\n const showSourceMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'source') return mode\n const content = isDirty ? activeCodec.serialize(richDraft) : savedContentRef.current\n setSourceDraft(content)\n setIsDirty(content !== savedContentRef.current)\n return 'source'\n })\n }, [activeCodec, isDirty, richDraft])\n\n const onSourceChange = useCallback((next: string) => {\n dirtyRef.current = next !== savedContentRef.current\n setSourceDraft(next)\n setIsDirty(dirtyRef.current)\n }, [])\n\n const onRichChange = useCallback((next: VaultRichParts) => {\n dirtyRef.current = activeCodec.serialize(next) !== savedContentRef.current\n setRichDraft(next)\n setIsDirty(dirtyRef.current)\n }, [activeCodec])\n\n const saveCurrent = useCallback(async () => {\n if (!selectedFile) return\n const content = editorMode === 'source' ? sourceDraft : activeCodec.serialize(richDraft)\n setSaving(true)\n setSaveError(null)\n try {\n await port.writeFile(selectedFile.path, content)\n savedContentRef.current = content\n setSelectedFile({ ...selectedFile, content })\n setSourceDraft(content)\n setRichDraft(activeCodec.parse(content))\n setIsDirty(false)\n } catch (error) {\n setSaveError(reportFailure('save', 'operation', error, 'Failed to save file', selectedFile.path))\n } finally {\n setSaving(false)\n }\n }, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port, reportFailure])\n\n const handleCreate = useCallback(async () => {\n const trimmed = newPath.trim()\n // Same rule as the confirm button, enforced here too: the dialog can also be\n // confirmed by keyboard, and a directory path is not a file to create.\n if (!trimmed || !(trimmed.split('/').pop()?.trim())) return\n setCreating(true)\n setCreateError(null)\n try {\n const created = await port.createFile(trimmed)\n setCreateOpen(false)\n setNewPath('')\n const refreshed = await refresh({\n operation: 'create',\n phase: 'post-mutation-refresh',\n path: created,\n selectAfterRecovery: created,\n })\n if (refreshed) commitPath(created)\n } catch (error) {\n setCreateError(reportFailure('create', 'operation', error, 'Failed to create file', trimmed))\n } finally {\n setCreating(false)\n }\n }, [newPath, port, refresh, commitPath, reportFailure])\n\n const handleDelete = useCallback(async () => {\n if (!selectedFile) return\n const path = selectedFile.path\n setDeleting(true)\n setDeleteError(null)\n try {\n await port.deleteFile(path)\n setDeleteOpen(false)\n setIsDirty(false)\n commitPath(null)\n setSelectedFile(null)\n await refresh({ operation: 'delete', phase: 'post-mutation-refresh', path })\n } catch (error) {\n setDeleteError(reportFailure('delete', 'operation', error, 'Failed to delete file', path))\n } finally {\n setDeleting(false)\n }\n }, [selectedFile, port, refresh, commitPath, reportFailure])\n\n const createFileName = newPath.trim().split('/').pop()?.trim() ?? ''\n\n let treeContent: ReactNode\n if (!treeLoaded && (treeLoading || !treeError)) {\n treeContent = <TreeSkeleton />\n } else if (!treeLoaded && treeError) {\n treeContent = <TreeErrorState message={treeFailureMessage(treeError.failure)} onRetry={() => void retryTree()} />\n } else {\n treeContent = (\n <>\n {treeError && (\n <OperationErrorAlert\n message={treeFailureMessage(treeError.failure)}\n retryLabel=\"Retry vault refresh\"\n onRetry={() => void retryTree()}\n onDismiss={() => setTreeError(null)}\n />\n )}\n {renderTree({\n root: visibleRoot,\n selectedPath: resolvedSelectedPath ?? undefined,\n onSelect: handleTreeSelect,\n })}\n </>\n )\n }\n\n return (\n <EditorErrorBoundary onReset={() => { commitPath(null); setSelectedFile(null) }}>\n <div className={`flex min-h-0 min-w-0 flex-1 overflow-hidden ${className ?? ''}`}>\n <div className=\"@container/vault flex min-w-0 flex-1 flex-col\">\n <nav aria-label=\"Vault navigation\" className=\"flex shrink-0 items-center gap-1 border-b border-border p-2 @[45rem]/vault:hidden\">\n <button\n type=\"button\"\n aria-pressed={showFiles}\n onClick={() => {\n const focused = document.activeElement\n setFilesOpen(true)\n requestAnimationFrame(() => {\n if (document.activeElement === focused || document.activeElement === document.body) {\n searchRef.current?.focus()\n }\n })\n }}\n className={`shrink-0 rounded-md px-3 py-2 text-sm ${showFiles ? 'bg-muted font-medium text-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n >\n Files\n </button>\n {selectedPath && (\n <button\n type=\"button\"\n aria-pressed={!showFiles}\n onClick={showDocument}\n title={selectedPath}\n className={`min-w-0 truncate rounded-md px-3 py-2 text-sm ${!showFiles ? 'bg-muted font-medium text-foreground' : 'text-muted-foreground hover:bg-muted'}`}\n >\n {selectedPath.split('/').pop()}\n </button>\n )}\n </nav>\n <div className=\"flex min-h-0 min-w-0 flex-1\">\n <div data-vault-tree className={`${showFiles ? 'flex' : 'hidden'} min-w-0 flex-1 flex-col border-r border-border bg-background @[45rem]/vault:flex @[45rem]/vault:w-[23rem] @[45rem]/vault:min-w-[23rem] @[45rem]/vault:flex-none`}>\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <input\n ref={searchRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={activeFolder ? `Search ${activeFolder}…` : 'Search…'}\n aria-label=\"Search vault\"\n className=\"h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {headerActions}\n <button\n type=\"button\"\n aria-label=\"Refresh vault\"\n onClick={() => void refresh()}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n ↻\n </button>\n {canWrite && (\n <button\n type=\"button\"\n aria-label={activeFolder ? `New vault file in ${activeFolder}` : 'New vault file'}\n onClick={() => { setCreateError(null); setNewPath(activeFolder ? `${activeFolder}/` : ''); setCreateOpen(true) }}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90\"\n >\n +\n </button>\n )}\n </div>\n </div>\n {activeFolder && (\n <div className=\"flex items-center gap-1.5 border-b border-border bg-muted/40 px-4 py-1.5 text-xs\">\n <Folder className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span data-vault-folder className=\"min-w-0 flex-1 truncate font-medium text-foreground\" title={activeFolder}>\n {activeFolder}\n </span>\n <button\n type=\"button\"\n aria-label=\"Clear the active folder\"\n onClick={() => setFolderPath(null)}\n className=\"shrink-0 rounded px-1 text-muted-foreground underline-offset-2 transition-colors hover:text-foreground hover:underline\"\n >\n Clear\n </button>\n </div>\n )}\n <div\n className=\"flex-1 overflow-y-auto\"\n onClickCapture={(event) => {\n const target = treeClickTarget(event)\n if (target) handleTreeSelect(target.path)\n }}\n >\n {treeContent}\n </div>\n </div>\n\n <div\n ref={documentRef}\n role=\"region\"\n aria-label=\"Vault document\"\n tabIndex={-1}\n className={`${showFiles ? 'hidden' : 'flex'} min-w-0 flex-1 flex-col overflow-hidden @[45rem]/vault:flex`}\n >\n {selectedFile && (\n <div className={`flex shrink-0 items-center justify-between gap-2 border-b border-border px-4 py-1.5 ${pathBarClassName ?? 'bg-card'}`}>\n <span data-vault-path className=\"min-w-0 flex-1 truncate text-xs font-medium text-foreground\">{selectedFile.path}</span>\n <div className=\"flex shrink-0 items-center gap-1\">\n {canWrite && isMarkdownCapable && (\n <div className=\"mr-1 flex items-center gap-1\">\n <button\n type=\"button\"\n aria-label=\"Edit as rich text\"\n aria-pressed={editorMode === 'rich'}\n onClick={showRichMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'rich'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Rich\n </button>\n <button\n type=\"button\"\n aria-label=\"Edit as source\"\n aria-pressed={editorMode === 'source'}\n onClick={showSourceMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'source'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Source\n </button>\n </div>\n )}\n {renderDock && !persistentDock && (\n <button\n type=\"button\"\n aria-label={dockToggleCfg.label}\n aria-pressed={dockOpen}\n disabled={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty}\n title={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? 'Save your changes first' : (dockToggleCfg.title ?? dockToggleCfg.label)}\n onClick={() => setDockOpen((v) => !v)}\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${\n dockOpen\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {dockToggleCfg.label}\n </button>\n )}\n {onDownloadFile && (\n <button\n type=\"button\"\n aria-label=\"Download this file\"\n title=\"Download file\"\n onClick={() => onDownloadFile(selectedFile)}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"Delete this file\"\n title=\"Delete file\"\n onClick={() => { setDeleteError(null); setDeleteOpen(true) }}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n {selectedFile && saveError && (\n <OperationErrorAlert\n message={saveError.message}\n retryLabel=\"Retry save\"\n onRetry={() => void saveCurrent()}\n onDismiss={() => setSaveError(null)}\n />\n )}\n {readError && selectedFile?.path === resolvedSelectedPath && (\n <OperationErrorAlert\n message={readError}\n retryLabel=\"Retry file refresh\"\n onRetry={() => setReloadNonce((n) => n + 1)}\n onDismiss={() => setReadError(null)}\n />\n )}\n <div className=\"flex-1 overflow-hidden\">\n {fileLoading && selectedFile?.path !== resolvedSelectedPath ? (\n <EditorSkeleton />\n ) : readError && selectedFile?.path !== resolvedSelectedPath ? (\n <ReadErrorState message={readError} onRetry={() => setReloadNonce((n) => n + 1)} />\n ) : selectedFile && canWrite && isMarkdownCapable && editorMode === 'source' ? (\n <SourceEditor\n path={selectedFile.path}\n content={sourceDraft}\n saving={saving}\n dirty={isDirty}\n onChange={onSourceChange}\n onSave={() => void saveCurrent()}\n />\n ) : selectedFile ? (\n renderArtifact({\n file: selectedFile,\n loading: false,\n mode: editorMode,\n canWrite,\n richDraft,\n dirty: isDirty,\n onRichChange,\n onSave: () => void saveCurrent(),\n })\n ) : null}\n </div>\n </div>\n </div>\n </div>\n\n {renderDock && selectedFile && renderDock({\n file: selectedFile,\n open: persistentDock ? true : dockOpen,\n onClose: persistentDock ? () => {} : () => setDockOpen(false),\n })}\n\n <ConfirmDialog\n open={createOpen}\n title=\"Create vault file\"\n description={activeFolder ? `Add a new document to ${activeFolder}.` : 'Add a new document to this vault.'}\n confirmLabel={creating ? 'Creating…' : 'Create'}\n // A prefilled folder is a path with no file name yet, so emptiness is\n // not the test — `folder/` would otherwise be sent to the port as a\n // file to create.\n confirmDisabled={creating || !createFileName}\n onConfirm={() => void handleCreate()}\n onCancel={() => { setCreateOpen(false); setNewPath(''); setCreateError(null) }}\n >\n <div className=\"space-y-2\">\n <input\n value={newPath}\n autoFocus\n onChange={(e) => setNewPath(e.target.value)}\n placeholder=\"e.g. playbooks/new-strategy.md\"\n aria-label=\"New file path\"\n className=\"h-9 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground\"\n />\n {createError && <p role=\"alert\" className=\"text-xs text-destructive\">{createError.message}</p>}\n </div>\n </ConfirmDialog>\n\n <ConfirmDialog\n open={deleteOpen}\n title=\"Delete file?\"\n description={`This permanently removes ${selectedFile?.path ?? 'this file'} from the vault.`}\n confirmLabel={deleting ? 'Deleting…' : 'Delete file'}\n confirmDisabled={deleting}\n destructive\n onConfirm={() => void handleDelete()}\n onCancel={() => { setDeleteOpen(false); setDeleteError(null) }}\n >\n {deleteError && <p role=\"alert\" className=\"text-xs text-destructive\">{deleteError.message}</p>}\n </ConfirmDialog>\n\n <ConfirmDialog\n open={pendingNav !== null}\n title=\"Discard unsaved changes?\"\n description=\"Your edits to this document haven't been saved. Continue and lose them?\"\n confirmLabel=\"Discard changes\"\n destructive\n onConfirm={confirmDiscard}\n onCancel={() => setPendingNav(null)}\n />\n </div>\n </EditorErrorBoundary>\n )\n}\n\nfunction SourceEditor({\n path,\n content,\n saving,\n dirty,\n onChange,\n onSave,\n}: {\n path: string\n content: string\n saving: boolean\n dirty: boolean\n onChange: (content: string) => void\n onSave: () => void\n}) {\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-2\">\n <p className=\"truncate font-mono text-xs text-muted-foreground\">{path}</p>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs text-muted-foreground\">\n {dirty ? 'Unsaved changes' : 'Saved'}\n </span>\n <button\n type=\"button\"\n onClick={onSave}\n disabled={saving || !dirty}\n className=\"inline-flex h-7 items-center rounded-md bg-primary px-2 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n </div>\n <textarea\n value={content}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n aria-label=\"Source editor\"\n // Full-bleed editor: keep the floor's ring but draw it inside the border\n // box, since an outward ring on a `flex-1` pane child is clipped.\n className=\"min-h-0 flex-1 resize-none border-0 bg-background p-4 font-mono text-sm leading-6 text-foreground focus-visible:[outline-offset:-2px]\"\n />\n </div>\n )\n}\n","/**\n * Self-contained confirm dialog — no dialog library. A focus-trapped modal with\n * Esc-to-cancel and Enter-to-confirm, used for create / delete / discard-unsaved\n * flows so the pane carries zero UI-kit dependency.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\n\nexport interface ConfirmDialogProps {\n open: boolean\n title: string\n description?: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n /** Styles the confirm button as a destructive action. */\n destructive?: boolean\n /** Disables the confirm button (e.g. while the action is in flight). */\n confirmDisabled?: boolean\n onConfirm: () => void\n onCancel: () => void\n /** Optional body (e.g. an input field for the create flow). */\n children?: ReactNode\n}\n\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n destructive = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n children,\n}: ConfirmDialogProps) {\n const panelRef = useRef<HTMLDivElement>(null)\n const confirmRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n if (!open) return\n confirmRef.current?.focus()\n }, [open])\n\n if (!open) return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && !confirmDisabled) {\n event.preventDefault()\n onConfirm()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={onKeyDown}\n className=\"w-full max-w-md rounded-lg border border-border bg-card p-5 shadow-lg\"\n >\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n {description && <p className=\"mt-1.5 text-xs text-muted-foreground\">{description}</p>}\n {children && <div className=\"mt-3\">{children}</div>}\n <div className=\"mt-5 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-8 items-center rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n {cancelLabel}\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n className={`inline-flex h-8 items-center rounded-md px-3 text-xs font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 ${\n destructive\n ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90'\n : 'bg-primary text-primary-foreground hover:bg-primary/90'\n }`}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","jsx","jsxs","path","useRef","useEffect"]}
@@ -12,4 +12,9 @@
12
12
  * default). Chrome uses the shared theme tokens (bg-card, border-border, …).
13
13
  */
14
14
  import type { VaultPaneProps } from './contracts';
15
+ /**
16
+ * Browse and edit files in the available pane width.
17
+ * Below 45rem, Files and the selected document share one pane.
18
+ * Switching panes keeps the editor mounted and preserves unsaved changes.
19
+ */
15
20
  export declare function VaultPane(props: VaultPaneProps): import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ConfirmDialog,
3
3
  VaultPane
4
- } from "../chunk-ZNLASEO3.js";
4
+ } from "../chunk-FCUWRMAF.js";
5
5
  export {
6
6
  ConfirmDialog,
7
7
  VaultPane
@@ -1,7 +1,7 @@
1
1
  // src/vault/lazy.tsx
2
2
  import { lazy } from "react";
3
3
  var VaultPaneLazy = lazy(
4
- () => import("../VaultPane-QZC3YKQG.js").then((m) => ({ default: m.VaultPane }))
4
+ () => import("../VaultPane-32HVWZ6A.js").then((m) => ({ default: m.VaultPane }))
5
5
  );
6
6
  export {
7
7
  VaultPaneLazy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.49.27",
3
+ "version": "0.49.29",
4
4
  "packageManager": "pnpm@11.24.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -1,7 +0,0 @@
1
- import {
2
- VaultPane
3
- } from "./chunk-ZNLASEO3.js";
4
- export {
5
- VaultPane
6
- };
7
- //# sourceMappingURL=VaultPane-QZC3YKQG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/vault/VaultPane.tsx","../src/vault/ConfirmDialog.tsx"],"sourcesContent":["/**\n * The shared 3-pane vault: tree | artifact viewer | optional agent dock. This is\n * pure shell MECHANISM — selection, the dirty-guard + pending-nav state machine,\n * rich/source editor modes, create/delete/refresh, skeletons, and an error\n * boundary. It renders NO file tree and NO artifact viewer of its own:\n * those arrive through the `renderTree` / `renderArtifact` / `renderDock` seams,\n * so a product wires sandbox-ui's RichFileTree + FileArtifactPane in ~10 lines.\n *\n * Data flows exclusively through `port` (a `VaultDataPort`). The pane never\n * imports a fetch client, a router, a toast system, or a markdown library — the\n * optional `codec` seam supplies rich/source parsing (identity passthrough by\n * default). Chrome uses the shared theme tokens (bg-card, border-border, …).\n */\n\nimport {\n Component,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ErrorInfo,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { Download, Folder, Trash2 } from 'lucide-react'\nimport { ConfirmDialog } from './ConfirmDialog'\nimport type {\n VaultEditorMode,\n VaultFile,\n VaultMarkdownCodec,\n VaultOperation,\n VaultOperationFailure,\n VaultOperationPhase,\n VaultPaneProps,\n VaultRichParts,\n VaultTreeNode,\n} from './contracts'\n\nconst IDENTITY_CODEC: VaultMarkdownCodec = {\n parse: (raw) => raw,\n serialize: (parts) => (typeof parts === 'string' ? parts : String(parts ?? '')),\n}\n\ntype PendingNav = { type: 'open'; path: string } | { type: 'close' } | null\n\ninterface TreeRefreshContext {\n operation: Extract<VaultOperation, 'list' | 'create' | 'delete'>\n phase: VaultOperationPhase\n path?: string\n selectAfterRecovery?: string\n}\n\ninterface TreeFailureState {\n failure: VaultOperationFailure\n context: TreeRefreshContext\n}\n\nconst LIST_CONTEXT: TreeRefreshContext = { operation: 'list', phase: 'operation' }\n\nfunction operationMessage(error: unknown, fallback: string): string {\n return error instanceof Error && error.message ? error.message : fallback\n}\n\nfunction treeFailureMessage(failure: VaultOperationFailure): string {\n if (failure.phase !== 'post-mutation-refresh') return failure.message\n const completed = failure.operation === 'create' ? 'created' : 'deleted'\n return `The file was ${completed}, but the Vault couldn't refresh. ${failure.message}`\n}\n\ninterface TreePaths {\n files: Set<string>\n directories: Set<string>\n}\n\n// Directories are collected alongside files because a click on one has to be\n// RECOGNIZED to be answered — dropping them here is what made a folder row a\n// dead target: the path resolved to nothing and every downstream branch was\n// keyed on a file.\nfunction collectTreePaths(nodes: VaultTreeNode[], into: TreePaths): TreePaths {\n for (const node of nodes) {\n if (node.type === 'file') into.files.add(node.path)\n else into.directories.add(node.path)\n if (node.children) collectTreePaths(node.children, into)\n }\n return into\n}\n\nfunction resolveFilePath(rawPath: string, filePaths: Set<string>): string | null {\n if (filePaths.has(rawPath)) return rawPath\n const path = rawPath.replace(/^\\/+|\\/+$/g, '')\n return filePaths.has(path) ? path : null\n}\n\nfunction resolveTreePath(rawPath: string, paths: TreePaths): { path: string; type: 'file' | 'directory' } | null {\n const file = resolveFilePath(rawPath, paths.files)\n if (file) return { path: file, type: 'file' }\n if (paths.directories.has(rawPath)) return { path: rawPath, type: 'directory' }\n const trimmed = rawPath.replace(/^\\/+|\\/+$/g, '')\n return paths.directories.has(trimmed) ? { path: trimmed, type: 'directory' } : null\n}\n\nfunction findDirectory(nodes: VaultTreeNode[], path: string): VaultTreeNode | null {\n for (const node of nodes) {\n if (node.type === 'directory' && node.path === path) return node\n const found = node.children ? findDirectory(node.children, path) : null\n if (found) return found\n }\n return null\n}\n\n/** The clicked tree row, files and directories alike. The type travels with the\n * path so the caller routes on it instead of discarding everything that is not\n * a file. */\nfunction treeClickTarget(event: MouseEvent<HTMLElement>): { path: string; type: string } | null {\n const read = (el: HTMLElement) => {\n const path = el.dataset.itemPath\n return path ? { path, type: el.dataset.itemType ?? '' } : null\n }\n\n const path = event.nativeEvent.composedPath?.() ?? []\n for (const item of path) {\n if (!(item instanceof HTMLElement)) continue\n if (item.dataset.type !== 'item') continue\n return read(item)\n }\n\n const target = event.target instanceof HTMLElement\n ? event.target.closest('[data-type=\"item\"]')\n : null\n return target instanceof HTMLElement ? read(target) : null\n}\n\n// Case-insensitive name filter over the tree: files survive when their name\n// matches; a directory survives whole (with all its children) when its own name\n// matches, otherwise only when some descendant survives.\nfunction filterNodes(nodes: VaultTreeNode[], q: string): VaultTreeNode[] {\n const out: VaultTreeNode[] = []\n for (const node of nodes) {\n if (node.type === 'file') {\n if (node.name.toLowerCase().includes(q)) out.push(node)\n } else if (node.name.toLowerCase().includes(q)) {\n out.push(node)\n } else {\n const children = filterNodes(node.children ?? [], q)\n if (children.length > 0) out.push({ ...node, children })\n }\n }\n return out\n}\n\nclass EditorErrorBoundary extends Component<{ children: ReactNode; onReset?: () => void }, { error: unknown }> {\n state: { error: unknown } = { error: null }\n static getDerivedStateFromError(error: unknown) {\n return { error }\n }\n componentDidCatch(error: unknown, info: ErrorInfo) {\n console.error('Vault crashed:', error, info)\n }\n render() {\n if (this.state.error) {\n const msg = this.state.error instanceof Error\n ? this.state.error.message\n : typeof this.state.error === 'string'\n ? this.state.error\n : 'Something went wrong loading the vault'\n return (\n <div className=\"flex h-full flex-1 flex-col items-center justify-center p-8 text-center\">\n <h3 className=\"mb-1 text-sm font-medium text-foreground\">Vault failed to load</h3>\n <p className=\"mb-4 max-w-xs text-xs text-muted-foreground\">{String(msg)}</p>\n <button\n type=\"button\"\n onClick={() => { this.setState({ error: null }); this.props.onReset?.() }}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Try again\n </button>\n </div>\n )\n }\n return this.props.children\n }\n}\n\n/**\n * A skeleton is a picture of a wait, and a picture is exactly what a screen\n * reader cannot see. `aria-hidden` on the shimmer bars is right — they carry no\n * information — but hiding them without saying anything else is what left the\n * whole load silent. The container announces the wait instead: `aria-busy` for\n * the state, a `status` live region so arrival is reported, and a real text\n * label, since a live region with only decorative children announces nothing.\n */\nfunction SkeletonRegion({ label, className, children }: { label: string; className: string; children: ReactNode }) {\n // The live region is a SIBLING of the shimmer, not a wrapper around it: the\n // shimmer container keeps its exact classes and its exact position in the\n // parent's layout, so adding the announcement cannot move a pixel. Wrapping\n // it would put a new box between `space-y-*` and the bars it spaces.\n return (\n <>\n <span role=\"status\" aria-live=\"polite\" aria-busy={true} className=\"sr-only\">\n {label}\n </span>\n <div className={className} aria-hidden=\"true\">\n {children}\n </div>\n </>\n )\n}\n\nfunction TreeSkeleton() {\n return (\n <SkeletonRegion label=\"Loading files…\" className=\"space-y-2 p-4\">\n {[32, 48, 40, 52].map((w, i) => (\n <div key={i} className=\"h-4 animate-pulse rounded bg-muted\" style={{ width: `${w * 4}px` }} />\n ))}\n </SkeletonRegion>\n )\n}\n\nfunction EditorSkeleton() {\n return (\n <SkeletonRegion label=\"Loading file…\" className=\"space-y-3 p-8\">\n <div className=\"h-5 w-1/2 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-full animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-muted\" />\n <div className=\"h-4 w-2/3 animate-pulse rounded bg-muted\" />\n </SkeletonRegion>\n )\n}\n\nfunction ReadErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 p-8 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't open this file</h3>\n <p className=\"mt-1 max-w-md text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction TreeErrorState({ message, onRetry }: { message: string; onRetry: () => void }) {\n return (\n <div role=\"alert\" className=\"flex h-full flex-col items-center justify-center gap-3 p-6 text-center\">\n <div>\n <h3 className=\"text-sm font-medium text-foreground\">Couldn't load the Vault</h3>\n <p className=\"mt-1 max-w-xs text-xs text-muted-foreground\">{message}</p>\n </div>\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"inline-flex h-8 items-center rounded-md border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted\"\n >\n Retry\n </button>\n </div>\n )\n}\n\nfunction OperationErrorAlert({\n message,\n retryLabel,\n onRetry,\n onDismiss,\n}: {\n message: string\n retryLabel: string\n onRetry: () => void\n onDismiss: () => void\n}) {\n return (\n <div\n role=\"alert\"\n className=\"flex shrink-0 items-center justify-between gap-3 border-b border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive\"\n >\n <span className=\"min-w-0 flex-1\">{message}</span>\n <div className=\"flex shrink-0 items-center gap-3\">\n <button type=\"button\" aria-label={retryLabel} onClick={onRetry} className=\"font-medium underline-offset-2 hover:underline\">\n Retry\n </button>\n <button type=\"button\" onClick={onDismiss} className=\"underline-offset-2 hover:underline\">\n Dismiss\n </button>\n </div>\n </div>\n )\n}\n\nexport function VaultPane(props: VaultPaneProps) {\n const {\n port,\n renderTree,\n renderArtifact,\n renderDock,\n canWrite = true,\n selectedPath: controlledPath,\n onSelectedPathChange,\n onOperationError,\n codec,\n className,\n dockToggle,\n refreshKey,\n headerActions,\n onDownloadFile,\n pathBarClassName,\n } = props\n\n const activeCodec = codec ?? IDENTITY_CODEC\n const controlled = controlledPath !== undefined\n const isMarkdownCapable = codec !== undefined\n // `false` → a persistent dock (no toggle, always open with the selected file).\n const persistentDock = dockToggle === false\n const dockToggleCfg = dockToggle ? dockToggle : { label: 'Discuss', disabledWhenDirty: true }\n\n const [tree, setTree] = useState<VaultTreeNode[]>([])\n const [treeLoading, setTreeLoading] = useState(true)\n const [treeLoaded, setTreeLoaded] = useState(false)\n const [treeError, setTreeError] = useState<TreeFailureState | null>(null)\n const [internalPath, setInternalPath] = useState<string | null>(null)\n const selectedPath = controlled ? (controlledPath ?? null) : internalPath\n\n const [selectedFile, setSelectedFile] = useState<VaultFile | null>(null)\n const [fileLoading, setFileLoading] = useState(false)\n const [readError, setReadError] = useState<string | null>(null)\n const [reloadNonce, setReloadNonce] = useState(0)\n const [saving, setSaving] = useState(false)\n const [saveError, setSaveError] = useState<VaultOperationFailure | null>(null)\n\n const [editorMode, setEditorMode] = useState<VaultEditorMode>('rich')\n const [richDraft, setRichDraft] = useState<VaultRichParts>('')\n const [sourceDraft, setSourceDraft] = useState('')\n const [isDirty, setIsDirty] = useState(false)\n\n const [createOpen, setCreateOpen] = useState(false)\n const [newPath, setNewPath] = useState('')\n const [creating, setCreating] = useState(false)\n const [createError, setCreateError] = useState<VaultOperationFailure | null>(null)\n const [deleteOpen, setDeleteOpen] = useState(false)\n const [deleting, setDeleting] = useState(false)\n const [deleteError, setDeleteError] = useState<VaultOperationFailure | null>(null)\n const [dockOpen, setDockOpen] = useState(false)\n const [pendingNav, setPendingNav] = useState<PendingNav>(null)\n const [query, setQuery] = useState('')\n const [folderPath, setFolderPath] = useState<string | null>(null)\n\n const dirtyRef = useRef(isDirty)\n dirtyRef.current = isDirty\n const treeRequestRef = useRef(0)\n const savedContentRef = useRef('')\n const loadedPathRef = useRef<string | null>(null)\n const onOperationErrorRef = useRef(onOperationError)\n onOperationErrorRef.current = onOperationError\n\n const treePaths = useMemo(\n () => collectTreePaths(tree, { files: new Set<string>(), directories: new Set<string>() }),\n [tree],\n )\n const filePaths = treePaths.files\n const resolvedSelectedPath = useMemo(\n () => selectedPath ? resolveFilePath(selectedPath, filePaths) : null,\n [selectedPath, filePaths],\n )\n // The clicked folder, resolved against the CURRENT tree — a folder that a\n // refresh removed stops being the active one on its own, so neither the\n // search scope nor the create target can point at a directory that is gone.\n const activeFolderNode = useMemo(\n () => (folderPath ? findDirectory(tree, folderPath) : null),\n [tree, folderPath],\n )\n const activeFolder = activeFolderNode?.path ?? null\n const treeRoot = useMemo<VaultTreeNode>(\n () => ({ name: 'Vault', path: '', type: 'directory', children: tree }),\n [tree],\n )\n // With no query the whole vault stays on screen: the tree renderer owns\n // expansion (both sandbox-ui trees keep it internal), so re-rooting on a\n // plain folder click would fight the expand the click already performs. The\n // folder scopes the SEARCH, which is where a narrowed list is what the reader\n // asked for.\n const visibleRoot = useMemo<VaultTreeNode>(() => {\n const q = query.trim().toLowerCase()\n if (!q) return treeRoot\n const base = activeFolderNode ?? treeRoot\n return { ...base, children: filterNodes(base.children ?? [], q) }\n }, [treeRoot, activeFolderNode, query])\n\n const commitPath = useCallback(\n (next: string | null) => {\n if (!controlled) setInternalPath(next)\n onSelectedPathChange?.(next)\n },\n [controlled, onSelectedPathChange],\n )\n\n const reportFailure = useCallback((\n operation: VaultOperation,\n phase: VaultOperationPhase,\n error: unknown,\n fallback: string,\n path?: string,\n ): VaultOperationFailure => {\n const failure: VaultOperationFailure = {\n operation,\n phase,\n path,\n message: operationMessage(error, fallback),\n cause: error,\n }\n try {\n onOperationErrorRef.current?.(failure)\n } catch (callbackError) {\n console.error('Vault onOperationError callback failed:', callbackError)\n }\n return failure\n }, [])\n\n const refresh = useCallback(async (context: TreeRefreshContext = LIST_CONTEXT): Promise<boolean> => {\n const request = ++treeRequestRef.current\n setTreeLoading(true)\n setTreeError(null)\n try {\n const nextTree = await port.listTree()\n if (request !== treeRequestRef.current) return false\n setTree(nextTree)\n setTreeLoaded(true)\n return true\n } catch (error) {\n if (request !== treeRequestRef.current) return false\n const failure = reportFailure(\n context.operation,\n context.phase,\n error,\n 'Failed to load the Vault',\n context.path,\n )\n setTreeError({ failure, context })\n return false\n } finally {\n if (request === treeRequestRef.current) setTreeLoading(false)\n }\n }, [port, reportFailure])\n\n useEffect(() => {\n setTree([])\n setTreeLoaded(false)\n setTreeError(null)\n setSelectedFile(null)\n }, [port])\n\n useEffect(() => {\n void refresh()\n return () => { treeRequestRef.current += 1 }\n }, [refresh, refreshKey])\n\n const retryTree = useCallback(async () => {\n if (!treeError) return\n const { context } = treeError\n const recovered = await refresh(context)\n if (recovered && context.selectAfterRecovery) commitPath(context.selectAfterRecovery)\n }, [treeError, refresh, commitPath])\n\n useEffect(() => {\n if (!selectedPath) {\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n if (treeLoading || !treeLoaded || isDirty || saving) return\n if (!resolvedSelectedPath) {\n commitPath(null)\n setSelectedFile(null)\n setFileLoading(false)\n setReadError(null)\n loadedPathRef.current = null\n return\n }\n let cancelled = false\n const path = resolvedSelectedPath\n if (path !== selectedPath) commitPath(path)\n setFileLoading(true)\n setReadError(null)\n void (async () => {\n try {\n const file = await port.readFile(path)\n if (!cancelled && !dirtyRef.current) setSelectedFile(file)\n } catch (err) {\n // Surface read failures instead of making them indistinguishable from\n // the intentionally empty \"no file selected\" state.\n if (!cancelled) {\n const failure = reportFailure('read', 'operation', err, 'Failed to read file', path)\n setSelectedFile((current) => current?.path === path ? current : null)\n setReadError(failure.message)\n }\n } finally {\n if (!cancelled) setFileLoading(false)\n }\n })()\n return () => {\n cancelled = true\n }\n }, [port, selectedPath, resolvedSelectedPath, treeLoading, treeLoaded, isDirty, saving, reloadNonce, commitPath, reportFailure])\n\n useEffect(() => {\n if (!selectedFile) {\n loadedPathRef.current = null\n savedContentRef.current = ''\n setRichDraft('')\n setSourceDraft('')\n setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n return\n }\n const pathChanged = loadedPathRef.current !== selectedFile.path\n loadedPathRef.current = selectedFile.path\n savedContentRef.current = selectedFile.content\n setRichDraft(activeCodec.parse(selectedFile.content))\n setSourceDraft(selectedFile.content)\n if (pathChanged) setEditorMode('rich')\n setIsDirty(false)\n setSaveError(null)\n setDockOpen(false)\n }, [selectedFile?.path, selectedFile?.content, activeCodec])\n\n const guardedOpen = useCallback(\n (path: string) => {\n if (path === selectedPath) return\n if (isDirty) {\n setPendingNav({ type: 'open', path })\n return\n }\n commitPath(path)\n },\n [isDirty, selectedPath, commitPath],\n )\n\n // Clicking a folder makes it the vault's active folder: the search narrows to\n // it and a new file lands inside it. Clicking it again clears that — the same\n // row is the way back out, so the gesture is reversible where it was made.\n const toggleFolder = useCallback((path: string) => {\n setFolderPath((current) => (current === path ? null : path))\n }, [])\n\n // Some tree models keep their original selection callback while resetting\n // paths internally. Keep the callable stable, but have it execute the latest\n // path validation and dirty-guard logic.\n const selectFileRef = useRef<(path: string) => void>(() => {})\n selectFileRef.current = (rawPath: string) => {\n const target = resolveTreePath(rawPath, treePaths)\n if (!target) return\n if (target.type === 'file') {\n guardedOpen(target.path)\n return\n }\n toggleFolder(target.path)\n }\n const handleTreeSelect = useCallback((path: string) => selectFileRef.current(path), [])\n\n const guardedClose = useCallback(() => {\n if (isDirty) {\n setPendingNav({ type: 'close' })\n return\n }\n commitPath(null)\n setSelectedFile(null)\n }, [isDirty, commitPath])\n\n const confirmDiscard = useCallback(() => {\n const nav = pendingNav\n setPendingNav(null)\n setIsDirty(false)\n if (!nav) return\n if (nav.type === 'open') {\n commitPath(nav.path)\n } else {\n commitPath(null)\n setSelectedFile(null)\n }\n }, [pendingNav, commitPath])\n\n const showRichMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'rich') return mode\n setRichDraft(activeCodec.parse(sourceDraft))\n setIsDirty(sourceDraft !== savedContentRef.current)\n return 'rich'\n })\n }, [activeCodec, sourceDraft])\n\n const showSourceMode = useCallback(() => {\n setEditorMode((mode) => {\n if (mode === 'source') return mode\n const content = isDirty ? activeCodec.serialize(richDraft) : savedContentRef.current\n setSourceDraft(content)\n setIsDirty(content !== savedContentRef.current)\n return 'source'\n })\n }, [activeCodec, isDirty, richDraft])\n\n const onSourceChange = useCallback((next: string) => {\n dirtyRef.current = next !== savedContentRef.current\n setSourceDraft(next)\n setIsDirty(dirtyRef.current)\n }, [])\n\n const onRichChange = useCallback((next: VaultRichParts) => {\n dirtyRef.current = activeCodec.serialize(next) !== savedContentRef.current\n setRichDraft(next)\n setIsDirty(dirtyRef.current)\n }, [activeCodec])\n\n const saveCurrent = useCallback(async () => {\n if (!selectedFile) return\n const content = editorMode === 'source' ? sourceDraft : activeCodec.serialize(richDraft)\n setSaving(true)\n setSaveError(null)\n try {\n await port.writeFile(selectedFile.path, content)\n savedContentRef.current = content\n setSelectedFile({ ...selectedFile, content })\n setSourceDraft(content)\n setRichDraft(activeCodec.parse(content))\n setIsDirty(false)\n } catch (error) {\n setSaveError(reportFailure('save', 'operation', error, 'Failed to save file', selectedFile.path))\n } finally {\n setSaving(false)\n }\n }, [selectedFile, editorMode, sourceDraft, richDraft, activeCodec, port, reportFailure])\n\n const handleCreate = useCallback(async () => {\n const trimmed = newPath.trim()\n // Same rule as the confirm button, enforced here too: the dialog can also be\n // confirmed by keyboard, and a directory path is not a file to create.\n if (!trimmed || !(trimmed.split('/').pop()?.trim())) return\n setCreating(true)\n setCreateError(null)\n try {\n const created = await port.createFile(trimmed)\n setCreateOpen(false)\n setNewPath('')\n const refreshed = await refresh({\n operation: 'create',\n phase: 'post-mutation-refresh',\n path: created,\n selectAfterRecovery: created,\n })\n if (refreshed) commitPath(created)\n } catch (error) {\n setCreateError(reportFailure('create', 'operation', error, 'Failed to create file', trimmed))\n } finally {\n setCreating(false)\n }\n }, [newPath, port, refresh, commitPath, reportFailure])\n\n const handleDelete = useCallback(async () => {\n if (!selectedFile) return\n const path = selectedFile.path\n setDeleting(true)\n setDeleteError(null)\n try {\n await port.deleteFile(path)\n setDeleteOpen(false)\n setIsDirty(false)\n commitPath(null)\n setSelectedFile(null)\n await refresh({ operation: 'delete', phase: 'post-mutation-refresh', path })\n } catch (error) {\n setDeleteError(reportFailure('delete', 'operation', error, 'Failed to delete file', path))\n } finally {\n setDeleting(false)\n }\n }, [selectedFile, port, refresh, commitPath, reportFailure])\n\n const createFileName = newPath.trim().split('/').pop()?.trim() ?? ''\n\n let treeContent: ReactNode\n if (!treeLoaded && (treeLoading || !treeError)) {\n treeContent = <TreeSkeleton />\n } else if (!treeLoaded && treeError) {\n treeContent = <TreeErrorState message={treeFailureMessage(treeError.failure)} onRetry={() => void retryTree()} />\n } else {\n treeContent = (\n <>\n {treeError && (\n <OperationErrorAlert\n message={treeFailureMessage(treeError.failure)}\n retryLabel=\"Retry vault refresh\"\n onRetry={() => void retryTree()}\n onDismiss={() => setTreeError(null)}\n />\n )}\n {renderTree({\n root: visibleRoot,\n selectedPath: resolvedSelectedPath ?? undefined,\n onSelect: handleTreeSelect,\n })}\n </>\n )\n }\n\n return (\n <EditorErrorBoundary onReset={() => { commitPath(null); setSelectedFile(null) }}>\n <div className={`flex min-h-0 flex-1 overflow-hidden ${className ?? ''}`}>\n <div className=\"flex w-[23rem] min-w-[23rem] flex-col border-r border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <div className=\"min-w-0 flex-1\">\n <input\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={activeFolder ? `Search ${activeFolder}…` : 'Search…'}\n aria-label=\"Search vault\"\n className=\"h-8 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {headerActions}\n <button\n type=\"button\"\n aria-label=\"Refresh vault\"\n onClick={() => void refresh()}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n ↻\n </button>\n {canWrite && (\n <button\n type=\"button\"\n aria-label={activeFolder ? `New vault file in ${activeFolder}` : 'New vault file'}\n onClick={() => { setCreateError(null); setNewPath(activeFolder ? `${activeFolder}/` : ''); setCreateOpen(true) }}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90\"\n >\n +\n </button>\n )}\n </div>\n </div>\n {activeFolder && (\n <div className=\"flex items-center gap-1.5 border-b border-border bg-muted/40 px-4 py-1.5 text-xs\">\n <Folder className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n <span data-vault-folder className=\"min-w-0 flex-1 truncate font-medium text-foreground\" title={activeFolder}>\n {activeFolder}\n </span>\n <button\n type=\"button\"\n aria-label=\"Clear the active folder\"\n onClick={() => setFolderPath(null)}\n className=\"shrink-0 rounded px-1 text-muted-foreground underline-offset-2 transition-colors hover:text-foreground hover:underline\"\n >\n Clear\n </button>\n </div>\n )}\n <div\n className=\"flex-1 overflow-y-auto\"\n onClickCapture={(event) => {\n const target = treeClickTarget(event)\n if (target) handleTreeSelect(target.path)\n }}\n >\n {treeContent}\n </div>\n </div>\n\n <div className=\"flex min-w-0 flex-1 flex-col overflow-hidden\">\n {selectedFile && (\n <div className={`flex shrink-0 items-center justify-between border-b border-border px-4 py-1.5 ${pathBarClassName ?? 'bg-card'}`}>\n <span data-vault-path className=\"truncate text-xs font-medium text-foreground\">{selectedFile.path}</span>\n <div className=\"flex items-center gap-1\">\n {canWrite && isMarkdownCapable && (\n <div className=\"mr-1 flex items-center gap-1\">\n <button\n type=\"button\"\n aria-label=\"Edit as rich text\"\n aria-pressed={editorMode === 'rich'}\n onClick={showRichMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'rich'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Rich\n </button>\n <button\n type=\"button\"\n aria-label=\"Edit as source\"\n aria-pressed={editorMode === 'source'}\n onClick={showSourceMode}\n className={`inline-flex h-7 items-center rounded px-2 text-xs transition-colors ${\n editorMode === 'source'\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n Source\n </button>\n </div>\n )}\n {renderDock && !persistentDock && (\n <button\n type=\"button\"\n aria-label={dockToggleCfg.label}\n aria-pressed={dockOpen}\n disabled={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty}\n title={(dockToggleCfg.disabledWhenDirty ?? true) && isDirty ? 'Save your changes first' : (dockToggleCfg.title ?? dockToggleCfg.label)}\n onClick={() => setDockOpen((v) => !v)}\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs transition-colors disabled:pointer-events-none disabled:opacity-40 ${\n dockOpen\n ? 'bg-primary text-primary-foreground'\n : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n }`}\n >\n {dockToggleCfg.label}\n </button>\n )}\n {onDownloadFile && (\n <button\n type=\"button\"\n aria-label=\"Download this file\"\n title=\"Download file\"\n onClick={() => onDownloadFile(selectedFile)}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n {canWrite && (\n <button\n type=\"button\"\n aria-label=\"Delete this file\"\n title=\"Delete file\"\n onClick={() => { setDeleteError(null); setDeleteOpen(true) }}\n className=\"inline-flex h-7 w-7 items-center justify-center rounded text-destructive/70 transition-colors hover:bg-destructive/10 hover:text-destructive\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n {selectedFile && saveError && (\n <OperationErrorAlert\n message={saveError.message}\n retryLabel=\"Retry save\"\n onRetry={() => void saveCurrent()}\n onDismiss={() => setSaveError(null)}\n />\n )}\n {readError && selectedFile?.path === resolvedSelectedPath && (\n <OperationErrorAlert\n message={readError}\n retryLabel=\"Retry file refresh\"\n onRetry={() => setReloadNonce((n) => n + 1)}\n onDismiss={() => setReadError(null)}\n />\n )}\n <div className=\"flex-1 overflow-hidden\">\n {fileLoading && selectedFile?.path !== resolvedSelectedPath ? (\n <EditorSkeleton />\n ) : readError && selectedFile?.path !== resolvedSelectedPath ? (\n <ReadErrorState message={readError} onRetry={() => setReloadNonce((n) => n + 1)} />\n ) : selectedFile && canWrite && isMarkdownCapable && editorMode === 'source' ? (\n <SourceEditor\n path={selectedFile.path}\n content={sourceDraft}\n saving={saving}\n dirty={isDirty}\n onChange={onSourceChange}\n onSave={() => void saveCurrent()}\n />\n ) : selectedFile ? (\n renderArtifact({\n file: selectedFile,\n loading: false,\n mode: editorMode,\n canWrite,\n richDraft,\n dirty: isDirty,\n onRichChange,\n onSave: () => void saveCurrent(),\n })\n ) : null}\n </div>\n </div>\n\n {renderDock && selectedFile && renderDock({\n file: selectedFile,\n open: persistentDock ? true : dockOpen,\n onClose: persistentDock ? () => {} : () => setDockOpen(false),\n })}\n\n <ConfirmDialog\n open={createOpen}\n title=\"Create vault file\"\n description={activeFolder ? `Add a new document to ${activeFolder}.` : 'Add a new document to this vault.'}\n confirmLabel={creating ? 'Creating…' : 'Create'}\n // A prefilled folder is a path with no file name yet, so emptiness is\n // not the test — `folder/` would otherwise be sent to the port as a\n // file to create.\n confirmDisabled={creating || !createFileName}\n onConfirm={() => void handleCreate()}\n onCancel={() => { setCreateOpen(false); setNewPath(''); setCreateError(null) }}\n >\n <div className=\"space-y-2\">\n <input\n value={newPath}\n autoFocus\n onChange={(e) => setNewPath(e.target.value)}\n placeholder=\"e.g. playbooks/new-strategy.md\"\n aria-label=\"New file path\"\n className=\"h-9 w-full rounded-md border border-border bg-background px-3 text-sm text-foreground placeholder:text-muted-foreground\"\n />\n {createError && <p role=\"alert\" className=\"text-xs text-destructive\">{createError.message}</p>}\n </div>\n </ConfirmDialog>\n\n <ConfirmDialog\n open={deleteOpen}\n title=\"Delete file?\"\n description={`This permanently removes ${selectedFile?.path ?? 'this file'} from the vault.`}\n confirmLabel={deleting ? 'Deleting…' : 'Delete file'}\n confirmDisabled={deleting}\n destructive\n onConfirm={() => void handleDelete()}\n onCancel={() => { setDeleteOpen(false); setDeleteError(null) }}\n >\n {deleteError && <p role=\"alert\" className=\"text-xs text-destructive\">{deleteError.message}</p>}\n </ConfirmDialog>\n\n <ConfirmDialog\n open={pendingNav !== null}\n title=\"Discard unsaved changes?\"\n description=\"Your edits to this document haven't been saved. Continue and lose them?\"\n confirmLabel=\"Discard changes\"\n destructive\n onConfirm={confirmDiscard}\n onCancel={() => setPendingNav(null)}\n />\n </div>\n </EditorErrorBoundary>\n )\n}\n\nfunction SourceEditor({\n path,\n content,\n saving,\n dirty,\n onChange,\n onSave,\n}: {\n path: string\n content: string\n saving: boolean\n dirty: boolean\n onChange: (content: string) => void\n onSave: () => void\n}) {\n return (\n <div className=\"flex h-full min-h-0 flex-col bg-background\">\n <div className=\"flex items-center justify-between gap-2 border-b border-border px-4 py-2\">\n <p className=\"truncate font-mono text-xs text-muted-foreground\">{path}</p>\n <div className=\"flex shrink-0 items-center gap-2\">\n <span className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs text-muted-foreground\">\n {dirty ? 'Unsaved changes' : 'Saved'}\n </span>\n <button\n type=\"button\"\n onClick={onSave}\n disabled={saving || !dirty}\n className=\"inline-flex h-7 items-center rounded-md bg-primary px-2 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\"\n >\n {saving ? 'Saving…' : 'Save'}\n </button>\n </div>\n </div>\n <textarea\n value={content}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n aria-label=\"Source editor\"\n // Full-bleed editor: keep the floor's ring but draw it inside the border\n // box, since an outward ring on a `flex-1` pane child is clipped.\n className=\"min-h-0 flex-1 resize-none border-0 bg-background p-4 font-mono text-sm leading-6 text-foreground focus-visible:[outline-offset:-2px]\"\n />\n </div>\n )\n}\n","/**\n * Self-contained confirm dialog — no dialog library. A focus-trapped modal with\n * Esc-to-cancel and Enter-to-confirm, used for create / delete / discard-unsaved\n * flows so the pane carries zero UI-kit dependency.\n */\n\nimport { useEffect, useRef, type ReactNode } from 'react'\n\nexport interface ConfirmDialogProps {\n open: boolean\n title: string\n description?: ReactNode\n confirmLabel?: string\n cancelLabel?: string\n /** Styles the confirm button as a destructive action. */\n destructive?: boolean\n /** Disables the confirm button (e.g. while the action is in flight). */\n confirmDisabled?: boolean\n onConfirm: () => void\n onCancel: () => void\n /** Optional body (e.g. an input field for the create flow). */\n children?: ReactNode\n}\n\nexport function ConfirmDialog({\n open,\n title,\n description,\n confirmLabel = 'Confirm',\n cancelLabel = 'Cancel',\n destructive = false,\n confirmDisabled = false,\n onConfirm,\n onCancel,\n children,\n}: ConfirmDialogProps) {\n const panelRef = useRef<HTMLDivElement>(null)\n const confirmRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n if (!open) return\n confirmRef.current?.focus()\n }, [open])\n\n if (!open) return null\n\n function onKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && !confirmDisabled) {\n event.preventDefault()\n onConfirm()\n return\n }\n if (event.key !== 'Tab') return\n const focusable = panelRef.current?.querySelectorAll<HTMLElement>(\n 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\n )\n if (!focusable || focusable.length === 0) return\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement as HTMLElement | null\n if (event.shiftKey && active === first) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first?.focus()\n }\n }\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel() }}\n >\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={onKeyDown}\n className=\"w-full max-w-md rounded-lg border border-border bg-card p-5 shadow-lg\"\n >\n <h2 className=\"text-sm font-semibold text-foreground\">{title}</h2>\n {description && <p className=\"mt-1.5 text-xs text-muted-foreground\">{description}</p>}\n {children && <div className=\"mt-3\">{children}</div>}\n <div className=\"mt-5 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex h-8 items-center rounded-md px-3 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n {cancelLabel}\n </button>\n <button\n ref={confirmRef}\n type=\"button\"\n onClick={onConfirm}\n disabled={confirmDisabled}\n className={`inline-flex h-8 items-center rounded-md px-3 text-xs font-medium transition-colors disabled:pointer-events-none disabled:opacity-50 ${\n destructive\n ? 'bg-destructive text-destructive-foreground hover:bg-destructive/90'\n : 'bg-primary text-primary-foreground hover:bg-primary/90'\n }`}\n >\n {confirmLabel}\n </button>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","jsx","jsxs","path","useRef","useEffect"]}