@petrarca/sonnet-shell 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,8 +4,9 @@ import {
4
4
  useEffect as useEffect3,
5
5
  useCallback as useCallback2,
6
6
  useRef as useRef2,
7
- useMemo as useMemo3
7
+ useMemo as useMemo5
8
8
  } from "react";
9
+ import { useResizablePanel as useResizablePanel2 } from "@petrarca/sonnet-core/hooks";
9
10
  import { Outlet, useLocation as useLocation2, useNavigate as useNavigate2 } from "react-router-dom";
10
11
  import { TooltipProvider } from "@petrarca/sonnet-ui";
11
12
  import { ScrollArea as ScrollArea2 } from "@petrarca/sonnet-ui";
@@ -74,6 +75,9 @@ function ShellFooter({ children }) {
74
75
  return /* @__PURE__ */ jsx3("footer", { className: "h-8 shrink-0 border-t border-border flex items-center justify-between px-3 bg-background text-[11px] text-muted-foreground z-20", children });
75
76
  }
76
77
 
78
+ // src/ShellRail.tsx
79
+ import { useMemo as useMemo3 } from "react";
80
+
77
81
  // src/IconRail.tsx
78
82
  import { cn } from "@petrarca/sonnet-core";
79
83
  import { Button as Button2, Separator } from "@petrarca/sonnet-ui";
@@ -98,7 +102,9 @@ function RailIcon({
98
102
  icon: Icon,
99
103
  label,
100
104
  active = false,
101
- onClick
105
+ onClick,
106
+ disabled = false,
107
+ tooltip
102
108
  }) {
103
109
  return /* @__PURE__ */ jsxs2(Tooltip, { delayDuration: 0, children: [
104
110
  /* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
@@ -106,10 +112,11 @@ function RailIcon({
106
112
  {
107
113
  variant: "ghost",
108
114
  size: "compact",
109
- onClick,
115
+ "aria-disabled": disabled || void 0,
116
+ onClick: disabled ? void 0 : onClick,
110
117
  className: cn(
111
118
  "h-10 w-10 rounded-lg transition-colors",
112
- active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-muted-foreground/10"
119
+ disabled ? "text-muted-foreground/40 cursor-default hover:bg-transparent" : active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-muted-foreground/10"
113
120
  ),
114
121
  children: [
115
122
  /* @__PURE__ */ jsx4(Icon, { className: "h-5 w-5" }),
@@ -117,7 +124,7 @@ function RailIcon({
117
124
  ]
118
125
  }
119
126
  ) }),
120
- /* @__PURE__ */ jsx4(TooltipContent, { side: "right", sideOffset: 8, children: label })
127
+ /* @__PURE__ */ jsx4(TooltipContent, { side: "right", sideOffset: 8, children: tooltip ?? label })
121
128
  ] });
122
129
  }
123
130
  function RailSeparator() {
@@ -645,10 +652,82 @@ function useShellNavigation() {
645
652
  return ctx;
646
653
  }
647
654
 
655
+ // src/shellConfig.ts
656
+ import { createContext as createContext3, useContext as useContext3 } from "react";
657
+ var ShellConfigContext = createContext3(null);
658
+ function useShellConfig() {
659
+ const config = useContext3(ShellConfigContext);
660
+ if (!config) {
661
+ throw new Error("useShellConfig must be used within a ShellConfigProvider");
662
+ }
663
+ return config;
664
+ }
665
+
666
+ // src/capabilities.ts
667
+ import { warnLog as warnLog3 } from "@petrarca/sonnet-core";
668
+ var DEFAULT_CAPABILITY_POLICY = {
669
+ "missing-state": { rail: "disabled", command: "disabled", route: "redirect" },
670
+ "not-authorized": { rail: "hidden", command: "hidden", route: "redirect" },
671
+ "not-authorized-soft": {
672
+ rail: "disabled",
673
+ command: "disabled",
674
+ route: "redirect"
675
+ },
676
+ "feature-off": { rail: "hidden", command: "disabled", route: "redirect" },
677
+ error: { rail: "hidden", command: "hidden", route: "redirect" }
678
+ };
679
+ var EFFECT_RANK = {
680
+ hidden: 3,
681
+ redirect: 2,
682
+ disabled: 1,
683
+ visible: 0
684
+ };
685
+ function resolveCapabilityPolicy(override) {
686
+ if (!override) return DEFAULT_CAPABILITY_POLICY;
687
+ const merged = {};
688
+ for (const kind of Object.keys(DEFAULT_CAPABILITY_POLICY)) {
689
+ merged[kind] = {
690
+ ...DEFAULT_CAPABILITY_POLICY[kind],
691
+ ...override[kind] ?? {}
692
+ };
693
+ }
694
+ return merged;
695
+ }
696
+ function foldUnmet(effect, resultReason, acc) {
697
+ const rank = EFFECT_RANK[effect];
698
+ const worstRank = EFFECT_RANK[acc.effect];
699
+ if (rank > worstRank) {
700
+ return { effect, reason: resultReason };
701
+ }
702
+ if (rank === worstRank && !acc.reason && resultReason) {
703
+ return { effect: acc.effect, reason: resultReason };
704
+ }
705
+ return acc;
706
+ }
707
+ function evaluateModule(module, surface, resolve, policy) {
708
+ const capabilities = module.requires;
709
+ if (!capabilities || capabilities.length === 0) return { effect: "visible" };
710
+ if (!resolve) return { effect: "visible" };
711
+ let acc = { effect: "visible" };
712
+ for (const capability of capabilities) {
713
+ const result = resolve(capability);
714
+ if (result.met) continue;
715
+ const kind = result.kind ?? "error";
716
+ if (kind === "error") {
717
+ warnLog3(
718
+ `[capabilities] unmet capability "${capability}" resolved to kind "error" (fail-closed)`
719
+ );
720
+ }
721
+ acc = foldUnmet(policy[kind][surface], result.reason, acc);
722
+ }
723
+ return acc;
724
+ }
725
+
648
726
  // src/ShellRail.tsx
649
727
  import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
650
728
  function ShellRail() {
651
729
  const { mainModules, bottomModules } = useShellModules();
730
+ const { resolveCapability, capabilityPolicy } = useShellConfig();
652
731
  const {
653
732
  activeService,
654
733
  sidePaneModuleId,
@@ -657,29 +736,37 @@ function ShellRail() {
657
736
  onServiceSelect
658
737
  } = useShellNavigation();
659
738
  const isActive = (id) => activeService?.id === id || sidePaneModuleId === id;
739
+ const policy = useMemo3(
740
+ () => resolveCapabilityPolicy(capabilityPolicy),
741
+ [capabilityPolicy]
742
+ );
743
+ const renderModule = (service) => {
744
+ const { effect, reason } = evaluateModule(
745
+ service,
746
+ "rail",
747
+ resolveCapability,
748
+ policy
749
+ );
750
+ if (effect === "hidden" || effect === "redirect") return null;
751
+ const disabled = effect === "disabled";
752
+ return /* @__PURE__ */ jsx8(
753
+ RailIcon,
754
+ {
755
+ icon: service.icon,
756
+ label: service.label,
757
+ active: isActive(service.id),
758
+ onClick: () => onServiceSelect(service.id),
759
+ disabled,
760
+ tooltip: disabled && reason ? `${service.label} \u2014 ${reason}` : void 0
761
+ },
762
+ service.id
763
+ );
764
+ };
660
765
  return /* @__PURE__ */ jsxs6(Fragment, { children: [
661
766
  /* @__PURE__ */ jsxs6(IconRail, { children: [
662
- /* @__PURE__ */ jsx8("div", { className: "flex-1 flex flex-col items-center gap-1 overflow-y-auto", children: mainModules.map((service) => /* @__PURE__ */ jsx8(
663
- RailIcon,
664
- {
665
- icon: service.icon,
666
- label: service.label,
667
- active: isActive(service.id),
668
- onClick: () => onServiceSelect(service.id)
669
- },
670
- service.id
671
- )) }),
767
+ /* @__PURE__ */ jsx8("div", { className: "flex-1 flex flex-col items-center gap-1 overflow-y-auto", children: mainModules.map(renderModule) }),
672
768
  /* @__PURE__ */ jsx8(RailSeparator, {}),
673
- /* @__PURE__ */ jsx8("div", { className: "flex flex-col items-center gap-1", children: bottomModules.map((service) => /* @__PURE__ */ jsx8(
674
- RailIcon,
675
- {
676
- icon: service.icon,
677
- label: service.label,
678
- active: isActive(service.id),
679
- onClick: () => onServiceSelect(service.id)
680
- },
681
- service.id
682
- )) })
769
+ /* @__PURE__ */ jsx8("div", { className: "flex flex-col items-center gap-1", children: bottomModules.map(renderModule) })
683
770
  ] }),
684
771
  activeService && activeService.navigation.length > 0 && /* @__PURE__ */ jsx8(
685
772
  SubNavPanel,
@@ -694,23 +781,25 @@ function ShellRail() {
694
781
 
695
782
  // src/SidePane.tsx
696
783
  import { X } from "lucide-react";
697
- import { cn as cn4 } from "@petrarca/sonnet-core";
784
+ import { cn as cn5 } from "@petrarca/sonnet-core";
698
785
  import { useResizablePanel } from "@petrarca/sonnet-core/hooks";
699
786
 
700
787
  // src/sidePaneState.ts
701
- import { createContext as createContext3, useContext as useContext3 } from "react";
702
- var SidePaneContext = createContext3(null);
788
+ import { createContext as createContext4, useContext as useContext4 } from "react";
789
+ var SidePaneContext = createContext4(null);
703
790
  function useSidePaneState() {
704
- const ctx = useContext3(SidePaneContext);
791
+ const ctx = useContext4(SidePaneContext);
705
792
  if (!ctx) {
706
793
  throw new Error("useSidePaneState must be used within an AppShell");
707
794
  }
708
795
  return ctx;
709
796
  }
710
797
 
711
- // src/SidePane.tsx
712
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
798
+ // src/DragHandle.tsx
799
+ import { cn as cn4 } from "@petrarca/sonnet-core";
800
+ import { jsx as jsx9 } from "react/jsx-runtime";
713
801
  function DragHandle({
802
+ edge,
714
803
  separatorProps,
715
804
  onPointerDown,
716
805
  onDoubleClick
@@ -722,19 +811,28 @@ function DragHandle({
722
811
  onPointerDown,
723
812
  onDoubleClick,
724
813
  className: cn4(
725
- "absolute right-0 top-0 h-full w-1 cursor-col-resize",
726
- "hover:bg-primary/40 active:bg-primary/60 transition-colors"
814
+ // 8px invisible hit area; visual feedback only via the before pseudo-element.
815
+ "absolute top-0 h-full w-2 cursor-col-resize",
816
+ edge === "right" ? "right-0" : "left-0",
817
+ // Centered line: invisible at rest, 2px on hover, 4px while dragging.
818
+ "before:absolute before:inset-y-0 before:left-1/2 before:-translate-x-1/2",
819
+ "before:w-0 before:transition-all before:duration-150",
820
+ "hover:before:w-0.5 hover:before:bg-primary/60",
821
+ "active:before:w-1 active:before:bg-primary/80"
727
822
  )
728
823
  }
729
824
  );
730
825
  }
826
+
827
+ // src/SidePane.tsx
828
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
731
829
  var DEFAULT_WIDTH = 320;
732
830
  var DEFAULT_MIN = 240;
733
831
  var DEFAULT_MAX = 800;
734
832
  function SidePane() {
735
833
  const { pane, close } = useSidePaneState();
736
834
  if (!pane) return null;
737
- return /* @__PURE__ */ jsx9(SidePaneOpen, { pane, onClose: close });
835
+ return /* @__PURE__ */ jsx10(SidePaneOpen, { pane, onClose: close });
738
836
  }
739
837
  function SidePaneOpen({
740
838
  pane,
@@ -750,29 +848,30 @@ function SidePaneOpen({
750
848
  return /* @__PURE__ */ jsxs7(
751
849
  "div",
752
850
  {
753
- className: cn4(
851
+ className: cn5(
754
852
  "relative flex flex-col border-r bg-background",
755
853
  isFullWidth ? "flex-1" : "shrink-0"
756
854
  ),
757
855
  style: isFullWidth ? void 0 : { width: panelWidth },
758
856
  children: [
759
- /* @__PURE__ */ jsx9("div", { className: "flex h-10 shrink-0 items-center justify-end border-b px-2", children: /* @__PURE__ */ jsx9(
857
+ /* @__PURE__ */ jsx10("div", { className: "flex h-10 shrink-0 items-center justify-end border-b px-2", children: /* @__PURE__ */ jsx10(
760
858
  "button",
761
859
  {
762
860
  onClick: onClose,
763
- className: cn4(
861
+ className: cn5(
764
862
  "flex h-6 w-6 items-center justify-center rounded text-muted-foreground",
765
863
  "hover:bg-accent hover:text-foreground transition-colors",
766
864
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
767
865
  ),
768
866
  "aria-label": "Close side pane",
769
- children: /* @__PURE__ */ jsx9(X, { className: "h-3.5 w-3.5" })
867
+ children: /* @__PURE__ */ jsx10(X, { className: "h-3.5 w-3.5" })
770
868
  }
771
869
  ) }),
772
- /* @__PURE__ */ jsx9("div", { className: "flex-1 overflow-auto", children: pane.content }),
773
- !isFullWidth && /* @__PURE__ */ jsx9(
870
+ /* @__PURE__ */ jsx10("div", { className: "flex-1 overflow-auto", children: pane.content }),
871
+ !isFullWidth && /* @__PURE__ */ jsx10(
774
872
  DragHandle,
775
873
  {
874
+ edge: "right",
776
875
  separatorProps,
777
876
  onPointerDown: handlePointerDown,
778
877
  onDoubleClick: handleDoubleClick
@@ -784,7 +883,7 @@ function SidePaneOpen({
784
883
  }
785
884
 
786
885
  // src/CommandMenu.tsx
787
- import { useEffect as useEffect2, useCallback } from "react";
886
+ import { useEffect as useEffect2, useCallback, useMemo as useMemo4 } from "react";
788
887
  import { useNavigate } from "react-router-dom";
789
888
  import {
790
889
  CommandDialog,
@@ -795,10 +894,11 @@ import {
795
894
  CommandList,
796
895
  CommandSeparator
797
896
  } from "@petrarca/sonnet-ui";
798
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
897
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
799
898
  function CommandMenu({ open, onOpenChange }) {
800
899
  const navigate = useNavigate();
801
900
  const { mainModules, bottomModules } = useShellModules();
901
+ const { resolveCapability, capabilityPolicy } = useShellConfig();
802
902
  useEffect2(() => {
803
903
  const handleKeyDown = (e) => {
804
904
  if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
@@ -809,6 +909,11 @@ function CommandMenu({ open, onOpenChange }) {
809
909
  document.addEventListener("keydown", handleKeyDown);
810
910
  return () => document.removeEventListener("keydown", handleKeyDown);
811
911
  }, [open, onOpenChange]);
912
+ const policy = useMemo4(
913
+ () => resolveCapabilityPolicy(capabilityPolicy),
914
+ [capabilityPolicy]
915
+ );
916
+ const moduleEffect = (service) => evaluateModule(service, "command", resolveCapability, policy);
812
917
  const handleSelect = useCallback(
813
918
  (path) => {
814
919
  navigate(path);
@@ -818,17 +923,21 @@ function CommandMenu({ open, onOpenChange }) {
818
923
  );
819
924
  const renderNavGroup = (service) => {
820
925
  if (service.navigation.length === 0) return null;
926
+ const { effect, reason } = moduleEffect(service);
927
+ if (effect === "hidden" || effect === "redirect") return null;
928
+ const disabled = effect === "disabled";
821
929
  const Icon = service.icon;
822
- return /* @__PURE__ */ jsx10(CommandGroup, { heading: service.label, children: service.navigation.flatMap(
930
+ return /* @__PURE__ */ jsx11(CommandGroup, { heading: service.label, children: service.navigation.flatMap(
823
931
  (group) => group.links.map((link) => /* @__PURE__ */ jsxs8(
824
932
  CommandItem,
825
933
  {
826
934
  value: `${service.label} ${group.heading ?? ""} ${link.label}`,
827
- onSelect: () => handleSelect(link.path),
935
+ disabled,
936
+ onSelect: disabled ? void 0 : () => handleSelect(link.path),
828
937
  children: [
829
- /* @__PURE__ */ jsx10(Icon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
830
- /* @__PURE__ */ jsx10("span", { children: link.label }),
831
- group.heading && /* @__PURE__ */ jsx10("span", { className: "ml-auto text-xs text-muted-foreground", children: group.heading })
938
+ /* @__PURE__ */ jsx11(Icon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
939
+ /* @__PURE__ */ jsx11("span", { children: link.label }),
940
+ disabled && reason ? /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: reason }) : group.heading && /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: group.heading })
832
941
  ]
833
942
  },
834
943
  link.path
@@ -837,8 +946,11 @@ function CommandMenu({ open, onOpenChange }) {
837
946
  };
838
947
  const renderCommandGroup = (service) => {
839
948
  if (!service.commands?.length) return null;
949
+ const { effect, reason } = moduleEffect(service);
950
+ if (effect === "hidden" || effect === "redirect") return null;
951
+ const disabled = effect === "disabled";
840
952
  const Icon = service.icon;
841
- return /* @__PURE__ */ jsx10(
953
+ return /* @__PURE__ */ jsx11(
842
954
  CommandGroup,
843
955
  {
844
956
  heading: service.commands[0].group ?? service.label,
@@ -848,13 +960,15 @@ function CommandMenu({ open, onOpenChange }) {
848
960
  CommandItem,
849
961
  {
850
962
  value: `${service.label} ${cmd.label}`,
851
- onSelect: () => {
963
+ disabled,
964
+ onSelect: disabled ? void 0 : () => {
852
965
  cmd.action();
853
966
  onOpenChange(false);
854
967
  },
855
968
  children: [
856
- /* @__PURE__ */ jsx10(CmdIcon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
857
- /* @__PURE__ */ jsx10("span", { children: cmd.label })
969
+ /* @__PURE__ */ jsx11(CmdIcon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
970
+ /* @__PURE__ */ jsx11("span", { children: cmd.label }),
971
+ disabled && reason && /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: reason })
858
972
  ]
859
973
  },
860
974
  cmd.id
@@ -865,45 +979,69 @@ function CommandMenu({ open, onOpenChange }) {
865
979
  );
866
980
  };
867
981
  const allModules = [...mainModules, ...bottomModules];
982
+ const hasVisibleNav = (modules) => modules.some(
983
+ (m) => m.navigation.length > 0 && !["hidden", "redirect"].includes(moduleEffect(m).effect)
984
+ );
985
+ const hasVisibleCmds = allModules.some(
986
+ (m) => (m.commands?.length ?? 0) > 0 && !["hidden", "redirect"].includes(moduleEffect(m).effect)
987
+ );
868
988
  return /* @__PURE__ */ jsxs8(CommandDialog, { open, onOpenChange, children: [
869
- /* @__PURE__ */ jsx10(CommandInput, { placeholder: "Search pages, services, actions..." }),
989
+ /* @__PURE__ */ jsx11(CommandInput, { placeholder: "Search pages, services, actions..." }),
870
990
  /* @__PURE__ */ jsxs8(CommandList, { children: [
871
- /* @__PURE__ */ jsx10(CommandEmpty, { children: "No results found." }),
991
+ /* @__PURE__ */ jsx11(CommandEmpty, { children: "No results found." }),
872
992
  mainModules.map(renderNavGroup),
873
- /* @__PURE__ */ jsx10(CommandSeparator, {}),
993
+ hasVisibleNav(mainModules) && hasVisibleNav(bottomModules) && /* @__PURE__ */ jsx11(CommandSeparator, {}),
874
994
  bottomModules.map(renderNavGroup),
875
- allModules.some((m) => m.commands?.length) && /* @__PURE__ */ jsxs8(Fragment2, { children: [
876
- /* @__PURE__ */ jsx10(CommandSeparator, {}),
995
+ hasVisibleCmds && /* @__PURE__ */ jsxs8(Fragment2, { children: [
996
+ /* @__PURE__ */ jsx11(CommandSeparator, {}),
877
997
  allModules.map(renderCommandGroup)
878
998
  ] })
879
999
  ] })
880
1000
  ] });
881
1001
  }
882
1002
 
883
- // src/shellConfig.ts
884
- import { createContext as createContext4, useContext as useContext4 } from "react";
885
- var ShellConfigContext = createContext4(null);
886
- function useShellConfig() {
887
- const config = useContext4(ShellConfigContext);
888
- if (!config) {
889
- throw new Error("useShellConfig must be used within a ShellConfigProvider");
1003
+ // src/ModuleEffects.tsx
1004
+ import React3 from "react";
1005
+ import { warnLog as warnLog4 } from "@petrarca/sonnet-core";
1006
+ import { Fragment as Fragment3, jsx as jsx12 } from "react/jsx-runtime";
1007
+ var ModuleEffectBoundary = class extends React3.Component {
1008
+ state = { caught: false };
1009
+ static getDerivedStateFromError() {
1010
+ return { caught: true };
890
1011
  }
891
- return config;
1012
+ componentDidCatch(error) {
1013
+ warnLog4(
1014
+ "[ModuleEffects] module '{}' useEffects threw \u2014 effects disabled for this module: {}",
1015
+ this.props.moduleId,
1016
+ error
1017
+ );
1018
+ }
1019
+ render() {
1020
+ return this.state.caught ? null : this.props.children;
1021
+ }
1022
+ };
1023
+ function ModuleEffectHost({ module }) {
1024
+ module.useEffects();
1025
+ return null;
1026
+ }
1027
+ function ModuleEffects({ modules }) {
1028
+ return /* @__PURE__ */ jsx12(Fragment3, { children: modules.filter((m) => typeof m.useEffects === "function").map((m) => /* @__PURE__ */ jsx12(ModuleEffectBoundary, { moduleId: m.id, children: /* @__PURE__ */ jsx12(ModuleEffectHost, { module: m }) }, m.id)) });
892
1029
  }
893
1030
 
894
1031
  // src/AppShell.tsx
895
- import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
896
- var PANEL_WIDTH_CLASS = {
897
- narrow: "w-[480px]",
898
- default: "w-[640px]",
899
- wide: "w-[800px]",
900
- half: "w-[50vw]",
901
- full: "w-screen",
1032
+ import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
1033
+ var PANEL_WIDTHS = {
1034
+ narrow: { css: "w-[480px]", px: 480 },
1035
+ default: { css: "w-[640px]", px: 640 },
1036
+ wide: { css: "w-[800px]", px: 800 },
1037
+ half: { css: "w-[50vw]", px: 640 },
1038
+ full: { css: "w-screen", px: 640 },
902
1039
  // legacy aliases
903
- lg: "w-[640px]",
904
- "1/3": "w-[33vw]",
905
- "1/2": "w-[50vw]"
1040
+ lg: { css: "w-[640px]", px: 640 },
1041
+ "1/3": { css: "w-[33vw]", px: 640 },
1042
+ "1/2": { css: "w-[50vw]", px: 640 }
906
1043
  };
1044
+ var DEFAULT_PANEL = PANEL_WIDTHS.default;
907
1045
  function isSidePaneModule(service) {
908
1046
  return !!service.sidePane && service.navigation.length === 0;
909
1047
  }
@@ -951,7 +1089,7 @@ function useShellApiInit(deps) {
951
1089
  }
952
1090
  function useActiveService(modules) {
953
1091
  const location = useLocation2();
954
- const serviceByBasePath = useMemo3(
1092
+ const serviceByBasePath = useMemo5(
955
1093
  () => new Map(
956
1094
  modules.filter((m) => !m.hidden && m.basePath !== "/").map((m) => [m.basePath, m.id])
957
1095
  ),
@@ -1006,6 +1144,25 @@ function useSidePaneState2() {
1006
1144
  handleSetFullWidth
1007
1145
  };
1008
1146
  }
1147
+ var DEFAULT_RESIZE_MIN = 240;
1148
+ var DEFAULT_RESIZE_MAX = 1200;
1149
+ function resizeOptionsFromPanel(state, widthEntry) {
1150
+ if (!state?.resizable) {
1151
+ return {
1152
+ enabled: false,
1153
+ defaultWidth: widthEntry.px,
1154
+ minWidth: DEFAULT_RESIZE_MIN,
1155
+ maxWidth: DEFAULT_RESIZE_MAX
1156
+ };
1157
+ }
1158
+ const viewportMax = typeof window !== "undefined" ? Math.round(window.innerWidth * 0.9) : DEFAULT_RESIZE_MAX;
1159
+ return {
1160
+ enabled: true,
1161
+ defaultWidth: widthEntry.px,
1162
+ minWidth: state.minWidth ?? DEFAULT_RESIZE_MIN,
1163
+ maxWidth: state.maxWidth ?? viewportMax
1164
+ };
1165
+ }
1009
1166
  function usePanelState() {
1010
1167
  const [panelState, setPanelState] = useState2(null);
1011
1168
  const panelOnCloseRef = useRef2(void 0);
@@ -1017,7 +1174,8 @@ function usePanelState() {
1017
1174
  panelOnCloseRef.current = panelState?.onClose;
1018
1175
  setPanelState(null);
1019
1176
  }, [panelState]);
1020
- const panelWidth = PANEL_WIDTH_CLASS[panelState?.width ?? "default"] ?? PANEL_WIDTH_CLASS.default;
1177
+ const widthEntry = PANEL_WIDTHS[panelState?.width ?? "default"] ?? DEFAULT_PANEL;
1178
+ const panelWidth = widthEntry.css;
1021
1179
  const panelOffsetTop = panelState?.coverage === "full" ? "0px" : "3rem";
1022
1180
  return {
1023
1181
  panelState,
@@ -1025,7 +1183,8 @@ function usePanelState() {
1025
1183
  handleOpen,
1026
1184
  handleClose,
1027
1185
  panelWidth,
1028
- panelOffsetTop
1186
+ panelOffsetTop,
1187
+ resize: resizeOptionsFromPanel(panelState, widthEntry)
1029
1188
  };
1030
1189
  }
1031
1190
  function useDialogState() {
@@ -1041,7 +1200,7 @@ function useDialogState() {
1041
1200
  return { dialogState, setDialogState, handleConfirm, handleCancel };
1042
1201
  }
1043
1202
  function useFeatureLookup(modules) {
1044
- return useMemo3(() => {
1203
+ return useMemo5(() => {
1045
1204
  const map = /* @__PURE__ */ new Map();
1046
1205
  for (const m of modules) {
1047
1206
  for (const group of m.navigation) {
@@ -1120,7 +1279,7 @@ function AppShell({ registry, sidebar }) {
1120
1279
  setSubNavCollapsed
1121
1280
  ]
1122
1281
  );
1123
- const sidePaneContextValue = useMemo3(
1282
+ const sidePaneContextValue = useMemo5(
1124
1283
  () => ({
1125
1284
  pane: sidePane2.sidePaneState,
1126
1285
  open: sidePane2.handleOpen,
@@ -1143,82 +1302,118 @@ function AppShell({ registry, sidebar }) {
1143
1302
  onToggleSubNav: () => setSubNavCollapsed((c) => !c),
1144
1303
  onServiceSelect: handleServiceSelect
1145
1304
  };
1146
- return /* @__PURE__ */ jsx11(ShellModulesContext.Provider, { value: registry, children: /* @__PURE__ */ jsx11(SidePaneContext.Provider, { value: sidePaneContextValue, children: /* @__PURE__ */ jsx11(ShellNavigationContext.Provider, { value: navigationValue, children: /* @__PURE__ */ jsx11(TooltipProvider, { children: /* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen flex-col overflow-hidden", children: [
1147
- /* @__PURE__ */ jsx11(TopBar, { children: config.topBar }),
1148
- /* @__PURE__ */ jsx11(
1149
- CommandMenu,
1150
- {
1151
- open: commandMenuOpen,
1152
- onOpenChange: setCommandMenuOpen
1153
- }
1154
- ),
1155
- /* @__PURE__ */ jsx11(
1156
- ShellBody,
1157
- {
1158
- activeService,
1159
- sidePaneFullWidth: sidePane2.sidePaneState?.fullWidth,
1160
- sidebar
1161
- }
1162
- ),
1163
- config.footer && /* @__PURE__ */ jsx11(ShellFooter, { children: config.footer }),
1164
- dialog2.dialogState && /* @__PURE__ */ jsx11(
1165
- ConfirmDialog,
1166
- {
1167
- open: true,
1168
- title: dialog2.dialogState.opts.title,
1169
- description: dialog2.dialogState.opts.description,
1170
- confirmLabel: dialog2.dialogState.opts.confirmLabel,
1171
- cancelLabel: dialog2.dialogState.opts.cancelLabel,
1172
- variant: dialog2.dialogState.opts.variant,
1173
- onConfirm: dialog2.handleConfirm,
1174
- onCancel: dialog2.handleCancel
1175
- }
1176
- ),
1177
- fullscreenState && /* @__PURE__ */ jsx11("div", { className: "fixed inset-0 z-50 bg-background overflow-auto", children: fullscreenState.content }),
1178
- /* @__PURE__ */ jsx11(
1179
- SlideOverPanel,
1180
- {
1181
- panelState: panel2.panelState,
1182
- panelWidth: panel2.panelWidth,
1183
- panelOffsetTop: panel2.panelOffsetTop,
1184
- panelOnCloseRef: panel2.panelOnCloseRef,
1185
- onClose: panel2.handleClose
1186
- }
1187
- )
1188
- ] }) }) }) }) });
1305
+ return /* @__PURE__ */ jsx13(ShellModulesContext.Provider, { value: registry, children: /* @__PURE__ */ jsx13(SidePaneContext.Provider, { value: sidePaneContextValue, children: /* @__PURE__ */ jsx13(ShellNavigationContext.Provider, { value: navigationValue, children: /* @__PURE__ */ jsxs9(TooltipProvider, { children: [
1306
+ /* @__PURE__ */ jsx13(ModuleEffects, { modules }),
1307
+ /* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen flex-col overflow-hidden", children: [
1308
+ /* @__PURE__ */ jsx13(TopBar, { children: config.topBar }),
1309
+ /* @__PURE__ */ jsx13(
1310
+ CommandMenu,
1311
+ {
1312
+ open: commandMenuOpen,
1313
+ onOpenChange: setCommandMenuOpen
1314
+ }
1315
+ ),
1316
+ /* @__PURE__ */ jsx13(
1317
+ ShellBody,
1318
+ {
1319
+ activeService,
1320
+ sidePaneFullWidth: sidePane2.sidePaneState?.fullWidth,
1321
+ sidebar
1322
+ }
1323
+ ),
1324
+ config.footer && /* @__PURE__ */ jsx13(ShellFooter, { children: config.footer }),
1325
+ dialog2.dialogState && /* @__PURE__ */ jsx13(
1326
+ ConfirmDialog,
1327
+ {
1328
+ open: true,
1329
+ title: dialog2.dialogState.opts.title,
1330
+ description: dialog2.dialogState.opts.description,
1331
+ confirmLabel: dialog2.dialogState.opts.confirmLabel,
1332
+ cancelLabel: dialog2.dialogState.opts.cancelLabel,
1333
+ variant: dialog2.dialogState.opts.variant,
1334
+ onConfirm: dialog2.handleConfirm,
1335
+ onCancel: dialog2.handleCancel
1336
+ }
1337
+ ),
1338
+ fullscreenState && /* @__PURE__ */ jsx13("div", { className: "fixed inset-0 z-50 bg-background overflow-auto", children: fullscreenState.content }),
1339
+ /* @__PURE__ */ jsx13(
1340
+ SlideOverPanel,
1341
+ {
1342
+ panelState: panel2.panelState,
1343
+ panelWidth: panel2.panelWidth,
1344
+ panelOffsetTop: panel2.panelOffsetTop,
1345
+ panelOnCloseRef: panel2.panelOnCloseRef,
1346
+ onClose: panel2.handleClose,
1347
+ resize: panel2.resize
1348
+ }
1349
+ )
1350
+ ] })
1351
+ ] }) }) }) });
1189
1352
  }
1190
1353
  function SlideOverPanel({
1191
1354
  panelState,
1192
1355
  panelWidth,
1193
1356
  panelOffsetTop,
1194
1357
  panelOnCloseRef,
1195
- onClose
1358
+ onClose,
1359
+ resize
1196
1360
  }) {
1197
- return /* @__PURE__ */ jsx11(
1361
+ const sheetProps = {
1362
+ side: "right",
1363
+ offsetTop: panelOffsetTop,
1364
+ onCloseAutoFocus: (e) => {
1365
+ if (panelOnCloseRef.current) {
1366
+ e.preventDefault();
1367
+ panelOnCloseRef.current();
1368
+ }
1369
+ },
1370
+ ...!panelState?.description && { "aria-describedby": void 0 }
1371
+ };
1372
+ return /* @__PURE__ */ jsx13(
1198
1373
  Sheet,
1199
1374
  {
1200
1375
  open: panelState !== null,
1201
1376
  onOpenChange: (open) => {
1202
1377
  if (!open) onClose();
1203
1378
  },
1204
- children: /* @__PURE__ */ jsx11(
1205
- SheetContent,
1206
- {
1207
- side: "right",
1208
- className: `${panelWidth} max-w-[90vw]`,
1209
- offsetTop: panelOffsetTop,
1210
- onCloseAutoFocus: (e) => {
1211
- if (panelOnCloseRef.current) {
1212
- e.preventDefault();
1213
- panelOnCloseRef.current();
1214
- }
1215
- },
1216
- ...!panelState?.description && {
1217
- "aria-describedby": void 0
1218
- },
1219
- children: panelState && /* @__PURE__ */ jsx11(PanelContent, { state: panelState })
1220
- }
1221
- )
1379
+ children: resize.enabled ? /* @__PURE__ */ jsx13(ResizableSheetContent, { ...sheetProps, resize, children: panelState && /* @__PURE__ */ jsx13(PanelContent, { state: panelState }) }) : /* @__PURE__ */ jsx13(SheetContent, { ...sheetProps, className: `${panelWidth} max-w-[90vw]`, children: panelState && /* @__PURE__ */ jsx13(PanelContent, { state: panelState }) })
1380
+ }
1381
+ );
1382
+ }
1383
+ function ResizableSheetContent({
1384
+ resize,
1385
+ children,
1386
+ ...sheetProps
1387
+ }) {
1388
+ const {
1389
+ panelWidth: dynWidth,
1390
+ handlePointerDown,
1391
+ handleDoubleClick,
1392
+ separatorProps
1393
+ } = useResizablePanel2({
1394
+ defaultWidth: resize.defaultWidth,
1395
+ minWidth: resize.minWidth,
1396
+ maxWidth: resize.maxWidth,
1397
+ direction: "left-edge"
1398
+ });
1399
+ return /* @__PURE__ */ jsxs9(
1400
+ SheetContent,
1401
+ {
1402
+ ...sheetProps,
1403
+ className: "max-w-[90vw]",
1404
+ style: { width: dynWidth },
1405
+ children: [
1406
+ /* @__PURE__ */ jsx13(
1407
+ DragHandle,
1408
+ {
1409
+ edge: "left",
1410
+ separatorProps,
1411
+ onPointerDown: handlePointerDown,
1412
+ onDoubleClick: handleDoubleClick
1413
+ }
1414
+ ),
1415
+ children
1416
+ ]
1222
1417
  }
1223
1418
  );
1224
1419
  }
@@ -1228,24 +1423,24 @@ function ShellBody({
1228
1423
  sidebar
1229
1424
  }) {
1230
1425
  return /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 overflow-hidden", children: [
1231
- sidebar ?? /* @__PURE__ */ jsx11(ShellRail, {}),
1232
- /* @__PURE__ */ jsx11(SidePane, {}),
1233
- sidePaneFullWidth !== true && /* @__PURE__ */ jsx11("div", { className: "flex-1 min-w-0 h-full overflow-hidden", children: /* @__PURE__ */ jsx11(ContentArea, { layout: activeService?.layout }) })
1426
+ sidebar ?? /* @__PURE__ */ jsx13(ShellRail, {}),
1427
+ /* @__PURE__ */ jsx13(SidePane, {}),
1428
+ sidePaneFullWidth !== true && /* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0 h-full overflow-hidden", children: /* @__PURE__ */ jsx13(ContentArea, { layout: activeService?.layout }) })
1234
1429
  ] });
1235
1430
  }
1236
1431
  function ContentArea({ layout }) {
1237
1432
  if (layout === "full") {
1238
- return /* @__PURE__ */ jsx11("div", { className: "h-full w-full overflow-hidden", children: /* @__PURE__ */ jsx11(Outlet, {}) });
1433
+ return /* @__PURE__ */ jsx13("div", { className: "h-full w-full overflow-hidden", children: /* @__PURE__ */ jsx13(Outlet, {}) });
1239
1434
  }
1240
- return /* @__PURE__ */ jsx11(ScrollArea2, { className: "h-full", children: /* @__PURE__ */ jsx11("main", { className: "p-6", children: /* @__PURE__ */ jsx11(Outlet, {}) }) });
1435
+ return /* @__PURE__ */ jsx13(ScrollArea2, { className: "h-full", children: /* @__PURE__ */ jsx13("main", { className: "p-6", children: /* @__PURE__ */ jsx13(Outlet, {}) }) });
1241
1436
  }
1242
1437
  function PanelContent({ state }) {
1243
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
1438
+ return /* @__PURE__ */ jsxs9(Fragment4, { children: [
1244
1439
  state.title ? /* @__PURE__ */ jsxs9(SheetHeader, { children: [
1245
- /* @__PURE__ */ jsx11(SheetTitle, { children: state.title }),
1246
- state.description && /* @__PURE__ */ jsx11(SheetDescription, { children: state.description })
1247
- ] }) : /* @__PURE__ */ jsx11(SheetTitle, { className: "sr-only", children: "Panel" }),
1248
- /* @__PURE__ */ jsx11(SheetBody, { children: state.content })
1440
+ /* @__PURE__ */ jsx13(SheetTitle, { children: state.title }),
1441
+ state.description && /* @__PURE__ */ jsx13(SheetDescription, { children: state.description })
1442
+ ] }) : /* @__PURE__ */ jsx13(SheetTitle, { className: "sr-only", children: "Panel" }),
1443
+ /* @__PURE__ */ jsx13(SheetBody, { children: state.content })
1249
1444
  ] });
1250
1445
  }
1251
1446
 
@@ -1253,36 +1448,36 @@ function PanelContent({ state }) {
1253
1448
  import { Toaster } from "sonner";
1254
1449
 
1255
1450
  // src/ShellConfigProvider.tsx
1256
- import { jsx as jsx12 } from "react/jsx-runtime";
1451
+ import { jsx as jsx14 } from "react/jsx-runtime";
1257
1452
  function ShellConfigProvider({
1258
1453
  config,
1259
1454
  children
1260
1455
  }) {
1261
- return /* @__PURE__ */ jsx12(ShellConfigContext.Provider, { value: config, children });
1456
+ return /* @__PURE__ */ jsx14(ShellConfigContext.Provider, { value: config, children });
1262
1457
  }
1263
1458
 
1264
1459
  // src/RootLayout.tsx
1265
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1460
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1266
1461
  function RootLayout({
1267
1462
  config,
1268
1463
  registry,
1269
1464
  sidebar
1270
1465
  }) {
1271
1466
  return /* @__PURE__ */ jsxs10(ShellConfigProvider, { config, children: [
1272
- /* @__PURE__ */ jsx13(Toaster, { position: "top-right", richColors: true, closeButton: true }),
1273
- /* @__PURE__ */ jsx13(AppShell, { registry, sidebar })
1467
+ /* @__PURE__ */ jsx15(Toaster, { position: "top-right", richColors: true, closeButton: true }),
1468
+ /* @__PURE__ */ jsx15(AppShell, { registry, sidebar })
1274
1469
  ] });
1275
1470
  }
1276
1471
 
1277
1472
  // src/PlaceholderPage.tsx
1278
1473
  import { useLocation as useLocation3 } from "react-router-dom";
1279
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1474
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1280
1475
  function PlaceholderPage() {
1281
1476
  const { pathname } = useLocation3();
1282
1477
  return /* @__PURE__ */ jsxs11("div", { children: [
1283
- /* @__PURE__ */ jsx14("h1", { className: "mb-1", children: pathToTitle(pathname) }),
1284
- /* @__PURE__ */ jsx14("p", { className: "text-sm text-muted-foreground mb-6", children: pathname }),
1285
- /* @__PURE__ */ jsx14("div", { className: "rounded-lg border-2 border-dashed border-border p-12 flex items-center justify-center", children: /* @__PURE__ */ jsx14("span", { className: "text-sm text-muted-foreground", children: "Content area \u2014 not yet implemented" }) })
1478
+ /* @__PURE__ */ jsx16("h1", { className: "mb-1", children: pathToTitle(pathname) }),
1479
+ /* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground mb-6", children: pathname }),
1480
+ /* @__PURE__ */ jsx16("div", { className: "rounded-lg border-2 border-dashed border-border p-12 flex items-center justify-center", children: /* @__PURE__ */ jsx16("span", { className: "text-sm text-muted-foreground", children: "Content area \u2014 not yet implemented" }) })
1286
1481
  ] });
1287
1482
  }
1288
1483
  function pathToTitle(path) {
@@ -1292,9 +1487,9 @@ function pathToTitle(path) {
1292
1487
  }
1293
1488
 
1294
1489
  // src/Sidebar.tsx
1295
- import { cn as cn5 } from "@petrarca/sonnet-core";
1490
+ import { cn as cn6 } from "@petrarca/sonnet-core";
1296
1491
  import { ScrollArea as ScrollArea3 } from "@petrarca/sonnet-ui";
1297
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1492
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1298
1493
  function Sidebar({
1299
1494
  children,
1300
1495
  header,
@@ -1305,20 +1500,20 @@ function Sidebar({
1305
1500
  "aside",
1306
1501
  {
1307
1502
  style: { width },
1308
- className: cn5(
1503
+ className: cn6(
1309
1504
  "shrink-0 border-r bg-muted/30 flex flex-col h-full",
1310
1505
  className
1311
1506
  ),
1312
1507
  children: [
1313
1508
  header,
1314
- /* @__PURE__ */ jsx15(ScrollArea3, { className: "flex-1", children: /* @__PURE__ */ jsx15("nav", { className: "px-1.5 py-2 space-y-3", children }) })
1509
+ /* @__PURE__ */ jsx17(ScrollArea3, { className: "flex-1", children: /* @__PURE__ */ jsx17("nav", { className: "px-1.5 py-2 space-y-3", children }) })
1315
1510
  ]
1316
1511
  }
1317
1512
  );
1318
1513
  }
1319
1514
 
1320
1515
  // src/ShellSidebar.tsx
1321
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1516
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
1322
1517
  function ShellSidebar({
1323
1518
  bottomGroupLabel = "Tools",
1324
1519
  ...sidebarProps
@@ -1328,7 +1523,7 @@ function ShellSidebar({
1328
1523
  (mod) => (mod.topNav ?? []).map((link) => ({ link, icon: mod.icon }))
1329
1524
  );
1330
1525
  return /* @__PURE__ */ jsxs13(Sidebar, { ...sidebarProps, children: [
1331
- topNavItems.length > 0 && /* @__PURE__ */ jsx16(SidebarGroup, { separator: true, children: topNavItems.map(({ link, icon }) => /* @__PURE__ */ jsx16(
1526
+ topNavItems.length > 0 && /* @__PURE__ */ jsx18(SidebarGroup, { separator: true, children: topNavItems.map(({ link, icon }) => /* @__PURE__ */ jsx18(
1332
1527
  SidebarItem,
1333
1528
  {
1334
1529
  icon,
@@ -1340,7 +1535,7 @@ function ShellSidebar({
1340
1535
  )) }),
1341
1536
  mainModules.map((mod) => {
1342
1537
  if (mod.navigation.length === 0) {
1343
- return /* @__PURE__ */ jsx16(
1538
+ return /* @__PURE__ */ jsx18(
1344
1539
  SidebarItem,
1345
1540
  {
1346
1541
  icon: mod.icon,
@@ -1350,15 +1545,15 @@ function ShellSidebar({
1350
1545
  mod.id
1351
1546
  );
1352
1547
  }
1353
- return /* @__PURE__ */ jsx16(SidebarGroup, { heading: mod.label, collapsible: true, children: mod.navigation.flatMap((group) => [
1548
+ return /* @__PURE__ */ jsx18(SidebarGroup, { heading: mod.label, collapsible: true, children: mod.navigation.flatMap((group) => [
1354
1549
  // Render NavGroup heading if it has one
1355
1550
  ...group.heading ? [
1356
- /* @__PURE__ */ jsx16(
1551
+ /* @__PURE__ */ jsx18(
1357
1552
  SidebarGroup,
1358
1553
  {
1359
1554
  heading: group.heading,
1360
1555
  collapsible: group.collapsible,
1361
- children: group.links.map((link) => /* @__PURE__ */ jsx16(
1556
+ children: group.links.map((link) => /* @__PURE__ */ jsx18(
1362
1557
  SidebarItem,
1363
1558
  {
1364
1559
  icon: mod.icon,
@@ -1371,7 +1566,7 @@ function ShellSidebar({
1371
1566
  },
1372
1567
  group.id
1373
1568
  )
1374
- ] : group.links.map((link) => /* @__PURE__ */ jsx16(
1569
+ ] : group.links.map((link) => /* @__PURE__ */ jsx18(
1375
1570
  SidebarItem,
1376
1571
  {
1377
1572
  icon: mod.icon,
@@ -1383,7 +1578,7 @@ function ShellSidebar({
1383
1578
  ))
1384
1579
  ]) }, mod.id);
1385
1580
  }),
1386
- bottomModules.length > 0 && /* @__PURE__ */ jsx16(SidebarGroup, { heading: bottomGroupLabel, collapsible: true, children: bottomModules.map((mod) => /* @__PURE__ */ jsx16(
1581
+ bottomModules.length > 0 && /* @__PURE__ */ jsx18(SidebarGroup, { heading: bottomGroupLabel, collapsible: true, children: bottomModules.map((mod) => /* @__PURE__ */ jsx18(
1387
1582
  SidebarItem,
1388
1583
  {
1389
1584
  icon: mod.icon,
@@ -1396,13 +1591,13 @@ function ShellSidebar({
1396
1591
  }
1397
1592
 
1398
1593
  // src/ShellVersion.tsx
1399
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1594
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1400
1595
  function ShellVersion({
1401
1596
  name,
1402
1597
  version
1403
1598
  }) {
1404
1599
  return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
1405
- /* @__PURE__ */ jsx17("span", { children: name }),
1600
+ /* @__PURE__ */ jsx19("span", { children: name }),
1406
1601
  version && /* @__PURE__ */ jsxs14("span", { className: "text-muted-foreground/50", children: [
1407
1602
  "v",
1408
1603
  version
@@ -1413,7 +1608,7 @@ function ShellVersion({
1413
1608
  // src/SearchTrigger.tsx
1414
1609
  import { Search } from "lucide-react";
1415
1610
  import { Button as Button3 } from "@petrarca/sonnet-ui";
1416
- import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1611
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1417
1612
  function SearchTrigger() {
1418
1613
  return /* @__PURE__ */ jsxs15(
1419
1614
  Button3,
@@ -1423,10 +1618,10 @@ function SearchTrigger() {
1423
1618
  className: "h-8 gap-2 text-sm text-muted-foreground w-56 justify-start",
1424
1619
  onClick: () => navigation.openCommandMenu(),
1425
1620
  children: [
1426
- /* @__PURE__ */ jsx18(Search, { className: "h-4 w-4" }),
1427
- /* @__PURE__ */ jsx18("span", { children: "Search..." }),
1621
+ /* @__PURE__ */ jsx20(Search, { className: "h-4 w-4" }),
1622
+ /* @__PURE__ */ jsx20("span", { children: "Search..." }),
1428
1623
  /* @__PURE__ */ jsxs15("kbd", { className: "ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground", children: [
1429
- /* @__PURE__ */ jsx18("span", { className: "text-xs", children: "\u2318" }),
1624
+ /* @__PURE__ */ jsx20("span", { className: "text-xs", children: "\u2318" }),
1430
1625
  "K"
1431
1626
  ] })
1432
1627
  ]
@@ -1446,23 +1641,23 @@ import {
1446
1641
  DropdownMenuSeparator,
1447
1642
  DropdownMenuTrigger
1448
1643
  } from "@petrarca/sonnet-ui";
1449
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1644
+ import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
1450
1645
  function UserMenu({ user, onSignOut }) {
1451
1646
  return /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
1452
- /* @__PURE__ */ jsx19(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx19(Button4, { variant: "ghost", size: "compact", className: "rounded-full", children: /* @__PURE__ */ jsx19(Avatar, { className: "h-7 w-7", children: /* @__PURE__ */ jsx19(AvatarFallback, { className: "text-xs", children: user.initials }) }) }) }),
1647
+ /* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(Button4, { variant: "ghost", size: "compact", className: "rounded-full", children: /* @__PURE__ */ jsx21(Avatar, { className: "h-7 w-7", children: /* @__PURE__ */ jsx21(AvatarFallback, { className: "text-xs", children: user.initials }) }) }) }),
1453
1648
  /* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", className: "w-48", children: [
1454
- /* @__PURE__ */ jsx19(DropdownMenuLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1", children: [
1455
- /* @__PURE__ */ jsx19("p", { className: "text-sm font-medium", children: user.name }),
1456
- /* @__PURE__ */ jsx19("p", { className: "text-xs text-muted-foreground", children: user.email })
1649
+ /* @__PURE__ */ jsx21(DropdownMenuLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1", children: [
1650
+ /* @__PURE__ */ jsx21("p", { className: "text-sm font-medium", children: user.name }),
1651
+ /* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground", children: user.email })
1457
1652
  ] }) }),
1458
- /* @__PURE__ */ jsx19(DropdownMenuSeparator, {}),
1653
+ /* @__PURE__ */ jsx21(DropdownMenuSeparator, {}),
1459
1654
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { children: [
1460
- /* @__PURE__ */ jsx19(User, { className: "mr-2 h-4 w-4" }),
1655
+ /* @__PURE__ */ jsx21(User, { className: "mr-2 h-4 w-4" }),
1461
1656
  "Profile"
1462
1657
  ] }),
1463
- /* @__PURE__ */ jsx19(DropdownMenuSeparator, {}),
1658
+ /* @__PURE__ */ jsx21(DropdownMenuSeparator, {}),
1464
1659
  /* @__PURE__ */ jsxs16(DropdownMenuItem, { onSelect: onSignOut, children: [
1465
- /* @__PURE__ */ jsx19(LogOut, { className: "mr-2 h-4 w-4" }),
1660
+ /* @__PURE__ */ jsx21(LogOut, { className: "mr-2 h-4 w-4" }),
1466
1661
  "Sign out"
1467
1662
  ] })
1468
1663
  ] })
@@ -1493,13 +1688,13 @@ function createModuleRegistry(modules) {
1493
1688
  }
1494
1689
 
1495
1690
  // src/OverviewCard.tsx
1496
- import { cn as cn6 } from "@petrarca/sonnet-core";
1497
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
1691
+ import { cn as cn7 } from "@petrarca/sonnet-core";
1692
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
1498
1693
  function FeatureLink({
1499
1694
  feature,
1500
1695
  children
1501
1696
  }) {
1502
- return /* @__PURE__ */ jsx20(
1697
+ return /* @__PURE__ */ jsx22(
1503
1698
  "span",
1504
1699
  {
1505
1700
  role: "link",
@@ -1532,17 +1727,17 @@ function OverviewCard({
1532
1727
  {
1533
1728
  onClick: feature ? () => navigation.goToFeature(feature) : void 0,
1534
1729
  disabled: !feature,
1535
- className: cn6(
1730
+ className: cn7(
1536
1731
  "rounded-lg border bg-card p-5 text-left flex flex-col gap-3",
1537
1732
  "disabled:cursor-default",
1538
1733
  feature && "hover:bg-accent/50 transition-colors",
1539
1734
  className
1540
1735
  ),
1541
1736
  children: [
1542
- /* @__PURE__ */ jsx20("div", { className: "h-9 w-9 rounded-md bg-blue-50 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx20(Icon, { className: "h-5 w-5 text-blue-600" }) }),
1737
+ /* @__PURE__ */ jsx22("div", { className: "h-9 w-9 rounded-md bg-blue-50 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx22(Icon, { className: "h-5 w-5 text-blue-600" }) }),
1543
1738
  /* @__PURE__ */ jsxs17("div", { children: [
1544
- /* @__PURE__ */ jsx20("p", { className: "text-sm font-medium mb-1", children: title }),
1545
- /* @__PURE__ */ jsx20("p", { className: "text-xs text-muted-foreground leading-relaxed", children: description })
1739
+ /* @__PURE__ */ jsx22("p", { className: "text-sm font-medium mb-1", children: title }),
1740
+ /* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground leading-relaxed", children: description })
1546
1741
  ] })
1547
1742
  ]
1548
1743
  }
@@ -1552,6 +1747,7 @@ export {
1552
1747
  AppShell,
1553
1748
  CommandMenu,
1554
1749
  ConfirmDialog,
1750
+ DEFAULT_CAPABILITY_POLICY,
1555
1751
  FeatureLink,
1556
1752
  IconRail,
1557
1753
  OverviewCard,
@@ -1575,6 +1771,7 @@ export {
1575
1771
  UserMenu,
1576
1772
  createModuleRegistry,
1577
1773
  dialog,
1774
+ evaluateModule,
1578
1775
  events,
1579
1776
  fullscreen,
1580
1777
  initDialog,
@@ -1586,6 +1783,7 @@ export {
1586
1783
  navigation,
1587
1784
  notification,
1588
1785
  panel,
1786
+ resolveCapabilityPolicy,
1589
1787
  sidePane,
1590
1788
  useExtensionPoint,
1591
1789
  useMainModules,