@ai-matrx/associations 0.5.2 → 0.6.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.
@@ -1,13 +1,191 @@
1
1
  "use client";
2
2
 
3
3
  // src/react/context.tsx
4
- import { createContext, useContext, useRef } from "react";
4
+ import {
5
+ createContext,
6
+ useContext,
7
+ useEffect,
8
+ useRef
9
+ } from "react";
10
+
11
+ // src/demanded-rpcs.generated.ts
12
+ var DEMANDED_RPC_NAMES = [
13
+ "assoc_add",
14
+ "assoc_remove",
15
+ "assoc_set_targets",
16
+ "assoc_remove_for_entity",
17
+ "assoc_for_entity",
18
+ "assoc_for_targets",
19
+ "assoc_for_sources",
20
+ "assoc_members_visible",
21
+ "conversation_file_add",
22
+ "conversation_file_remove",
23
+ "conversation_files",
24
+ "agent_resource_add",
25
+ "agent_resource_remove",
26
+ "cat_list",
27
+ "cat_create",
28
+ "cat_update",
29
+ "cat_reparent",
30
+ "cat_delete",
31
+ "ues_set",
32
+ "ues_list",
33
+ "ues_get_bulk",
34
+ "ues_touch",
35
+ "reference_search_candidates",
36
+ "cmt_list",
37
+ "cmt_add",
38
+ "cmt_edit",
39
+ "cmt_delete"
40
+ ];
41
+
42
+ // src/core/assertDemandedSchema.ts
43
+ var BAD_UUID = "__not_a_uuid__";
44
+ var SELF_TEST_MISSING_RPC = "assoc_probe_self_test_missing_fn";
45
+ var PROBE_ARGS = {
46
+ // edges — writes
47
+ assoc_add: {
48
+ p_source_type: "note",
49
+ p_source_id: BAD_UUID,
50
+ p_target_type: "task",
51
+ p_target_id: BAD_UUID
52
+ },
53
+ assoc_remove: {
54
+ p_source_type: "note",
55
+ p_source_id: BAD_UUID,
56
+ p_target_type: "task",
57
+ p_target_id: BAD_UUID
58
+ },
59
+ assoc_set_targets: {
60
+ p_source_type: "note",
61
+ p_source_id: BAD_UUID,
62
+ p_target_type: "task",
63
+ p_target_ids: [BAD_UUID]
64
+ },
65
+ assoc_remove_for_entity: { p_type: "note", p_id: BAD_UUID },
66
+ // edges — reads
67
+ assoc_for_entity: { p_type: "note", p_id: BAD_UUID },
68
+ assoc_for_targets: { p_target_type: "task", p_target_ids: [BAD_UUID] },
69
+ assoc_for_sources: { p_source_type: "note", p_source_ids: [BAD_UUID] },
70
+ assoc_members_visible: { p_target_type: "task", p_target_ids: [BAD_UUID] },
71
+ // conversation files
72
+ conversation_file_add: {
73
+ p_conversation_id: BAD_UUID,
74
+ p_file_id: BAD_UUID
75
+ },
76
+ conversation_file_remove: {
77
+ p_conversation_id: BAD_UUID,
78
+ p_file_id: BAD_UUID
79
+ },
80
+ conversation_files: { p_conversation_id: BAD_UUID },
81
+ // agent resources
82
+ agent_resource_add: {
83
+ p_agent_id: BAD_UUID,
84
+ p_source_type: "note",
85
+ p_source_id: BAD_UUID
86
+ },
87
+ agent_resource_remove: {
88
+ p_agent_id: BAD_UUID,
89
+ p_source_type: "note",
90
+ p_source_id: BAD_UUID
91
+ },
92
+ // categories
93
+ cat_list: {},
94
+ cat_create: { p_dimension: "", p_name: "", p_org_id: BAD_UUID },
95
+ cat_update: { p_category_id: BAD_UUID, p_name: "__probe__" },
96
+ cat_reparent: { p_category_id: BAD_UUID },
97
+ cat_delete: { p_category_id: BAD_UUID },
98
+ // favorites / recents
99
+ ues_set: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
100
+ ues_list: {},
101
+ ues_get_bulk: { p_entity_type: "__probe__", p_entity_ids: [BAD_UUID] },
102
+ ues_touch: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
103
+ // candidates
104
+ reference_search_candidates: { p_token: "__probe__", p_limit: 1 },
105
+ // comments (W6) — every fn takes a uuid arg, so the unparseable sentinel
106
+ // guarantees 22P02 before any SECURITY DEFINER body runs (no write occurs).
107
+ cmt_list: { p_entity_type: "__probe__", p_entity_id: BAD_UUID },
108
+ cmt_add: {
109
+ p_entity_type: "__probe__",
110
+ p_entity_id: BAD_UUID,
111
+ p_body: "__probe__"
112
+ },
113
+ cmt_edit: { p_id: BAD_UUID, p_body: "__probe__" },
114
+ cmt_delete: { p_id: BAD_UUID }
115
+ };
116
+ function isMissingFunctionError(error) {
117
+ if (!error || typeof error !== "object") return false;
118
+ return error.code === "PGRST202";
119
+ }
120
+ async function assertDemandedSchema(dataSource, options = {}) {
121
+ const { selfTest = false, concurrency = 6, throwOnViolation = true } = options;
122
+ const names = [...DEMANDED_RPC_NAMES];
123
+ if (selfTest) names.push(SELF_TEST_MISSING_RPC);
124
+ const missing = [];
125
+ const unreachable = [];
126
+ const answered = [];
127
+ let cursor = 0;
128
+ async function worker() {
129
+ while (cursor < names.length) {
130
+ const fn = names[cursor];
131
+ cursor += 1;
132
+ if (!fn) continue;
133
+ const args = fn === SELF_TEST_MISSING_RPC ? {} : PROBE_ARGS[fn];
134
+ try {
135
+ const { error } = await dataSource.rpc(fn, args);
136
+ if (error == null) answered.push(fn);
137
+ else if (isMissingFunctionError(error)) missing.push(fn);
138
+ else answered.push(fn);
139
+ } catch (e) {
140
+ unreachable.push({ fn, error: e });
141
+ }
142
+ }
143
+ }
144
+ await Promise.all(
145
+ Array.from({ length: Math.min(concurrency, names.length) }, worker)
146
+ );
147
+ if (selfTest) {
148
+ const selfTestMissing = missing.includes(SELF_TEST_MISSING_RPC);
149
+ const idx = missing.indexOf(SELF_TEST_MISSING_RPC);
150
+ if (idx >= 0) missing.splice(idx, 1);
151
+ const answeredIdx = answered.indexOf(SELF_TEST_MISSING_RPC);
152
+ if (answeredIdx >= 0) answered.splice(answeredIdx, 1);
153
+ if (!selfTestMissing) {
154
+ throw new Error(
155
+ `assertDemandedSchema self-test FAILED: the fabricated function "${SELF_TEST_MISSING_RPC}" did not come back as missing (PGRST202). This probe cannot currently fail, so its green result proves nothing \u2014 the dataSource is swallowing or faking errors.`
156
+ );
157
+ }
158
+ }
159
+ if (unreachable.length > 0) {
160
+ throw new Error(
161
+ `assertDemandedSchema could not complete: ${unreachable.length} probe call(s) failed to reach the database (${unreachable.map((u) => u.fn).join(", ")}). This is NOT a schema verdict \u2014 fix connectivity and re-run.`
162
+ );
163
+ }
164
+ const ok = missing.length === 0;
165
+ const report = { ok, missing, unreachable, answered };
166
+ if (!ok && throwOnViolation) {
167
+ throw new Error(
168
+ `DEMANDED SCHEMA VIOLATION: the database this dataSource points at cannot answer ${missing.length} demanded @ai-matrx/associations function(s): ${missing.join(", ")}. This package demands the AI Matrx platform schema (README \xA7 The demanded schema); a database without it is not this package's database.`
169
+ );
170
+ }
171
+ return report;
172
+ }
173
+
174
+ // src/react/context.tsx
5
175
  import { jsx } from "react/jsx-runtime";
6
176
  var AssociationsReactContext = createContext(
7
177
  null
8
178
  );
179
+ function isDevelopmentBuild() {
180
+ try {
181
+ return typeof process !== "undefined" && true;
182
+ } catch {
183
+ return false;
184
+ }
185
+ }
9
186
  function AssociationsProvider({
10
187
  store,
188
+ probeSchema,
11
189
  notifier,
12
190
  windowShell,
13
191
  capture,
@@ -17,6 +195,28 @@ function AssociationsProvider({
17
195
  children
18
196
  }) {
19
197
  const notifierWarned = useRef(false);
198
+ const shouldProbe = probeSchema ?? isDevelopmentBuild();
199
+ useEffect(() => {
200
+ if (!shouldProbe) return;
201
+ let stale = false;
202
+ void (async () => {
203
+ try {
204
+ await assertDemandedSchema(store.dataSource);
205
+ } catch (error) {
206
+ if (stale) return;
207
+ store.errorSink({
208
+ code: "demanded_schema_violation",
209
+ message: error instanceof Error ? error.message : "assertDemandedSchema failed",
210
+ context: {
211
+ remedy: "Run the platform.associations schema (README \xA7 The demanded schema) on the database this dataSource points at."
212
+ }
213
+ });
214
+ }
215
+ })();
216
+ return () => {
217
+ stale = true;
218
+ };
219
+ }, [shouldProbe, store]);
20
220
  return /* @__PURE__ */ jsx(
21
221
  AssociationsReactContext.Provider,
22
222
  {
@@ -78,7 +278,7 @@ function useNotifier() {
78
278
  }
79
279
 
80
280
  // src/react/hooks/useAssociations.ts
81
- import { useEffect, useRef as useRef2, useSyncExternalStore } from "react";
281
+ import { useEffect as useEffect2, useRef as useRef2, useSyncExternalStore } from "react";
82
282
 
83
283
  // src/results.ts
84
284
  function isAssociationsRpcErr(r) {
@@ -789,7 +989,7 @@ function useAssociations(args) {
789
989
  () => store.getEdges(type, id ?? "")
790
990
  );
791
991
  const loadedKey = useRef2(null);
792
- useEffect(() => {
992
+ useEffect2(() => {
793
993
  if (!autoLoad || !type || !id) return;
794
994
  const k = associationsKey(type, id);
795
995
  if (loadedKey.current === k) return;
@@ -845,7 +1045,7 @@ var useEntityRelationships = useAssociations;
845
1045
  // src/react/hooks/useContainerLinks.ts
846
1046
  import {
847
1047
  useCallback,
848
- useEffect as useEffect2,
1048
+ useEffect as useEffect3,
849
1049
  useLayoutEffect,
850
1050
  useRef as useRef3,
851
1051
  useState
@@ -910,7 +1110,7 @@ function useContainerLinks(args) {
910
1110
  loading: false
911
1111
  });
912
1112
  }, [containerId, conversationKey, store]);
913
- useEffect2(() => {
1113
+ useEffect3(() => {
914
1114
  const timeout = setTimeout(() => {
915
1115
  void loadConversationFiles();
916
1116
  }, 0);
@@ -993,7 +1193,7 @@ function useContainerLinks(args) {
993
1193
  }
994
1194
 
995
1195
  // src/react/hooks/useEntityTitles.ts
996
- import { useEffect as useEffect3, useState as useState2 } from "react";
1196
+ import { useEffect as useEffect4, useState as useState2 } from "react";
997
1197
  function useEntityTitles(refs) {
998
1198
  const store = useAssociationsStore();
999
1199
  const [resolved, setResolved] = useState2({});
@@ -1003,7 +1203,7 @@ function useEntityTitles(refs) {
1003
1203
  (r) => store.registry.tryGetEntityInfo(r.token)?.titleColumn != null && store.titles.get(r.token, r.id) == null && !attempted[entityTitleCacheKey(r.token, r.id)]
1004
1204
  );
1005
1205
  const neededKey = needed.map((r) => entityTitleCacheKey(r.token, r.id)).sort().join("|");
1006
- useEffect3(() => {
1206
+ useEffect4(() => {
1007
1207
  if (!neededKey) return;
1008
1208
  let cancelled = false;
1009
1209
  setLoading(true);
@@ -1067,7 +1267,7 @@ function useEntityTitles(refs) {
1067
1267
  }
1068
1268
 
1069
1269
  // src/react/hooks/useCategories.ts
1070
- import { useEffect as useEffect4, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
1270
+ import { useEffect as useEffect5, useRef as useRef4, useSyncExternalStore as useSyncExternalStore2 } from "react";
1071
1271
  var noopSubscribe2 = () => () => {
1072
1272
  };
1073
1273
  function useCategories(args) {
@@ -1079,7 +1279,7 @@ function useCategories(args) {
1079
1279
  () => store.getCategories(dimension ?? "")
1080
1280
  );
1081
1281
  const loadedKey = useRef4(null);
1082
- useEffect4(() => {
1282
+ useEffect5(() => {
1083
1283
  if (!autoLoad || !dimension) return;
1084
1284
  if (loadedKey.current === dimension) return;
1085
1285
  loadedKey.current = dimension;
@@ -1130,7 +1330,7 @@ function useCategories(args) {
1130
1330
  }
1131
1331
 
1132
1332
  // src/react/hooks/useUniversalEntitySearch.ts
1133
- import { useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
1333
+ import { useEffect as useEffect6, useRef as useRef5, useState as useState3 } from "react";
1134
1334
  var DEBOUNCE_MS = 250;
1135
1335
  var RECENTS_LIMIT = 12;
1136
1336
  function useUniversalEntitySearch(args) {
@@ -1148,7 +1348,7 @@ function useUniversalEntitySearch(args) {
1148
1348
  const [isRecents, setIsRecents] = useState3(true);
1149
1349
  const runRef = useRef5(0);
1150
1350
  const tokensKey = (tokens ?? []).join(",");
1151
- useEffect5(() => {
1351
+ useEffect6(() => {
1152
1352
  if (!enabled) return;
1153
1353
  const run = ++runRef.current;
1154
1354
  const trimmed = query.trim();
@@ -1210,7 +1410,7 @@ async function loadRecents(store, tokens) {
1210
1410
  }
1211
1411
 
1212
1412
  // src/react/hooks/useAssociationCandidates.ts
1213
- import { useEffect as useEffect6, useState as useState4 } from "react";
1413
+ import { useEffect as useEffect7, useState as useState4 } from "react";
1214
1414
  function useAssociationCandidates(args) {
1215
1415
  const { token, enabled = true, search, limit } = args;
1216
1416
  const store = useAssociationsStore();
@@ -1219,7 +1419,7 @@ function useAssociationCandidates(args) {
1219
1419
  const [loading, setLoading] = useState4(false);
1220
1420
  const [error, setError] = useState4(null);
1221
1421
  const [tick, setTick] = useState4(0);
1222
- useEffect6(() => {
1422
+ useEffect7(() => {
1223
1423
  if (!enabled) return void 0;
1224
1424
  let cancelled = false;
1225
1425
  void (async () => {
@@ -1260,7 +1460,7 @@ function currentUserIdOrNull(store) {
1260
1460
  }
1261
1461
 
1262
1462
  // src/react/hooks/useComments.ts
1263
- import { useEffect as useEffect7, useRef as useRef6, useSyncExternalStore as useSyncExternalStore3 } from "react";
1463
+ import { useEffect as useEffect8, useRef as useRef6, useSyncExternalStore as useSyncExternalStore3 } from "react";
1264
1464
  var noopSubscribe3 = () => () => {
1265
1465
  };
1266
1466
  function useComments(args) {
@@ -1273,7 +1473,7 @@ function useComments(args) {
1273
1473
  () => store.getComments(token, id ?? "")
1274
1474
  );
1275
1475
  const loadedKey = useRef6(null);
1276
- useEffect7(() => {
1476
+ useEffect8(() => {
1277
1477
  if (!autoLoad || !key || !id) return;
1278
1478
  if (loadedKey.current === key) return;
1279
1479
  loadedKey.current = key;
@@ -1415,6 +1615,16 @@ function usePrimaryEntity() {
1415
1615
 
1416
1616
  // src/react/components/AssociationWindow.tsx
1417
1617
  import { useId } from "react";
1618
+
1619
+ // src/react/components/DefaultWindowShell.tsx
1620
+ import {
1621
+ useCallback as useCallback2,
1622
+ useEffect as useEffect9,
1623
+ useLayoutEffect as useLayoutEffect2,
1624
+ useRef as useRef7,
1625
+ useState as useState6
1626
+ } from "react";
1627
+ import { createPortal } from "react-dom";
1418
1628
  import { cn } from "@ai-matrx/design-system";
1419
1629
 
1420
1630
  // src/react/icons.tsx
@@ -1533,9 +1743,246 @@ function DefaultEntityIcon(props) {
1533
1743
  /* @__PURE__ */ jsx3("path", { d: "M12 13.5V8" })
1534
1744
  ] });
1535
1745
  }
1746
+ function MaximizeIcon(props) {
1747
+ return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
1748
+ /* @__PURE__ */ jsx3("path", { d: "M15 3h6v6" }),
1749
+ /* @__PURE__ */ jsx3("path", { d: "M9 21H3v-6" }),
1750
+ /* @__PURE__ */ jsx3("path", { d: "M21 3l-7 7" }),
1751
+ /* @__PURE__ */ jsx3("path", { d: "M3 21l7-7" })
1752
+ ] });
1753
+ }
1754
+ function RestoreIcon(props) {
1755
+ return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
1756
+ /* @__PURE__ */ jsx3("path", { d: "M4 14h6v6" }),
1757
+ /* @__PURE__ */ jsx3("path", { d: "M20 10h-6V4" }),
1758
+ /* @__PURE__ */ jsx3("path", { d: "M14 10l7-7" }),
1759
+ /* @__PURE__ */ jsx3("path", { d: "M3 21l7-7" })
1760
+ ] });
1761
+ }
1762
+ function GripResizeIcon(props) {
1763
+ return /* @__PURE__ */ jsxs("svg", { ...base(props), children: [
1764
+ /* @__PURE__ */ jsx3("path", { d: "M21 15 15 21" }),
1765
+ /* @__PURE__ */ jsx3("path", { d: "M21 20 20 21" })
1766
+ ] });
1767
+ }
1536
1768
 
1537
- // src/react/components/AssociationWindow.tsx
1769
+ // src/react/components/DefaultWindowShell.tsx
1538
1770
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1771
+ var DEFAULT_WIDTH = 440;
1772
+ var DEFAULT_HEIGHT = 580;
1773
+ var MIN_WIDTH = 330;
1774
+ var MIN_HEIGHT = 380;
1775
+ var MOBILE_MAX_WIDTH = 640;
1776
+ var EDGE_KEEP = 48;
1777
+ function viewport() {
1778
+ if (typeof window === "undefined") {
1779
+ return { width: DEFAULT_WIDTH, height: DEFAULT_HEIGHT };
1780
+ }
1781
+ return { width: window.innerWidth, height: window.innerHeight };
1782
+ }
1783
+ function clamp(rect) {
1784
+ const { width: vw, height: vh } = viewport();
1785
+ const width = Math.min(Math.max(rect.width, MIN_WIDTH), Math.max(vw, MIN_WIDTH));
1786
+ const height = Math.min(
1787
+ Math.max(rect.height, MIN_HEIGHT),
1788
+ Math.max(vh, MIN_HEIGHT)
1789
+ );
1790
+ return {
1791
+ width,
1792
+ height,
1793
+ x: Math.min(Math.max(rect.x, EDGE_KEEP - width), Math.max(vw - EDGE_KEEP, 0)),
1794
+ y: Math.min(Math.max(rect.y, 0), Math.max(vh - EDGE_KEEP, 0))
1795
+ };
1796
+ }
1797
+ function centred() {
1798
+ const { width: vw, height: vh } = viewport();
1799
+ const width = Math.min(DEFAULT_WIDTH, Math.max(vw - 32, MIN_WIDTH));
1800
+ const height = Math.min(DEFAULT_HEIGHT, Math.max(vh - 32, MIN_HEIGHT));
1801
+ return clamp({
1802
+ width,
1803
+ height,
1804
+ x: Math.round((vw - width) / 2),
1805
+ y: Math.round((vh - height) / 2)
1806
+ });
1807
+ }
1808
+ function DefaultWindowShell({
1809
+ id,
1810
+ title,
1811
+ onClose,
1812
+ icon,
1813
+ children,
1814
+ className
1815
+ }) {
1816
+ const panelRef = useRef7(null);
1817
+ const [mounted, setMounted] = useState6(false);
1818
+ const [isMobile, setIsMobile] = useState6(false);
1819
+ const [rect, setRect] = useState6(() => centred());
1820
+ const [maximized, setMaximized] = useState6(false);
1821
+ const gesture = useRef7(null);
1822
+ useLayoutEffect2(() => {
1823
+ setMounted(true);
1824
+ setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
1825
+ setRect(centred());
1826
+ }, []);
1827
+ useEffect9(() => {
1828
+ if (!mounted) return;
1829
+ const onResize = () => {
1830
+ setIsMobile(window.innerWidth < MOBILE_MAX_WIDTH);
1831
+ setRect((current) => clamp(current));
1832
+ };
1833
+ window.addEventListener("resize", onResize);
1834
+ return () => window.removeEventListener("resize", onResize);
1835
+ }, [mounted]);
1836
+ useEffect9(() => {
1837
+ const onKeyDown = (event) => {
1838
+ if (event.key === "Escape") onClose();
1839
+ };
1840
+ window.addEventListener("keydown", onKeyDown);
1841
+ return () => window.removeEventListener("keydown", onKeyDown);
1842
+ }, [onClose]);
1843
+ useEffect9(() => {
1844
+ panelRef.current?.focus({ preventScroll: true });
1845
+ }, [mounted]);
1846
+ const beginGesture = useCallback2(
1847
+ (mode) => (event) => {
1848
+ if (isMobile || maximized || event.button !== 0) return;
1849
+ event.preventDefault();
1850
+ event.currentTarget.setPointerCapture(event.pointerId);
1851
+ gesture.current = {
1852
+ mode,
1853
+ pointerId: event.pointerId,
1854
+ startX: event.clientX,
1855
+ startY: event.clientY,
1856
+ origin: rect
1857
+ };
1858
+ },
1859
+ [isMobile, maximized, rect]
1860
+ );
1861
+ const onPointerMove = useCallback2((event) => {
1862
+ const active = gesture.current;
1863
+ if (!active || active.pointerId !== event.pointerId) return;
1864
+ const dx = event.clientX - active.startX;
1865
+ const dy = event.clientY - active.startY;
1866
+ setRect(
1867
+ clamp(
1868
+ active.mode === "move" ? { ...active.origin, x: active.origin.x + dx, y: active.origin.y + dy } : {
1869
+ ...active.origin,
1870
+ width: active.origin.width + dx,
1871
+ height: active.origin.height + dy
1872
+ }
1873
+ )
1874
+ );
1875
+ }, []);
1876
+ const endGesture = useCallback2((event) => {
1877
+ const active = gesture.current;
1878
+ if (!active || active.pointerId !== event.pointerId) return;
1879
+ gesture.current = null;
1880
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
1881
+ event.currentTarget.releasePointerCapture(event.pointerId);
1882
+ }
1883
+ }, []);
1884
+ if (!mounted || typeof document === "undefined") return null;
1885
+ const labelId = `assoc-window-title:${id}`;
1886
+ const style = isMobile ? {} : maximized ? { inset: "1rem", width: "auto", height: "auto" } : {
1887
+ left: rect.x,
1888
+ top: rect.y,
1889
+ width: rect.width,
1890
+ height: rect.height
1891
+ };
1892
+ return createPortal(
1893
+ /* @__PURE__ */ jsxs2(
1894
+ "div",
1895
+ {
1896
+ ref: panelRef,
1897
+ role: "dialog",
1898
+ "aria-labelledby": labelId,
1899
+ tabIndex: -1,
1900
+ style,
1901
+ className: cn(
1902
+ // Non-modal by design: no backdrop element exists, so the page
1903
+ // behind keeps every click. `pointer-events-auto` re-asserts our
1904
+ // own subtree in case a Radix surface left <body> inert.
1905
+ "pointer-events-auto fixed z-50 flex flex-col overflow-hidden border border-border bg-card text-card-foreground shadow-xl outline-none",
1906
+ isMobile ? "inset-x-0 bottom-0 max-h-[85dvh] rounded-t-xl" : "rounded-xl",
1907
+ className
1908
+ ),
1909
+ children: [
1910
+ /* @__PURE__ */ jsxs2(
1911
+ "header",
1912
+ {
1913
+ onPointerDown: beginGesture("move"),
1914
+ onPointerMove,
1915
+ onPointerUp: endGesture,
1916
+ onPointerCancel: endGesture,
1917
+ onDoubleClick: () => {
1918
+ if (!isMobile) setMaximized((v) => !v);
1919
+ },
1920
+ className: cn(
1921
+ "flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2 select-none",
1922
+ isMobile ? "" : "cursor-move touch-none"
1923
+ ),
1924
+ children: [
1925
+ /* @__PURE__ */ jsxs2(
1926
+ "span",
1927
+ {
1928
+ id: labelId,
1929
+ className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground",
1930
+ children: [
1931
+ icon,
1932
+ /* @__PURE__ */ jsx4("span", { className: "truncate", children: title })
1933
+ ]
1934
+ }
1935
+ ),
1936
+ /* @__PURE__ */ jsxs2("span", { className: "flex shrink-0 items-center gap-0.5", children: [
1937
+ isMobile ? null : /* @__PURE__ */ jsx4(
1938
+ "button",
1939
+ {
1940
+ type: "button",
1941
+ onPointerDown: (event) => event.stopPropagation(),
1942
+ onClick: () => setMaximized((v) => !v),
1943
+ "aria-label": maximized ? "Restore window" : "Maximize window",
1944
+ className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
1945
+ children: maximized ? /* @__PURE__ */ jsx4(RestoreIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx4(MaximizeIcon, { className: "h-3.5 w-3.5" })
1946
+ }
1947
+ ),
1948
+ /* @__PURE__ */ jsx4(
1949
+ "button",
1950
+ {
1951
+ type: "button",
1952
+ onPointerDown: (event) => event.stopPropagation(),
1953
+ onClick: onClose,
1954
+ "aria-label": "Close",
1955
+ className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
1956
+ children: /* @__PURE__ */ jsx4(XIcon, { className: "h-3.5 w-3.5" })
1957
+ }
1958
+ )
1959
+ ] })
1960
+ ]
1961
+ }
1962
+ ),
1963
+ /* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1 overflow-hidden", children }),
1964
+ isMobile || maximized ? null : /* @__PURE__ */ jsx4(
1965
+ "button",
1966
+ {
1967
+ type: "button",
1968
+ "aria-label": "Resize window",
1969
+ onPointerDown: beginGesture("resize"),
1970
+ onPointerMove,
1971
+ onPointerUp: endGesture,
1972
+ onPointerCancel: endGesture,
1973
+ className: "absolute bottom-0 right-0 flex h-4 w-4 cursor-nwse-resize touch-none items-center justify-center text-muted-foreground/60 hover:text-foreground",
1974
+ children: /* @__PURE__ */ jsx4(GripResizeIcon, { className: "h-3 w-3" })
1975
+ }
1976
+ )
1977
+ ]
1978
+ }
1979
+ ),
1980
+ document.body
1981
+ );
1982
+ }
1983
+
1984
+ // src/react/components/AssociationWindow.tsx
1985
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1539
1986
  function AssociationWindow({
1540
1987
  open,
1541
1988
  onClose,
@@ -1548,78 +1995,51 @@ function AssociationWindow({
1548
1995
  const instanceId = useId();
1549
1996
  const { windowShell } = useAssociationsUiPorts();
1550
1997
  if (!open) return null;
1551
- const body = /* @__PURE__ */ jsxs2("div", { className: "flex h-full min-h-0 flex-col gap-2 p-3", children: [
1552
- subtitle ? /* @__PURE__ */ jsx4("div", { className: "shrink-0 text-xs text-muted-foreground", children: subtitle }) : null,
1998
+ const body = /* @__PURE__ */ jsxs3("div", { className: "flex h-full min-h-0 flex-col gap-2 p-3", children: [
1999
+ subtitle ? /* @__PURE__ */ jsx5("div", { className: "shrink-0 text-xs text-muted-foreground", children: subtitle }) : null,
1553
2000
  children
1554
2001
  ] });
2002
+ const windowId = `association:${scopeId}:${instanceId}`;
1555
2003
  if (windowShell) {
1556
2004
  const HostWindow = windowShell.Window;
1557
- return /* @__PURE__ */ jsx4(
1558
- HostWindow,
1559
- {
1560
- id: `association:${scopeId}:${instanceId}`,
1561
- title,
1562
- onClose,
1563
- children: body
1564
- }
1565
- );
2005
+ return /* @__PURE__ */ jsx5(HostWindow, { id: windowId, title, onClose, children: body });
1566
2006
  }
1567
- return /* @__PURE__ */ jsxs2(
1568
- "div",
2007
+ return /* @__PURE__ */ jsx5(
2008
+ DefaultWindowShell,
1569
2009
  {
1570
- role: "dialog",
1571
- "aria-label": title,
1572
- className: cn(
1573
- "pointer-events-auto fixed left-1/2 top-1/2 z-50 flex max-h-[85dvh] w-[min(440px,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-border bg-card shadow-xl"
1574
- ),
1575
- style: { height: "min(580px, 85dvh)" },
1576
- children: [
1577
- /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border px-3 py-2", children: [
1578
- /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-1.5 text-sm font-medium text-foreground", children: [
1579
- icon,
1580
- /* @__PURE__ */ jsx4("span", { className: "truncate", children: title })
1581
- ] }),
1582
- /* @__PURE__ */ jsx4(
1583
- "button",
1584
- {
1585
- type: "button",
1586
- onClick: onClose,
1587
- "aria-label": "Close",
1588
- className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
1589
- children: /* @__PURE__ */ jsx4(XIcon, { className: "h-3.5 w-3.5" })
1590
- }
1591
- )
1592
- ] }),
1593
- /* @__PURE__ */ jsx4("div", { className: "min-h-0 flex-1", children: body })
1594
- ]
2010
+ id: windowId,
2011
+ title,
2012
+ onClose,
2013
+ ...icon !== void 0 ? { icon } : {},
2014
+ children: body
1595
2015
  }
1596
2016
  );
1597
2017
  }
1598
2018
 
1599
2019
  // src/react/components/AssociationPicker.tsx
1600
- import { useState as useState6 } from "react";
2020
+ import { useState as useState7 } from "react";
1601
2021
  import { cn as cn2, Input } from "@ai-matrx/design-system";
1602
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
2022
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1603
2023
  function AssociationPicker(props) {
1604
2024
  const store = useAssociationsStore();
1605
2025
  const { pickerOverrides } = useAssociationsUiPorts();
1606
2026
  const info = store.registry.getEntityInfo(props.token);
1607
2027
  const Icon = info.Icon ?? DefaultEntityIcon;
1608
2028
  const Override = pickerOverrides?.[props.token];
1609
- if (Override) return /* @__PURE__ */ jsx5(Override, { ...props });
2029
+ if (Override) return /* @__PURE__ */ jsx6(Override, { ...props });
1610
2030
  const title = `Add ${info.labelPlural}`;
1611
2031
  const subtitle = props.containerLabel ? `Attach to ${props.containerLabel}` : "Click an item to attach or detach it";
1612
2032
  if (!props.open) return null;
1613
- return /* @__PURE__ */ jsx5(
2033
+ return /* @__PURE__ */ jsx6(
1614
2034
  AssociationWindow,
1615
2035
  {
1616
2036
  open: props.open,
1617
2037
  onClose: () => props.onOpenChange(false),
1618
2038
  scopeId: `picker:${props.token}`,
1619
2039
  title,
1620
- icon: /* @__PURE__ */ jsx5(Icon, { className: "size-3.5 text-primary" }),
2040
+ icon: /* @__PURE__ */ jsx6(Icon, { className: "size-3.5 text-primary" }),
1621
2041
  subtitle,
1622
- children: /* @__PURE__ */ jsx5(
2042
+ children: /* @__PURE__ */ jsx6(
1623
2043
  AssociationCandidateBody,
1624
2044
  {
1625
2045
  token: props.token,
@@ -1644,7 +2064,7 @@ function AssociationCandidateBody({
1644
2064
  onClose
1645
2065
  }) {
1646
2066
  void onClose;
1647
- return /* @__PURE__ */ jsx5(
2067
+ return /* @__PURE__ */ jsx6(
1648
2068
  EntityCandidateList,
1649
2069
  {
1650
2070
  token,
@@ -1666,8 +2086,8 @@ function EntityCandidateList({
1666
2086
  }) {
1667
2087
  const store = useAssociationsStore();
1668
2088
  const notifier = useNotifier();
1669
- const [search, setSearch] = useState6("");
1670
- const [busyId, setBusyId] = useState6(null);
2089
+ const [search, setSearch] = useState7("");
2090
+ const [busyId, setBusyId] = useState7(null);
1671
2091
  const info = store.registry.getEntityInfo(token);
1672
2092
  const Icon = info.Icon ?? DefaultEntityIcon;
1673
2093
  const { candidates, loading, error, reload } = useAssociationCandidates({
@@ -1691,10 +2111,10 @@ function EntityCandidateList({
1691
2111
  setBusyId(null);
1692
2112
  }
1693
2113
  };
1694
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
1695
- /* @__PURE__ */ jsxs3("div", { className: "relative mb-2", children: [
1696
- /* @__PURE__ */ jsx5(SearchIcon, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
1697
- /* @__PURE__ */ jsx5(
2114
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
2115
+ /* @__PURE__ */ jsxs4("div", { className: "relative mb-2", children: [
2116
+ /* @__PURE__ */ jsx6(SearchIcon, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
2117
+ /* @__PURE__ */ jsx6(
1698
2118
  Input,
1699
2119
  {
1700
2120
  value: search,
@@ -1705,13 +2125,13 @@ function EntityCandidateList({
1705
2125
  }
1706
2126
  )
1707
2127
  ] }),
1708
- /* @__PURE__ */ jsx5("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: loading && candidates.length === 0 ? /* @__PURE__ */ jsxs3(ListMessage, { children: [
1709
- /* @__PURE__ */ jsx5(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
2128
+ /* @__PURE__ */ jsx6("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: loading && candidates.length === 0 ? /* @__PURE__ */ jsxs4(ListMessage, { children: [
2129
+ /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
1710
2130
  "Loading\u2026"
1711
- ] }) : error ? /* @__PURE__ */ jsxs3("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
1712
- /* @__PURE__ */ jsx5("p", { className: "font-medium", children: "Couldn\u2019t load items" }),
1713
- /* @__PURE__ */ jsx5("p", { className: "opacity-80", children: error }),
1714
- /* @__PURE__ */ jsx5(
2131
+ ] }) : error ? /* @__PURE__ */ jsxs4("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
2132
+ /* @__PURE__ */ jsx6("p", { className: "font-medium", children: "Couldn\u2019t load items" }),
2133
+ /* @__PURE__ */ jsx6("p", { className: "opacity-80", children: error }),
2134
+ /* @__PURE__ */ jsx6(
1715
2135
  "button",
1716
2136
  {
1717
2137
  type: "button",
@@ -1720,10 +2140,10 @@ function EntityCandidateList({
1720
2140
  children: "Retry"
1721
2141
  }
1722
2142
  )
1723
- ] }) : candidates.length === 0 ? /* @__PURE__ */ jsx5(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ jsx5("ul", { className: "space-y-0.5", children: candidates.map((c) => {
2143
+ ] }) : candidates.length === 0 ? /* @__PURE__ */ jsx6(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ jsx6("ul", { className: "space-y-0.5", children: candidates.map((c) => {
1724
2144
  const attached = attachedIds.has(c.id);
1725
2145
  const busy = busyId === c.id;
1726
- return /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsxs3(
2146
+ return /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsxs4(
1727
2147
  "button",
1728
2148
  {
1729
2149
  type: "button",
@@ -1735,23 +2155,23 @@ function EntityCandidateList({
1735
2155
  attached && "bg-accent/40"
1736
2156
  ),
1737
2157
  children: [
1738
- /* @__PURE__ */ jsx5(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
1739
- /* @__PURE__ */ jsx5("span", { className: "flex-1 min-w-0 truncate text-foreground", children: c.title }),
1740
- /* @__PURE__ */ jsx5(
2158
+ /* @__PURE__ */ jsx6(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2159
+ /* @__PURE__ */ jsx6("span", { className: "flex-1 min-w-0 truncate text-foreground", children: c.title }),
2160
+ /* @__PURE__ */ jsx6(
1741
2161
  "span",
1742
2162
  {
1743
2163
  className: cn2(
1744
2164
  "flex h-5 w-5 items-center justify-center rounded-full shrink-0",
1745
2165
  attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
1746
2166
  ),
1747
- children: busy ? /* @__PURE__ */ jsx5(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx5(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx5(PlusIcon, { className: "h-3 w-3" })
2167
+ children: busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx6(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx6(PlusIcon, { className: "h-3 w-3" })
1748
2168
  }
1749
2169
  )
1750
2170
  ]
1751
2171
  }
1752
2172
  ) }, c.id);
1753
2173
  }) }) }),
1754
- canCreate && /* @__PURE__ */ jsx5(
2174
+ canCreate && /* @__PURE__ */ jsx6(
1755
2175
  CreateAndAttachFooter,
1756
2176
  {
1757
2177
  token,
@@ -1773,9 +2193,9 @@ function CreateAndAttachFooter({
1773
2193
  const store = useAssociationsStore();
1774
2194
  const notifier = useNotifier();
1775
2195
  const info = store.registry.getEntityInfo(token);
1776
- const [editing, setEditing] = useState6(false);
1777
- const [name, setName] = useState6("");
1778
- const [busy, setBusy] = useState6(false);
2196
+ const [editing, setEditing] = useState7(false);
2197
+ const [name, setName] = useState7("");
2198
+ const [busy, setBusy] = useState7(false);
1779
2199
  const submit = async () => {
1780
2200
  const title = name.trim();
1781
2201
  if (!title || busy) return;
@@ -1810,7 +2230,7 @@ function CreateAndAttachFooter({
1810
2230
  }
1811
2231
  };
1812
2232
  if (!editing) {
1813
- return /* @__PURE__ */ jsxs3(
2233
+ return /* @__PURE__ */ jsxs4(
1814
2234
  "button",
1815
2235
  {
1816
2236
  type: "button",
@@ -1820,10 +2240,10 @@ function CreateAndAttachFooter({
1820
2240
  },
1821
2241
  className: "mt-2 flex min-h-11 w-full shrink-0 items-center justify-center gap-1.5 rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground md:min-h-0",
1822
2242
  children: [
1823
- /* @__PURE__ */ jsx5(PlusIcon, { className: "h-4 w-4" }),
2243
+ /* @__PURE__ */ jsx6(PlusIcon, { className: "h-4 w-4" }),
1824
2244
  "New ",
1825
2245
  info.label,
1826
- seed ? /* @__PURE__ */ jsxs3("span", { className: "max-w-40 truncate text-muted-foreground/70", children: [
2246
+ seed ? /* @__PURE__ */ jsxs4("span", { className: "max-w-40 truncate text-muted-foreground/70", children: [
1827
2247
  "\u201C",
1828
2248
  seed,
1829
2249
  "\u201D"
@@ -1832,8 +2252,8 @@ function CreateAndAttachFooter({
1832
2252
  }
1833
2253
  );
1834
2254
  }
1835
- return /* @__PURE__ */ jsxs3("div", { className: "mt-2 flex shrink-0 items-center gap-1.5", children: [
1836
- /* @__PURE__ */ jsx5(
2255
+ return /* @__PURE__ */ jsxs4("div", { className: "mt-2 flex shrink-0 items-center gap-1.5", children: [
2256
+ /* @__PURE__ */ jsx6(
1837
2257
  Input,
1838
2258
  {
1839
2259
  autoFocus: true,
@@ -1852,17 +2272,17 @@ function CreateAndAttachFooter({
1852
2272
  style: { fontSize: 16 }
1853
2273
  }
1854
2274
  ),
1855
- /* @__PURE__ */ jsx5(
2275
+ /* @__PURE__ */ jsx6(
1856
2276
  "button",
1857
2277
  {
1858
2278
  type: "button",
1859
2279
  disabled: busy || !name.trim(),
1860
2280
  onClick: () => void submit(),
1861
2281
  className: "flex h-11 items-center gap-1 rounded-md bg-primary px-2.5 text-sm font-medium text-primary-foreground transition-opacity disabled:opacity-50 md:h-8",
1862
- children: busy ? /* @__PURE__ */ jsx5(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : "Create"
2282
+ children: busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : "Create"
1863
2283
  }
1864
2284
  ),
1865
- /* @__PURE__ */ jsx5(
2285
+ /* @__PURE__ */ jsx6(
1866
2286
  "button",
1867
2287
  {
1868
2288
  type: "button",
@@ -1873,38 +2293,122 @@ function CreateAndAttachFooter({
1873
2293
  },
1874
2294
  title: "Cancel",
1875
2295
  className: "flex h-11 w-11 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 md:h-8 md:w-8",
1876
- children: /* @__PURE__ */ jsx5(XIcon, { className: "h-4 w-4" })
2296
+ children: /* @__PURE__ */ jsx6(XIcon, { className: "h-4 w-4" })
1877
2297
  }
1878
2298
  )
1879
2299
  ] });
1880
2300
  }
1881
2301
  function ListMessage({ children }) {
1882
- return /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children });
2302
+ return /* @__PURE__ */ jsx6("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children });
1883
2303
  }
1884
2304
 
1885
2305
  // src/react/components/UniversalAssociationPicker.tsx
1886
- import { useState as useState7 } from "react";
1887
- import { cn as cn3, Input as Input2 } from "@ai-matrx/design-system";
1888
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2306
+ import { useState as useState8 } from "react";
2307
+ import { cn as cn4, Input as Input2 } from "@ai-matrx/design-system";
2308
+
2309
+ // src/react/components/entityDoors.tsx
2310
+ import { cn as cn3 } from "@ai-matrx/design-system";
2311
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2312
+ function DoorRef(props) {
2313
+ const { onOpen, ...refProps } = props;
2314
+ const { entityDoors } = useAssociationsUiPorts();
2315
+ const store = useAssociationsStore();
2316
+ const HostRef = entityDoors?.EntityRef;
2317
+ if (HostRef) return /* @__PURE__ */ jsx7(HostRef, { ...refProps });
2318
+ const name = refProps.name ?? null;
2319
+ const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
2320
+ if (onOpen) {
2321
+ return /* @__PURE__ */ jsx7(
2322
+ "button",
2323
+ {
2324
+ type: "button",
2325
+ onClick: onOpen,
2326
+ className: cn3(
2327
+ "min-w-0 truncate text-left underline-offset-2 hover:underline",
2328
+ refProps.className
2329
+ ),
2330
+ children: name
2331
+ }
2332
+ );
2333
+ }
2334
+ if (href) {
2335
+ return /* @__PURE__ */ jsxs5(
2336
+ "a",
2337
+ {
2338
+ href,
2339
+ target: refProps.openInNewTab === false ? void 0 : "_blank",
2340
+ rel: "noopener noreferrer",
2341
+ className: cn3(
2342
+ "inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
2343
+ refProps.className
2344
+ ),
2345
+ children: [
2346
+ /* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: name }),
2347
+ /* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
2348
+ ]
2349
+ }
2350
+ );
2351
+ }
2352
+ return /* @__PURE__ */ jsx7("span", { className: cn3("min-w-0 truncate", refProps.className), children: name });
2353
+ }
2354
+ function UnresolvedRef({ token, id }) {
2355
+ const { entityDoors } = useAssociationsUiPorts();
2356
+ const HostUnresolved = entityDoors?.UnresolvedRef;
2357
+ if (HostUnresolved) return /* @__PURE__ */ jsx7(HostUnresolved, { token, id });
2358
+ return /* @__PURE__ */ jsx7(
2359
+ "span",
2360
+ {
2361
+ className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
2362
+ title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
2363
+ children: "Unavailable"
2364
+ }
2365
+ );
2366
+ }
2367
+ function DoorControlsSlot(props) {
2368
+ const { entityDoors } = useAssociationsUiPorts();
2369
+ const store = useAssociationsStore();
2370
+ const HostControls = entityDoors?.DoorControls;
2371
+ if (HostControls) return /* @__PURE__ */ jsx7(HostControls, { ...props });
2372
+ const href = store.registry.tryGetEntityInfo(props.token)?.hrefFor?.(props.id) ?? null;
2373
+ if (!href) return null;
2374
+ const label = props.name ? `Open ${props.name}` : `Open this ${props.token}`;
2375
+ return /* @__PURE__ */ jsx7(
2376
+ "a",
2377
+ {
2378
+ href,
2379
+ target: "_blank",
2380
+ rel: "noopener noreferrer",
2381
+ "aria-label": label,
2382
+ title: label,
2383
+ className: cn3(
2384
+ "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
2385
+ props.className
2386
+ ),
2387
+ children: /* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3" })
2388
+ }
2389
+ );
2390
+ }
2391
+
2392
+ // src/react/components/UniversalAssociationPicker.tsx
2393
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1889
2394
  function attachedKey(token, id) {
1890
2395
  return `${token}:${id}`;
1891
2396
  }
1892
2397
  function UniversalAssociationPicker(props) {
1893
2398
  const { attachedKeys, onAttach, onDetach, ownerId, orgId, className } = props;
1894
2399
  const store = useAssociationsStore();
1895
- const { entityDoors, pickerOverrides } = useAssociationsUiPorts();
2400
+ const { pickerOverrides } = useAssociationsUiPorts();
1896
2401
  const notifier = useNotifier();
1897
2402
  const tokens = props.tokens ?? store.registry.curatedTokens();
1898
- const [query, setQuery] = useState7("");
1899
- const [browseToken, setBrowseToken] = useState7(null);
1900
- const [busyKey, setBusyKey] = useState7(null);
2403
+ const [query, setQuery] = useState8("");
2404
+ const [browseToken, setBrowseToken] = useState8(null);
2405
+ const [busyKey, setBusyKey] = useState8(null);
1901
2406
  const { results, loading, isRecents } = useUniversalEntitySearch({
1902
2407
  query,
1903
2408
  tokens,
1904
2409
  ownerId: ownerId ?? null,
1905
2410
  enabled: browseToken === null
1906
2411
  });
1907
- const DoorControls = entityDoors?.DoorControls;
1908
2412
  const toggle = async (c) => {
1909
2413
  const key = attachedKey(c.token, c.id);
1910
2414
  if (busyKey) return;
@@ -1928,10 +2432,10 @@ function UniversalAssociationPicker(props) {
1928
2432
  groups.set(r.token, list);
1929
2433
  }
1930
2434
  const BrowseOverride = browseToken ? pickerOverrides?.[browseToken] : void 0;
1931
- return /* @__PURE__ */ jsxs4("div", { className: cn3("flex min-h-0 flex-1 flex-col gap-2", className), children: [
1932
- /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
1933
- /* @__PURE__ */ jsx6(SearchIcon, { className: "absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
1934
- /* @__PURE__ */ jsx6(
2435
+ return /* @__PURE__ */ jsxs6("div", { className: cn4("flex min-h-0 flex-1 flex-col gap-2", className), children: [
2436
+ /* @__PURE__ */ jsxs6("div", { className: "relative", children: [
2437
+ /* @__PURE__ */ jsx8(SearchIcon, { className: "absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
2438
+ /* @__PURE__ */ jsx8(
1935
2439
  Input2,
1936
2440
  {
1937
2441
  value: query,
@@ -1944,23 +2448,23 @@ function UniversalAssociationPicker(props) {
1944
2448
  style: { fontSize: 16 }
1945
2449
  }
1946
2450
  ),
1947
- loading && browseToken === null && /* @__PURE__ */ jsx6(SpinnerIcon, { className: "absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
2451
+ loading && browseToken === null && /* @__PURE__ */ jsx8(SpinnerIcon, { className: "absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
1948
2452
  ] }),
1949
- /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-1", children: tokens.map((t) => {
2453
+ /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1", children: tokens.map((t) => {
1950
2454
  const info = store.registry.getEntityInfo(t);
1951
2455
  const ChipIcon = info.Icon ?? DefaultEntityIcon;
1952
2456
  const active = browseToken === t;
1953
- return /* @__PURE__ */ jsxs4(
2457
+ return /* @__PURE__ */ jsxs6(
1954
2458
  "button",
1955
2459
  {
1956
2460
  type: "button",
1957
2461
  onClick: () => setBrowseToken(active ? null : t),
1958
- className: cn3(
2462
+ className: cn4(
1959
2463
  "inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] transition-colors",
1960
2464
  active ? "border-primary/50 bg-primary/10 text-foreground" : "border-border text-muted-foreground hover:text-foreground hover:bg-accent"
1961
2465
  ),
1962
2466
  children: [
1963
- /* @__PURE__ */ jsx6(ChipIcon, { className: "h-3 w-3" }),
2467
+ /* @__PURE__ */ jsx8(ChipIcon, { className: "h-3 w-3" }),
1964
2468
  info.labelPlural
1965
2469
  ]
1966
2470
  },
@@ -1970,7 +2474,7 @@ function UniversalAssociationPicker(props) {
1970
2474
  browseToken && BrowseOverride ? (
1971
2475
  // The token's canonical host picker (e.g. the stored-files browser)
1972
2476
  // owns per-token browsing when registered — never a plain list twin.
1973
- /* @__PURE__ */ jsx6(
2477
+ /* @__PURE__ */ jsx8(
1974
2478
  BrowseOverride,
1975
2479
  {
1976
2480
  open: true,
@@ -1986,7 +2490,7 @@ function UniversalAssociationPicker(props) {
1986
2490
  onDetach: (id) => onDetach(browseToken, id)
1987
2491
  }
1988
2492
  )
1989
- ) : browseToken ? /* @__PURE__ */ jsx6("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx6(
2493
+ ) : browseToken ? /* @__PURE__ */ jsx8("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx8(
1990
2494
  AssociationCandidateBody,
1991
2495
  {
1992
2496
  token: browseToken,
@@ -1999,63 +2503,63 @@ function UniversalAssociationPicker(props) {
1999
2503
  onAttach: (id, title) => onAttach(browseToken, id, title),
2000
2504
  onDetach: (id) => onDetach(browseToken, id)
2001
2505
  }
2002
- ) }) : /* @__PURE__ */ jsx6("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1", children: results.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "py-6 text-center text-[12px] text-muted-foreground", children: loading ? "Searching\u2026" : query.trim() ? "No matches \u2014 narrow with a type chip to browse." : "No recent items. Type to search, or pick a type to browse." }) : /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
2003
- isRecents && /* @__PURE__ */ jsx6("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
2506
+ ) }) : /* @__PURE__ */ jsx8("div", { className: "-mx-1 min-h-0 flex-1 overflow-y-auto px-1", children: results.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "py-6 text-center text-[12px] text-muted-foreground", children: loading ? "Searching\u2026" : query.trim() ? "No matches \u2014 narrow with a type chip to browse." : "No recent items. Type to search, or pick a type to browse." }) : /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
2507
+ isRecents && /* @__PURE__ */ jsx8("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: "Recent" }),
2004
2508
  [...groups.entries()].map(([token, items]) => {
2005
2509
  const info = store.registry.getEntityInfo(token);
2006
2510
  const GroupIcon = info.Icon ?? DefaultEntityIcon;
2007
- return /* @__PURE__ */ jsxs4("div", { className: "space-y-0.5", children: [
2008
- /* @__PURE__ */ jsxs4("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
2009
- /* @__PURE__ */ jsx6(GroupIcon, { className: "h-3 w-3" }),
2511
+ return /* @__PURE__ */ jsxs6("div", { className: "space-y-0.5", children: [
2512
+ /* @__PURE__ */ jsxs6("p", { className: "flex items-center gap-1 px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70", children: [
2513
+ /* @__PURE__ */ jsx8(GroupIcon, { className: "h-3 w-3" }),
2010
2514
  info.labelPlural
2011
2515
  ] }),
2012
- /* @__PURE__ */ jsx6("ul", { className: "space-y-0.5", children: items.map((c) => {
2516
+ /* @__PURE__ */ jsx8("ul", { className: "space-y-0.5", children: items.map((c) => {
2013
2517
  const key = attachedKey(c.token, c.id);
2014
2518
  const attached = attachedKeys.has(key);
2015
2519
  const busy = busyKey === key;
2016
- return /* @__PURE__ */ jsxs4(
2520
+ return /* @__PURE__ */ jsxs6(
2017
2521
  "li",
2018
2522
  {
2019
- className: cn3(
2523
+ className: cn4(
2020
2524
  "group/entity-ref group flex items-center gap-1 rounded-md pr-1.5 transition-colors",
2021
2525
  "hover:bg-accent",
2022
2526
  attached && "bg-accent/40"
2023
2527
  ),
2024
2528
  children: [
2025
- /* @__PURE__ */ jsxs4(
2529
+ /* @__PURE__ */ jsxs6(
2026
2530
  "button",
2027
2531
  {
2028
2532
  type: "button",
2029
2533
  disabled: busy,
2030
2534
  onClick: () => toggle(c),
2031
2535
  title: attached ? `Detach "${c.title}"` : `Attach "${c.title}"`,
2032
- className: cn3(
2536
+ className: cn4(
2033
2537
  "flex min-w-0 flex-1 items-center gap-2 rounded-md px-2.5 py-1.5 text-left text-sm",
2034
2538
  "disabled:opacity-50"
2035
2539
  ),
2036
2540
  children: [
2037
- /* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
2038
- /* @__PURE__ */ jsx6(
2541
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 flex-1 truncate text-foreground", children: c.title }),
2542
+ /* @__PURE__ */ jsx8(
2039
2543
  "span",
2040
2544
  {
2041
- className: cn3(
2545
+ className: cn4(
2042
2546
  "flex h-5 w-5 shrink-0 items-center justify-center rounded-full",
2043
2547
  attached ? "bg-primary text-primary-foreground" : "border border-border text-muted-foreground group-hover:border-primary/60"
2044
2548
  ),
2045
- children: busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx6(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx6(PlusIcon, { className: "h-3 w-3" })
2549
+ children: busy ? /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : attached ? /* @__PURE__ */ jsx8(CheckIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx8(PlusIcon, { className: "h-3 w-3" })
2046
2550
  }
2047
2551
  )
2048
2552
  ]
2049
2553
  }
2050
2554
  ),
2051
- DoorControls ? /* @__PURE__ */ jsx6(
2052
- DoorControls,
2555
+ /* @__PURE__ */ jsx8(
2556
+ DoorControlsSlot,
2053
2557
  {
2054
2558
  token: c.token,
2055
2559
  id: c.id,
2056
2560
  name: c.title
2057
2561
  }
2058
- ) : null
2562
+ )
2059
2563
  ]
2060
2564
  },
2061
2565
  key
@@ -2068,79 +2572,18 @@ function UniversalAssociationPicker(props) {
2068
2572
  }
2069
2573
 
2070
2574
  // src/react/components/AttachedItemsSheet.tsx
2071
- import { useEffect as useEffect8, useState as useState8 } from "react";
2575
+ import { useEffect as useEffect10, useState as useState9 } from "react";
2072
2576
  import { cn as cn5 } from "@ai-matrx/design-system";
2073
-
2074
- // src/react/components/entityDoors.tsx
2075
- import { cn as cn4 } from "@ai-matrx/design-system";
2076
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
2077
- function DoorRef(props) {
2078
- const { onOpen, ...refProps } = props;
2079
- const { entityDoors } = useAssociationsUiPorts();
2080
- const store = useAssociationsStore();
2081
- const HostRef = entityDoors?.EntityRef;
2082
- if (HostRef) return /* @__PURE__ */ jsx7(HostRef, { ...refProps });
2083
- const name = refProps.name ?? null;
2084
- const href = store.registry.tryGetEntityInfo(refProps.token)?.hrefFor?.(refProps.id) ?? null;
2085
- if (onOpen) {
2086
- return /* @__PURE__ */ jsx7(
2087
- "button",
2088
- {
2089
- type: "button",
2090
- onClick: onOpen,
2091
- className: cn4(
2092
- "min-w-0 truncate text-left underline-offset-2 hover:underline",
2093
- refProps.className
2094
- ),
2095
- children: name
2096
- }
2097
- );
2098
- }
2099
- if (href) {
2100
- return /* @__PURE__ */ jsxs5(
2101
- "a",
2102
- {
2103
- href,
2104
- target: refProps.openInNewTab === false ? void 0 : "_blank",
2105
- rel: "noopener noreferrer",
2106
- className: cn4(
2107
- "inline-flex min-w-0 items-center gap-1 truncate underline-offset-2 hover:underline",
2108
- refProps.className
2109
- ),
2110
- children: [
2111
- /* @__PURE__ */ jsx7("span", { className: "min-w-0 truncate", children: name }),
2112
- /* @__PURE__ */ jsx7(ExternalLinkIcon, { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-60" })
2113
- ]
2114
- }
2115
- );
2116
- }
2117
- return /* @__PURE__ */ jsx7("span", { className: cn4("min-w-0 truncate", refProps.className), children: name });
2118
- }
2119
- function UnresolvedRef({ token, id }) {
2120
- const { entityDoors } = useAssociationsUiPorts();
2121
- const HostUnresolved = entityDoors?.UnresolvedRef;
2122
- if (HostUnresolved) return /* @__PURE__ */ jsx7(HostUnresolved, { token, id });
2123
- return /* @__PURE__ */ jsx7(
2124
- "span",
2125
- {
2126
- className: "inline-flex items-center rounded border border-border/60 bg-muted/40 px-1.5 py-0.5 text-[11px] text-muted-foreground",
2127
- title: `This ${token} could not be read \u2014 it may be deleted or not shared with you.`,
2128
- children: "Unavailable"
2129
- }
2130
- );
2131
- }
2132
-
2133
- // src/react/components/AttachedItemsSheet.tsx
2134
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2577
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2135
2578
  function AttachedItemsSheet(props) {
2136
2579
  const store = useAssociationsStore();
2137
2580
  const info = store.registry.getEntityInfo(props.token);
2138
2581
  const Icon = info.Icon ?? DefaultEntityIcon;
2139
2582
  const title = info.labelPlural;
2140
2583
  const containerName = props.container?.label ?? props.containerLabel;
2141
- const subtitle = props.container ? /* @__PURE__ */ jsxs6("span", { className: "inline-flex min-w-0 max-w-full items-center gap-1", children: [
2584
+ const subtitle = props.container ? /* @__PURE__ */ jsxs7("span", { className: "inline-flex min-w-0 max-w-full items-center gap-1", children: [
2142
2585
  "Attached to",
2143
- /* @__PURE__ */ jsx8(
2586
+ /* @__PURE__ */ jsx9(
2144
2587
  DoorRef,
2145
2588
  {
2146
2589
  token: props.container.type,
@@ -2151,16 +2594,16 @@ function AttachedItemsSheet(props) {
2151
2594
  )
2152
2595
  ] }) : props.containerLabel ? `Attached to ${props.containerLabel}` : "Attached items";
2153
2596
  if (!props.open) return null;
2154
- return /* @__PURE__ */ jsx8(
2597
+ return /* @__PURE__ */ jsx9(
2155
2598
  AssociationWindow,
2156
2599
  {
2157
2600
  open: props.open,
2158
2601
  onClose: () => props.onOpenChange(false),
2159
2602
  scopeId: `attached:${props.token}`,
2160
2603
  title,
2161
- icon: /* @__PURE__ */ jsx8(Icon, { className: "size-3.5 text-primary" }),
2604
+ icon: /* @__PURE__ */ jsx9(Icon, { className: "size-3.5 text-primary" }),
2162
2605
  subtitle,
2163
- children: /* @__PURE__ */ jsx8(
2606
+ children: /* @__PURE__ */ jsx9(
2164
2607
  AttachedItemsBody,
2165
2608
  {
2166
2609
  token: props.token,
@@ -2184,11 +2627,11 @@ function AttachedItemsBody({
2184
2627
  const notifier = useNotifier();
2185
2628
  const info = store.registry.getEntityInfo(token);
2186
2629
  const Icon = info.Icon ?? DefaultEntityIcon;
2187
- const [titles, setTitles] = useState8(null);
2188
- const [titleError, setTitleError] = useState8(null);
2189
- const [busyId, setBusyId] = useState8(null);
2630
+ const [titles, setTitles] = useState9(null);
2631
+ const [titleError, setTitleError] = useState9(null);
2632
+ const [busyId, setBusyId] = useState9(null);
2190
2633
  const idKey = links.map((l) => l.resourceId).sort().join(",");
2191
- useEffect8(() => {
2634
+ useEffect10(() => {
2192
2635
  if (!enabled) return;
2193
2636
  const ids = idKey ? idKey.split(",") : [];
2194
2637
  if (ids.length === 0) {
@@ -2232,30 +2675,30 @@ function AttachedItemsBody({
2232
2675
  setBusyId(null);
2233
2676
  }
2234
2677
  };
2235
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
2236
- titleError ? /* @__PURE__ */ jsxs6("div", { className: "mb-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
2678
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
2679
+ titleError ? /* @__PURE__ */ jsxs7("div", { className: "mb-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
2237
2680
  "Showing names recorded at attach time \u2014 they may be out of date.",
2238
2681
  " ",
2239
2682
  titleError
2240
2683
  ] }) : null,
2241
- /* @__PURE__ */ jsx8("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: links.length === 0 ? /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-center py-8 text-[13px] text-muted-foreground", children: "Nothing attached yet." }) : titles === null ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children: [
2242
- /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
2684
+ /* @__PURE__ */ jsx9("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: links.length === 0 ? /* @__PURE__ */ jsx9("div", { className: "flex items-center justify-center py-8 text-[13px] text-muted-foreground", children: "Nothing attached yet." }) : titles === null ? /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-center gap-2 py-8 text-[13px] text-muted-foreground", children: [
2685
+ /* @__PURE__ */ jsx9(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
2243
2686
  "Loading\u2026"
2244
- ] }) : /* @__PURE__ */ jsx8("ul", { className: "space-y-0.5", children: links.map((link) => {
2687
+ ] }) : /* @__PURE__ */ jsx9("ul", { className: "space-y-0.5", children: links.map((link) => {
2245
2688
  const resolved = titles.get(link.resourceId);
2246
2689
  const missing = !titles.has(link.resourceId);
2247
2690
  const name = resolved ?? link.label ?? (missing ? null : "Untitled");
2248
2691
  const busy = busyId === link.resourceId;
2249
- return /* @__PURE__ */ jsxs6(
2692
+ return /* @__PURE__ */ jsxs7(
2250
2693
  "li",
2251
2694
  {
2252
2695
  className: "group/entity-ref group flex items-center gap-2 rounded-md px-2.5 py-2 text-sm transition-colors hover:bg-accent",
2253
2696
  children: [
2254
- /* @__PURE__ */ jsx8(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2255
- /* @__PURE__ */ jsx8("span", { className: "flex-1 min-w-0 truncate", children: name === null ? (
2697
+ /* @__PURE__ */ jsx9(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2698
+ /* @__PURE__ */ jsx9("span", { className: "flex-1 min-w-0 truncate", children: name === null ? (
2256
2699
  // The X beside the row stays the one-click detach.
2257
- /* @__PURE__ */ jsx8(UnresolvedRef, { token, id: link.resourceId })
2258
- ) : /* @__PURE__ */ jsx8(
2700
+ /* @__PURE__ */ jsx9(UnresolvedRef, { token, id: link.resourceId })
2701
+ ) : /* @__PURE__ */ jsx9(
2259
2702
  DoorRef,
2260
2703
  {
2261
2704
  token,
@@ -2265,7 +2708,7 @@ function AttachedItemsBody({
2265
2708
  className: "text-foreground"
2266
2709
  }
2267
2710
  ) }),
2268
- /* @__PURE__ */ jsx8(
2711
+ /* @__PURE__ */ jsx9(
2269
2712
  "button",
2270
2713
  {
2271
2714
  type: "button",
@@ -2276,7 +2719,7 @@ function AttachedItemsBody({
2276
2719
  "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
2277
2720
  "hover:bg-destructive/10 hover:text-destructive disabled:opacity-50"
2278
2721
  ),
2279
- children: busy ? /* @__PURE__ */ jsx8(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx8(XIcon, { className: "h-3.5 w-3.5" })
2722
+ children: busy ? /* @__PURE__ */ jsx9(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx9(XIcon, { className: "h-3.5 w-3.5" })
2280
2723
  }
2281
2724
  )
2282
2725
  ]
@@ -2284,14 +2727,14 @@ function AttachedItemsBody({
2284
2727
  link.edgeId
2285
2728
  );
2286
2729
  }) }) }),
2287
- onAdd ? /* @__PURE__ */ jsxs6(
2730
+ onAdd ? /* @__PURE__ */ jsxs7(
2288
2731
  "button",
2289
2732
  {
2290
2733
  type: "button",
2291
2734
  onClick: onAdd,
2292
2735
  className: "mt-2 flex w-full items-center justify-center gap-1.5 rounded-md border border-border px-3 py-2 text-sm text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground",
2293
2736
  children: [
2294
- /* @__PURE__ */ jsx8(PlusIcon, { className: "h-4 w-4" }),
2737
+ /* @__PURE__ */ jsx9(PlusIcon, { className: "h-4 w-4" }),
2295
2738
  "Attach ",
2296
2739
  info.labelPlural.toLowerCase()
2297
2740
  ]
@@ -2301,7 +2744,7 @@ function AttachedItemsBody({
2301
2744
  }
2302
2745
 
2303
2746
  // src/react/components/AssociationCard.tsx
2304
- import { useState as useState9 } from "react";
2747
+ import { useState as useState10 } from "react";
2305
2748
  import { cn as cn6 } from "@ai-matrx/design-system";
2306
2749
 
2307
2750
  // src/react/contentRoles.ts
@@ -2352,7 +2795,7 @@ function getContentRoleMeta(role) {
2352
2795
  }
2353
2796
 
2354
2797
  // src/react/components/AssociationCard.tsx
2355
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2798
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2356
2799
  function AssociationCard({
2357
2800
  token,
2358
2801
  container: containerProp,
@@ -2361,11 +2804,11 @@ function AssociationCard({
2361
2804
  const store = useAssociationsStore();
2362
2805
  const fromCtx = usePrimaryEntity();
2363
2806
  const container = containerProp ?? fromCtx;
2364
- const [open, setOpen] = useState9(false);
2807
+ const [open, setOpen] = useState10(false);
2365
2808
  const info = store.registry.getEntityInfo(token);
2366
2809
  const role = getContentRoleMeta(info.contentRole);
2367
2810
  const Icon = info.Icon ?? DefaultEntityIcon;
2368
- const [listOpen, setListOpen] = useState9(false);
2811
+ const [listOpen, setListOpen] = useState10(false);
2369
2812
  const { status, countFor, attachedIdsFor, linksFor, attach, detach } = useContainerLinks({
2370
2813
  containerType: container?.type ?? "organization",
2371
2814
  containerId: container?.id ?? null,
@@ -2383,8 +2826,8 @@ function AssociationCard({
2383
2826
  const loading = status === "loading" || status === "idle";
2384
2827
  const canAttach = info.canListCandidates;
2385
2828
  const canDrillIn = count > 0;
2386
- return /* @__PURE__ */ jsxs7(Fragment3, { children: [
2387
- /* @__PURE__ */ jsxs7(
2829
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
2830
+ /* @__PURE__ */ jsxs8(
2388
2831
  "div",
2389
2832
  {
2390
2833
  className: cn6(
@@ -2392,7 +2835,7 @@ function AssociationCard({
2392
2835
  className
2393
2836
  ),
2394
2837
  children: [
2395
- /* @__PURE__ */ jsx9(
2838
+ /* @__PURE__ */ jsx10(
2396
2839
  "span",
2397
2840
  {
2398
2841
  className: cn6(
@@ -2401,7 +2844,7 @@ function AssociationCard({
2401
2844
  )
2402
2845
  }
2403
2846
  ),
2404
- /* @__PURE__ */ jsxs7(
2847
+ /* @__PURE__ */ jsxs8(
2405
2848
  "button",
2406
2849
  {
2407
2850
  type: "button",
@@ -2413,7 +2856,7 @@ function AssociationCard({
2413
2856
  canDrillIn ? "cursor-pointer" : "cursor-default"
2414
2857
  ),
2415
2858
  children: [
2416
- /* @__PURE__ */ jsx9(
2859
+ /* @__PURE__ */ jsx10(
2417
2860
  "span",
2418
2861
  {
2419
2862
  className: cn6(
@@ -2421,20 +2864,20 @@ function AssociationCard({
2421
2864
  role.accentBg,
2422
2865
  role.accentText
2423
2866
  ),
2424
- children: /* @__PURE__ */ jsx9(Icon, { className: "h-4 w-4" })
2867
+ children: /* @__PURE__ */ jsx10(Icon, { className: "h-4 w-4" })
2425
2868
  }
2426
2869
  ),
2427
- /* @__PURE__ */ jsxs7("span", { className: "min-w-0 flex-1", children: [
2428
- /* @__PURE__ */ jsx9("span", { className: "block truncate text-sm font-medium text-foreground", children: info.labelPlural }),
2429
- /* @__PURE__ */ jsx9("span", { className: "block text-[11px] text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ jsxs7("span", { className: "inline-flex items-center gap-1", children: [
2430
- /* @__PURE__ */ jsx9(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
2870
+ /* @__PURE__ */ jsxs8("span", { className: "min-w-0 flex-1", children: [
2871
+ /* @__PURE__ */ jsx10("span", { className: "block truncate text-sm font-medium text-foreground", children: info.labelPlural }),
2872
+ /* @__PURE__ */ jsx10("span", { className: "block text-[11px] text-muted-foreground tabular-nums", children: loading ? /* @__PURE__ */ jsxs8("span", { className: "inline-flex items-center gap-1", children: [
2873
+ /* @__PURE__ */ jsx10(SpinnerIcon, { className: "h-3 w-3 animate-spin" }),
2431
2874
  "Loading\u2026"
2432
2875
  ] }) : `${count} attached` })
2433
2876
  ] })
2434
2877
  ]
2435
2878
  }
2436
2879
  ),
2437
- canAttach && /* @__PURE__ */ jsx9(
2880
+ canAttach && /* @__PURE__ */ jsx10(
2438
2881
  "button",
2439
2882
  {
2440
2883
  type: "button",
@@ -2442,13 +2885,13 @@ function AssociationCard({
2442
2885
  "aria-label": `Attach ${info.labelPlural.toLowerCase()}`,
2443
2886
  title: `Attach ${info.labelPlural.toLowerCase()}`,
2444
2887
  className: "mr-2 flex h-11 w-11 shrink-0 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:border-primary/60 hover:text-foreground lg:mr-3 lg:h-7 lg:w-7",
2445
- children: /* @__PURE__ */ jsx9(PlusIcon, { className: "h-4 w-4" })
2888
+ children: /* @__PURE__ */ jsx10(PlusIcon, { className: "h-4 w-4" })
2446
2889
  }
2447
2890
  )
2448
2891
  ]
2449
2892
  }
2450
2893
  ),
2451
- listOpen && /* @__PURE__ */ jsx9(
2894
+ listOpen && /* @__PURE__ */ jsx10(
2452
2895
  AttachedItemsSheet,
2453
2896
  {
2454
2897
  open: listOpen,
@@ -2466,7 +2909,7 @@ function AssociationCard({
2466
2909
  onDetach: (resourceId) => detach(token, resourceId)
2467
2910
  }
2468
2911
  ),
2469
- canAttach && /* @__PURE__ */ jsx9(
2912
+ canAttach && /* @__PURE__ */ jsx10(
2470
2913
  AssociationPicker,
2471
2914
  {
2472
2915
  open,
@@ -2484,7 +2927,7 @@ function AssociationCard({
2484
2927
 
2485
2928
  // src/react/components/AssociationCardGrid.tsx
2486
2929
  import { cn as cn7 } from "@ai-matrx/design-system";
2487
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
2930
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2488
2931
  function AssociationCardGrid({
2489
2932
  tokens,
2490
2933
  excludeTokens,
@@ -2495,33 +2938,33 @@ function AssociationCardGrid({
2495
2938
  const list = (tokens ?? store.registry.curatedTokens()).filter(
2496
2939
  (token) => !excluded.has(token)
2497
2940
  );
2498
- return /* @__PURE__ */ jsx10("div", { className: cn7("space-y-5", className), children: CONTENT_ROLES.map((role) => {
2941
+ return /* @__PURE__ */ jsx11("div", { className: cn7("space-y-5", className), children: CONTENT_ROLES.map((role) => {
2499
2942
  const inRole = list.filter(
2500
2943
  (token) => store.registry.getEntityInfo(token).contentRole === role.id
2501
2944
  );
2502
2945
  if (inRole.length === 0) return null;
2503
- return /* @__PURE__ */ jsxs8("section", { children: [
2504
- /* @__PURE__ */ jsxs8("div", { className: "mb-2.5 flex items-baseline gap-3 pl-1.5", children: [
2505
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
2506
- /* @__PURE__ */ jsx10(
2946
+ return /* @__PURE__ */ jsxs9("section", { children: [
2947
+ /* @__PURE__ */ jsxs9("div", { className: "mb-2.5 flex items-baseline gap-3 pl-1.5", children: [
2948
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
2949
+ /* @__PURE__ */ jsx11(
2507
2950
  "span",
2508
2951
  {
2509
2952
  className: cn7("h-2.5 w-2.5 rounded-full", role.accentBar)
2510
2953
  }
2511
2954
  ),
2512
- /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-foreground", children: role.title })
2955
+ /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-foreground", children: role.title })
2513
2956
  ] }),
2514
- /* @__PURE__ */ jsx10("p", { className: "hidden text-xs text-muted-foreground sm:block", children: role.tagline })
2957
+ /* @__PURE__ */ jsx11("p", { className: "hidden text-xs text-muted-foreground sm:block", children: role.tagline })
2515
2958
  ] }),
2516
- /* @__PURE__ */ jsx10("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3", children: inRole.map((token) => /* @__PURE__ */ jsx10(AssociationCard, { token }, token)) })
2959
+ /* @__PURE__ */ jsx11("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2 lg:grid-cols-3", children: inRole.map((token) => /* @__PURE__ */ jsx11(AssociationCard, { token }, token)) })
2517
2960
  ] }, role.id);
2518
2961
  }) });
2519
2962
  }
2520
2963
 
2521
2964
  // src/react/components/AssociationList.tsx
2522
- import { useState as useState10 } from "react";
2965
+ import { useState as useState11 } from "react";
2523
2966
  import { cn as cn8, Skeleton } from "@ai-matrx/design-system";
2524
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2967
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2525
2968
  function useContainerLinksAdapter(container, tokens) {
2526
2969
  const store = useAssociationsStore();
2527
2970
  const links = useContainerLinks({
@@ -2559,9 +3002,9 @@ function AssociationList(props) {
2559
3002
  const adapter = props.adapter ?? defaultAdapter;
2560
3003
  const variant = props.variant ?? "full";
2561
3004
  const tokenFilter = props.tokens ?? null;
2562
- const [pickerToken, setPickerToken] = useState10(null);
2563
- const [showUniversal, setShowUniversal] = useState10(false);
2564
- const [removingKeys, setRemovingKeys] = useState10(/* @__PURE__ */ new Set());
3005
+ const [pickerToken, setPickerToken] = useState11(null);
3006
+ const [showUniversal, setShowUniversal] = useState11(false);
3007
+ const [removingKeys, setRemovingKeys] = useState11(/* @__PURE__ */ new Set());
2565
3008
  const rows = tokenFilter ? adapter.rows.filter((r) => tokenFilter.includes(r.token)) : adapter.rows;
2566
3009
  const visibleRows = rows.filter((r) => !removingKeys.has(r.key));
2567
3010
  const { titleFor } = useEntityTitles(
@@ -2599,15 +3042,15 @@ function AssociationList(props) {
2599
3042
  const grouped = groupRows(store, visibleRows);
2600
3043
  const isLoading = adapter.status === "loading" || adapter.status === "idle";
2601
3044
  const attachableTokens = tokenFilter ?? store.registry.curatedTokens();
2602
- return /* @__PURE__ */ jsxs9("div", { className: cn8("flex flex-col gap-2 text-foreground", props.className), children: [
2603
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-2 px-1", children: [
2604
- /* @__PURE__ */ jsxs9("h3", { className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: [
2605
- /* @__PURE__ */ jsx11(Link2Icon, { className: "h-3.5 w-3.5" }),
3045
+ return /* @__PURE__ */ jsxs10("div", { className: cn8("flex flex-col gap-2 text-foreground", props.className), children: [
3046
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-2 px-1", children: [
3047
+ /* @__PURE__ */ jsxs10("h3", { className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: [
3048
+ /* @__PURE__ */ jsx12(Link2Icon, { className: "h-3.5 w-3.5" }),
2606
3049
  "Resources",
2607
- visibleRows.length > 0 && /* @__PURE__ */ jsx11("span", { className: "rounded bg-muted px-1 text-[10px] font-medium text-muted-foreground", children: visibleRows.length })
3050
+ visibleRows.length > 0 && /* @__PURE__ */ jsx12("span", { className: "rounded bg-muted px-1 text-[10px] font-medium text-muted-foreground", children: visibleRows.length })
2608
3051
  ] }),
2609
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1.5", children: [
2610
- /* @__PURE__ */ jsxs9(
3052
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5", children: [
3053
+ /* @__PURE__ */ jsxs10(
2611
3054
  "button",
2612
3055
  {
2613
3056
  type: "button",
@@ -2617,19 +3060,19 @@ function AssociationList(props) {
2617
3060
  showUniversal ? "bg-accent text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
2618
3061
  ),
2619
3062
  children: [
2620
- /* @__PURE__ */ jsx11(PlusIcon, { className: "h-3 w-3" }),
3063
+ /* @__PURE__ */ jsx12(PlusIcon, { className: "h-3 w-3" }),
2621
3064
  "Add"
2622
3065
  ]
2623
3066
  }
2624
3067
  ),
2625
- /* @__PURE__ */ jsx11(
3068
+ /* @__PURE__ */ jsx12(
2626
3069
  "button",
2627
3070
  {
2628
3071
  type: "button",
2629
3072
  onClick: () => void adapter.reload(),
2630
3073
  title: "Refresh",
2631
3074
  className: "text-muted-foreground/60 transition-colors hover:text-foreground",
2632
- children: /* @__PURE__ */ jsx11(
3075
+ children: /* @__PURE__ */ jsx12(
2633
3076
  RefreshIcon,
2634
3077
  {
2635
3078
  className: cn8(
@@ -2642,7 +3085,7 @@ function AssociationList(props) {
2642
3085
  )
2643
3086
  ] })
2644
3087
  ] }),
2645
- showUniversal && /* @__PURE__ */ jsx11("div", { className: "rounded-md border border-border/60 bg-muted/30 p-2 max-h-80 flex flex-col", children: /* @__PURE__ */ jsx11(
3088
+ showUniversal && /* @__PURE__ */ jsx12("div", { className: "rounded-md border border-border/60 bg-muted/30 p-2 max-h-80 flex flex-col", children: /* @__PURE__ */ jsx12(
2646
3089
  UniversalAssociationPicker,
2647
3090
  {
2648
3091
  tokens: attachableTokens,
@@ -2652,9 +3095,9 @@ function AssociationList(props) {
2652
3095
  onDetach: (token, id) => adapter.detach(token, id)
2653
3096
  }
2654
3097
  ) }),
2655
- adapter.status === "error" && /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-2", children: [
2656
- /* @__PURE__ */ jsx11("span", { className: "truncate text-[11px] text-destructive", children: adapter.error || "Failed to load resources" }),
2657
- /* @__PURE__ */ jsx11(
3098
+ adapter.status === "error" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-2.5 py-2", children: [
3099
+ /* @__PURE__ */ jsx12("span", { className: "truncate text-[11px] text-destructive", children: adapter.error || "Failed to load resources" }),
3100
+ /* @__PURE__ */ jsx12(
2658
3101
  "button",
2659
3102
  {
2660
3103
  type: "button",
@@ -2664,17 +3107,17 @@ function AssociationList(props) {
2664
3107
  }
2665
3108
  )
2666
3109
  ] }),
2667
- adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */ jsxs9("div", { className: "space-y-1.5 px-1", children: [
2668
- /* @__PURE__ */ jsx11(Skeleton, { className: "h-3 w-20" }),
2669
- /* @__PURE__ */ jsx11(Skeleton, { className: "h-7 w-full rounded-md" }),
2670
- /* @__PURE__ */ jsx11(Skeleton, { className: "h-7 w-3/4 rounded-md" })
3110
+ adapter.status !== "error" && isLoading && visibleRows.length === 0 && /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5 px-1", children: [
3111
+ /* @__PURE__ */ jsx12(Skeleton, { className: "h-3 w-20" }),
3112
+ /* @__PURE__ */ jsx12(Skeleton, { className: "h-7 w-full rounded-md" }),
3113
+ /* @__PURE__ */ jsx12(Skeleton, { className: "h-7 w-3/4 rounded-md" })
2671
3114
  ] }),
2672
- adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */ jsx11("p", { className: "px-1 py-1 text-[11px] text-muted-foreground", children: "Nothing attached yet \u2014 use Add to link anything." }),
2673
- visibleRows.length > 0 && /* @__PURE__ */ jsx11("div", { className: "space-y-2.5", children: grouped.map(({ role, tokens: tokenGroups }) => {
3115
+ adapter.status === "ready" && visibleRows.length === 0 && /* @__PURE__ */ jsx12("p", { className: "px-1 py-1 text-[11px] text-muted-foreground", children: "Nothing attached yet \u2014 use Add to link anything." }),
3116
+ visibleRows.length > 0 && /* @__PURE__ */ jsx12("div", { className: "space-y-2.5", children: grouped.map(({ role, tokens: tokenGroups }) => {
2674
3117
  const roleMeta = getContentRoleMeta(role);
2675
- return /* @__PURE__ */ jsxs9("div", { className: "space-y-1.5", children: [
2676
- variant === "full" && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1.5 px-1", children: [
2677
- /* @__PURE__ */ jsx11(
3118
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
3119
+ variant === "full" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1.5 px-1", children: [
3120
+ /* @__PURE__ */ jsx12(
2678
3121
  "span",
2679
3122
  {
2680
3123
  className: cn8(
@@ -2683,7 +3126,7 @@ function AssociationList(props) {
2683
3126
  )
2684
3127
  }
2685
3128
  ),
2686
- /* @__PURE__ */ jsx11(
3129
+ /* @__PURE__ */ jsx12(
2687
3130
  "p",
2688
3131
  {
2689
3132
  className: cn8(
@@ -2696,28 +3139,28 @@ function AssociationList(props) {
2696
3139
  ] }),
2697
3140
  tokenGroups.map(({ info, token, rows: tokenRows }) => {
2698
3141
  const TokenIcon = info?.Icon ?? null;
2699
- return /* @__PURE__ */ jsxs9("div", { className: "space-y-0.5", children: [
2700
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between gap-1 px-1", children: [
2701
- /* @__PURE__ */ jsxs9("p", { className: "flex items-center gap-1 text-[10px] font-medium text-muted-foreground/80", children: [
2702
- TokenIcon ? /* @__PURE__ */ jsx11(TokenIcon, { className: "h-3 w-3" }) : null,
3142
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-0.5", children: [
3143
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-between gap-1 px-1", children: [
3144
+ /* @__PURE__ */ jsxs10("p", { className: "flex items-center gap-1 text-[10px] font-medium text-muted-foreground/80", children: [
3145
+ TokenIcon ? /* @__PURE__ */ jsx12(TokenIcon, { className: "h-3 w-3" }) : null,
2703
3146
  info?.labelPlural ?? titleize(token),
2704
- /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground/50", children: tokenRows.length })
3147
+ /* @__PURE__ */ jsx12("span", { className: "text-muted-foreground/50", children: tokenRows.length })
2705
3148
  ] }),
2706
- /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
3149
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1", children: [
2707
3150
  props.renderSectionActions && info ? props.renderSectionActions(info.token) : null,
2708
- info?.canListCandidates && /* @__PURE__ */ jsx11(
3151
+ info?.canListCandidates && /* @__PURE__ */ jsx12(
2709
3152
  "button",
2710
3153
  {
2711
3154
  type: "button",
2712
3155
  onClick: () => setPickerToken(info.token),
2713
3156
  title: `Add ${info.labelPlural}`,
2714
3157
  className: "rounded p-0.5 text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground",
2715
- children: /* @__PURE__ */ jsx11(PlusIcon, { className: "h-3 w-3" })
3158
+ children: /* @__PURE__ */ jsx12(PlusIcon, { className: "h-3 w-3" })
2716
3159
  }
2717
3160
  )
2718
3161
  ] })
2719
3162
  ] }),
2720
- /* @__PURE__ */ jsx11("ul", { className: "space-y-0.5", children: tokenRows.map((row) => {
3163
+ /* @__PURE__ */ jsx12("ul", { className: "space-y-0.5", children: tokenRows.map((row) => {
2721
3164
  const busy = removingKeys.has(row.key);
2722
3165
  const custom = props.renderRow?.(row, {
2723
3166
  title: titleFor({
@@ -2730,9 +3173,9 @@ function AssociationList(props) {
2730
3173
  onOpen: () => openRow(row)
2731
3174
  });
2732
3175
  if (custom != null) {
2733
- return /* @__PURE__ */ jsx11("li", { children: custom }, row.key);
3176
+ return /* @__PURE__ */ jsx12("li", { children: custom }, row.key);
2734
3177
  }
2735
- return /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs9(
3178
+ return /* @__PURE__ */ jsx12("li", { children: /* @__PURE__ */ jsxs10(
2736
3179
  "div",
2737
3180
  {
2738
3181
  className: cn8(
@@ -2740,7 +3183,7 @@ function AssociationList(props) {
2740
3183
  busy && "opacity-50"
2741
3184
  ),
2742
3185
  children: [
2743
- /* @__PURE__ */ jsx11(
3186
+ /* @__PURE__ */ jsx12(
2744
3187
  DoorRef,
2745
3188
  {
2746
3189
  token: row.token,
@@ -2756,9 +3199,9 @@ function AssociationList(props) {
2756
3199
  className: "min-w-0 flex-1 text-foreground"
2757
3200
  }
2758
3201
  ),
2759
- row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */ jsxs9("span", { className: "flex shrink-0 items-center gap-1 text-[10px] text-muted-foreground/60", children: [
3202
+ row.originRefs && row.originRefs.length > 0 ? /* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1 text-[10px] text-muted-foreground/60", children: [
2760
3203
  "via",
2761
- row.originRefs.map((origin) => /* @__PURE__ */ jsx11(
3204
+ row.originRefs.map((origin) => /* @__PURE__ */ jsx12(
2762
3205
  DoorRef,
2763
3206
  {
2764
3207
  token: origin.token,
@@ -2770,8 +3213,8 @@ function AssociationList(props) {
2770
3213
  },
2771
3214
  `${origin.token}:${origin.id}`
2772
3215
  ))
2773
- ] }) : row.originNote ? /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: row.originNote }) : null,
2774
- adapter.setPinned && info && row.removable && /* @__PURE__ */ jsx11(
3216
+ ] }) : row.originNote ? /* @__PURE__ */ jsx12("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: row.originNote }) : null,
3217
+ adapter.setPinned && info && row.removable && /* @__PURE__ */ jsx12(
2775
3218
  "button",
2776
3219
  {
2777
3220
  type: "button",
@@ -2786,7 +3229,7 @@ function AssociationList(props) {
2786
3229
  "shrink-0 rounded p-0.5 transition-colors hover:!text-foreground",
2787
3230
  row.pinned ? "text-primary" : "text-muted-foreground/0 group-hover:text-muted-foreground"
2788
3231
  ),
2789
- children: /* @__PURE__ */ jsx11(
3232
+ children: /* @__PURE__ */ jsx12(
2790
3233
  PinIcon,
2791
3234
  {
2792
3235
  className: cn8(
@@ -2797,7 +3240,7 @@ function AssociationList(props) {
2797
3240
  )
2798
3241
  }
2799
3242
  ),
2800
- row.removable && /* @__PURE__ */ jsx11(
3243
+ row.removable && /* @__PURE__ */ jsx12(
2801
3244
  "button",
2802
3245
  {
2803
3246
  type: "button",
@@ -2806,7 +3249,7 @@ function AssociationList(props) {
2806
3249
  title: "Detach",
2807
3250
  "aria-label": "Detach",
2808
3251
  className: "shrink-0 rounded p-0.5 text-muted-foreground/0 transition-colors group-hover:text-muted-foreground hover:!text-destructive disabled:opacity-50",
2809
- children: busy ? /* @__PURE__ */ jsx11(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx11(XIcon, { className: "h-3 w-3" })
3252
+ children: busy ? /* @__PURE__ */ jsx12(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsx12(XIcon, { className: "h-3 w-3" })
2810
3253
  }
2811
3254
  )
2812
3255
  ]
@@ -2817,7 +3260,7 @@ function AssociationList(props) {
2817
3260
  })
2818
3261
  ] }, role);
2819
3262
  }) }),
2820
- pickerToken && /* @__PURE__ */ jsx11(
3263
+ pickerToken && /* @__PURE__ */ jsx12(
2821
3264
  AssociationPicker,
2822
3265
  {
2823
3266
  open: true,
@@ -2873,9 +3316,9 @@ function titleize(token) {
2873
3316
  }
2874
3317
 
2875
3318
  // src/react/components/AssociationCaptureToolbar.tsx
2876
- import { useRef as useRef7, useState as useState11 } from "react";
3319
+ import { useRef as useRef8, useState as useState12 } from "react";
2877
3320
  import { Button, cn as cn9, Input as Input3 } from "@ai-matrx/design-system";
2878
- import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3321
+ import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2879
3322
  function AssociationCaptureToolbar({
2880
3323
  attach,
2881
3324
  uploadFolderPath,
@@ -2893,21 +3336,43 @@ function AssociationCaptureToolbar({
2893
3336
  const store = useAssociationsStore();
2894
3337
  const { capture } = useAssociationsUiPorts();
2895
3338
  const notifier = useNotifier();
2896
- const fileInputRef = useRef7(null);
2897
- const [isUploading, setIsUploading] = useState11(false);
2898
- const [isDragOver, setIsDragOver] = useState11(false);
2899
- const [isPicking, setIsPicking] = useState11(false);
2900
- const [namingDoc, setNamingDoc] = useState11(false);
2901
- const [docName, setDocName] = useState11("");
2902
- const [creatingDoc, setCreatingDoc] = useState11(false);
3339
+ const fileInputRef = useRef8(null);
3340
+ const [isUploading, setIsUploading] = useState12(false);
3341
+ const [isDragOver, setIsDragOver] = useState12(false);
3342
+ const [isPicking, setIsPicking] = useState12(false);
3343
+ const [namingDoc, setNamingDoc] = useState12(false);
3344
+ const [docName, setDocName] = useState12("");
3345
+ const [creatingDoc, setCreatingDoc] = useState12(false);
3346
+ const hostRequestUpload = capture?.requestUpload;
3347
+ const hostUploadFile = capture?.uploadFile;
3348
+ const requestUploadPath = hostRequestUpload ? (opts) => hostRequestUpload(opts) : hostUploadFile ? async (opts) => {
3349
+ const uploaded = [];
3350
+ const failed = [];
3351
+ for (const file of opts.files) {
3352
+ try {
3353
+ const result = await hostUploadFile(file, {
3354
+ folderPath: opts.folderPath,
3355
+ ...opts.visibility !== void 0 ? { visibility: opts.visibility } : {}
3356
+ });
3357
+ if (result.ok) uploaded.push(result.id);
3358
+ else failed.push({ name: file.name, error: result.error });
3359
+ } catch (err) {
3360
+ failed.push({
3361
+ name: file.name,
3362
+ error: err instanceof Error && err.message ? err.message : "Upload failed"
3363
+ });
3364
+ }
3365
+ }
3366
+ return { uploaded, aliased: [], failed };
3367
+ } : void 0;
2903
3368
  const actions = {
2904
- upload: (showActions?.upload ?? true) && Boolean(capture?.requestUpload),
3369
+ upload: (showActions?.upload ?? true) && Boolean(requestUploadPath),
2905
3370
  addFile: (showActions?.addFile ?? true) && Boolean(capture?.openFilePicker),
2906
3371
  newDocument: (showActions?.newDocument ?? true) && Boolean(capture?.createDataTable)
2907
3372
  };
2908
- const canDrop = Boolean(capture?.requestUpload);
3373
+ const canDrop = Boolean(requestUploadPath);
2909
3374
  const uploadAndAttach = async (files) => {
2910
- const requestUpload = capture?.requestUpload;
3375
+ const requestUpload = requestUploadPath;
2911
3376
  if (files.length === 0 || !requestUpload) return;
2912
3377
  setIsUploading(true);
2913
3378
  const watchdog = setTimeout(() => {
@@ -3065,7 +3530,7 @@ function AssociationCaptureToolbar({
3065
3530
  }
3066
3531
  };
3067
3532
  const anyBuiltIn = actions.upload || actions.addFile || actions.newDocument;
3068
- return /* @__PURE__ */ jsxs10(
3533
+ return /* @__PURE__ */ jsxs11(
3069
3534
  "div",
3070
3535
  {
3071
3536
  className: cn9(
@@ -3086,11 +3551,11 @@ function AssociationCaptureToolbar({
3086
3551
  },
3087
3552
  onDrop: handleDrop,
3088
3553
  children: [
3089
- isDragOver ? /* @__PURE__ */ jsx12("div", { className: "pointer-events-none absolute inset-0 z-10 grid place-items-center bg-background/70", children: /* @__PURE__ */ jsxs10("span", { className: "flex items-center gap-2 rounded-md border border-primary/40 bg-card px-3 py-1.5 text-xs font-medium text-foreground", children: [
3090
- /* @__PURE__ */ jsx12(UploadIcon, { className: "size-3.5 text-primary" }),
3554
+ isDragOver ? /* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute inset-0 z-10 grid place-items-center bg-background/70", children: /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2 rounded-md border border-primary/40 bg-card px-3 py-1.5 text-xs font-medium text-foreground", children: [
3555
+ /* @__PURE__ */ jsx13(UploadIcon, { className: "size-3.5 text-primary" }),
3091
3556
  "Drop to upload & attach"
3092
3557
  ] }) }) : null,
3093
- /* @__PURE__ */ jsx12(
3558
+ /* @__PURE__ */ jsx13(
3094
3559
  "input",
3095
3560
  {
3096
3561
  ref: fileInputRef,
@@ -3100,8 +3565,8 @@ function AssociationCaptureToolbar({
3100
3565
  onChange: handleFilesSelected
3101
3566
  }
3102
3567
  ),
3103
- showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */ jsx12("div", { className: "flex flex-wrap items-center gap-0.5 border-b border-border/60 px-1.5 py-1", children: namingDoc ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-1 items-center gap-1.5 py-0.5", children: [
3104
- /* @__PURE__ */ jsx12(
3568
+ showToolbar && (anyBuiltIn || extraActions) ? /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap items-center gap-0.5 border-b border-border/60 px-1.5 py-1", children: namingDoc ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 items-center gap-1.5 py-0.5", children: [
3569
+ /* @__PURE__ */ jsx13(
3105
3570
  Input3,
3106
3571
  {
3107
3572
  autoFocus: true,
@@ -3120,17 +3585,17 @@ function AssociationCaptureToolbar({
3120
3585
  style: { fontSize: 16 }
3121
3586
  }
3122
3587
  ),
3123
- /* @__PURE__ */ jsx12(
3588
+ /* @__PURE__ */ jsx13(
3124
3589
  "button",
3125
3590
  {
3126
3591
  type: "button",
3127
3592
  disabled: creatingDoc || !docName.trim(),
3128
3593
  onClick: () => void handleCreateDoc(),
3129
3594
  className: "flex h-7 items-center rounded-md bg-primary px-2 text-[11px] font-medium text-primary-foreground disabled:opacity-50",
3130
- children: creatingDoc ? /* @__PURE__ */ jsx12(SpinnerIcon, { className: "size-3.5 animate-spin" }) : "Create"
3595
+ children: creatingDoc ? /* @__PURE__ */ jsx13(SpinnerIcon, { className: "size-3.5 animate-spin" }) : "Create"
3131
3596
  }
3132
3597
  ),
3133
- /* @__PURE__ */ jsx12(
3598
+ /* @__PURE__ */ jsx13(
3134
3599
  "button",
3135
3600
  {
3136
3601
  type: "button",
@@ -3143,8 +3608,8 @@ function AssociationCaptureToolbar({
3143
3608
  children: "Cancel"
3144
3609
  }
3145
3610
  )
3146
- ] }) : /* @__PURE__ */ jsxs10(Fragment4, { children: [
3147
- actions.upload ? /* @__PURE__ */ jsx12(
3611
+ ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
3612
+ actions.upload ? /* @__PURE__ */ jsx13(
3148
3613
  CaptureToolbarAction,
3149
3614
  {
3150
3615
  icon: isUploading ? SpinnerIcon : UploadIcon,
@@ -3154,7 +3619,7 @@ function AssociationCaptureToolbar({
3154
3619
  disabled: isPicking || isUploading
3155
3620
  }
3156
3621
  ) : null,
3157
- actions.addFile ? /* @__PURE__ */ jsx12(
3622
+ actions.addFile ? /* @__PURE__ */ jsx13(
3158
3623
  CaptureToolbarAction,
3159
3624
  {
3160
3625
  icon: isPicking ? SpinnerIcon : FolderOpenIcon,
@@ -3164,8 +3629,8 @@ function AssociationCaptureToolbar({
3164
3629
  disabled: isPicking || isUploading
3165
3630
  }
3166
3631
  ) : null,
3167
- (actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */ jsx12("span", { className: "mx-1 h-4 w-px bg-border" }) : null,
3168
- actions.newDocument ? /* @__PURE__ */ jsx12(
3632
+ (actions.upload || actions.addFile) && actions.newDocument ? /* @__PURE__ */ jsx13("span", { className: "mx-1 h-4 w-px bg-border" }) : null,
3633
+ actions.newDocument ? /* @__PURE__ */ jsx13(
3169
3634
  CaptureToolbarAction,
3170
3635
  {
3171
3636
  icon: creatingDoc ? SpinnerIcon : PlusIcon,
@@ -3189,7 +3654,7 @@ function CaptureToolbarAction({
3189
3654
  disabled,
3190
3655
  spinning
3191
3656
  }) {
3192
- return /* @__PURE__ */ jsxs10(
3657
+ return /* @__PURE__ */ jsxs11(
3193
3658
  Button,
3194
3659
  {
3195
3660
  type: "button",
@@ -3199,15 +3664,145 @@ function CaptureToolbarAction({
3199
3664
  disabled,
3200
3665
  className: "h-7 gap-1 px-2 text-[11px] text-muted-foreground hover:text-foreground",
3201
3666
  children: [
3202
- /* @__PURE__ */ jsx12(Icon, { className: cn9("size-3.5", spinning && "animate-spin") }),
3667
+ /* @__PURE__ */ jsx13(Icon, { className: cn9("size-3.5", spinning && "animate-spin") }),
3203
3668
  label
3204
3669
  ]
3205
3670
  }
3206
3671
  );
3207
3672
  }
3208
3673
 
3674
+ // src/react/lazyPorts.tsx
3675
+ import { Suspense, lazy } from "react";
3676
+ import { jsx as jsx14 } from "react/jsx-runtime";
3677
+ function lazyComponent(load) {
3678
+ return lazy(async () => {
3679
+ const loaded = await load();
3680
+ return typeof loaded === "function" ? { default: loaded } : loaded;
3681
+ });
3682
+ }
3683
+ function lazyWindowShell(load) {
3684
+ const Loaded = lazyComponent(load);
3685
+ return function LazyWindowShell(props) {
3686
+ return /* @__PURE__ */ jsx14(Suspense, { fallback: null, children: /* @__PURE__ */ jsx14(Loaded, { ...props }) });
3687
+ };
3688
+ }
3689
+ function lazyPickerOverride(load) {
3690
+ const Loaded = lazyComponent(load);
3691
+ return function LazyPickerOverride(props) {
3692
+ if (!props.open) return null;
3693
+ return /* @__PURE__ */ jsx14(Suspense, { fallback: null, children: /* @__PURE__ */ jsx14(Loaded, { ...props }) });
3694
+ };
3695
+ }
3696
+
3697
+ // src/react/hooks/useAssociationPickerBridge.ts
3698
+ import { useCallback as useCallback3, useState as useState13 } from "react";
3699
+ function useAssociationPickerBridge(props, options = {}) {
3700
+ const store = useAssociationsStore();
3701
+ const notifier = useNotifier();
3702
+ const [busy, setBusy] = useState13(false);
3703
+ const { attachedIds, onAttach, onDetach, token } = props;
3704
+ const {
3705
+ createdLocationLabel,
3706
+ openCreatedLocation,
3707
+ itemNoun = "item"
3708
+ } = options;
3709
+ const attachMany = useCallback3(
3710
+ async (items) => {
3711
+ if (items.length === 0) return;
3712
+ setBusy(true);
3713
+ const failed = [];
3714
+ try {
3715
+ for (const item of items) {
3716
+ try {
3717
+ const result = await onAttach(item.id, item.name);
3718
+ if (!result.ok) {
3719
+ failed.push({ name: item.name, error: result.error });
3720
+ }
3721
+ } catch (error) {
3722
+ store.errorSink({
3723
+ code: "picker_attach_threw",
3724
+ message: `[associations] attaching ${itemNoun} "${item.name}" threw`,
3725
+ context: { token, id: item.id, detail: error }
3726
+ });
3727
+ failed.push({
3728
+ name: item.name,
3729
+ error: error instanceof Error ? error.message : void 0
3730
+ });
3731
+ }
3732
+ }
3733
+ const attached = items.length - failed.length;
3734
+ if (attached > 0) {
3735
+ notifier.success(
3736
+ attached === 1 ? `Attached 1 ${itemNoun}` : `Attached ${attached} ${itemNoun}s`
3737
+ );
3738
+ }
3739
+ if (failed.length > 0) {
3740
+ const first = failed[0];
3741
+ const detail = first?.error ? ` (${first.error})` : "";
3742
+ notifier.error(
3743
+ failed.length === 1 ? `Couldn't attach "${first?.name ?? itemNoun}"${detail}` : `Couldn't attach ${failed.length} ${itemNoun}s${detail}`,
3744
+ {
3745
+ ...createdLocationLabel ? {
3746
+ description: `The ${failed.length === 1 ? itemNoun + " is" : itemNoun + "s are"} safe in ${createdLocationLabel}. You can retry the association here.`
3747
+ } : {},
3748
+ ...openCreatedLocation ? { action: openCreatedLocation } : {}
3749
+ }
3750
+ );
3751
+ store.errorSink({
3752
+ code: "picker_attach_partial",
3753
+ message: `[associations] ${failed.length} of ${items.length} ${itemNoun}s were not attached`,
3754
+ context: { token, failed }
3755
+ });
3756
+ }
3757
+ } finally {
3758
+ setBusy(false);
3759
+ }
3760
+ },
3761
+ [
3762
+ createdLocationLabel,
3763
+ itemNoun,
3764
+ notifier,
3765
+ onAttach,
3766
+ openCreatedLocation,
3767
+ store,
3768
+ token
3769
+ ]
3770
+ );
3771
+ const toggle = useCallback3(
3772
+ async (item) => {
3773
+ setBusy(true);
3774
+ try {
3775
+ const detaching = attachedIds.has(item.id);
3776
+ const result = detaching ? await onDetach(item.id) : await onAttach(item.id, item.name);
3777
+ if (!result.ok) {
3778
+ const verb = detaching ? "detach" : "attach";
3779
+ notifier.error(
3780
+ `Couldn't ${verb} "${item.name}"` + (result.error ? `: ${result.error}` : "")
3781
+ );
3782
+ store.errorSink({
3783
+ code: detaching ? "picker_detach_failed" : "picker_attach_failed",
3784
+ message: `[associations] ${verb} refused for "${item.name}"`,
3785
+ context: { token, id: item.id, error: result.error }
3786
+ });
3787
+ }
3788
+ } catch (error) {
3789
+ store.errorSink({
3790
+ code: "picker_toggle_threw",
3791
+ message: `[associations] toggling ${itemNoun} "${item.name}" threw`,
3792
+ context: { token, id: item.id, detail: error }
3793
+ });
3794
+ notifier.error(`Couldn't update "${item.name}"`);
3795
+ } finally {
3796
+ setBusy(false);
3797
+ }
3798
+ },
3799
+ [attachedIds, itemNoun, notifier, onAttach, onDetach, store, token]
3800
+ );
3801
+ return { attachMany, toggle, busy };
3802
+ }
3803
+
3209
3804
  // src/react/components/AssociationEntitySelect.tsx
3210
- import { useState as useState12 } from "react";
3805
+ import { useState as useState14 } from "react";
3211
3806
  import {
3212
3807
  cn as cn10,
3213
3808
  Command,
@@ -3221,7 +3816,7 @@ import {
3221
3816
  PopoverContent,
3222
3817
  PopoverTrigger
3223
3818
  } from "@ai-matrx/design-system";
3224
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
3819
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
3225
3820
  function AssociationEntitySelect({
3226
3821
  token,
3227
3822
  adapter,
@@ -3235,19 +3830,17 @@ function AssociationEntitySelect({
3235
3830
  createSlot
3236
3831
  }) {
3237
3832
  const store = useAssociationsStore();
3238
- const { entityDoors } = useAssociationsUiPorts();
3239
3833
  const notifier = useNotifier();
3240
3834
  const info = store.registry.getEntityInfo(token);
3241
3835
  const InfoIcon = info.Icon ?? DefaultEntityIcon;
3242
- const DoorControls = entityDoors?.DoorControls;
3243
3836
  const { items, activeId } = adapter;
3244
3837
  const active = items.find((i) => i.id === activeId) ?? null;
3245
3838
  const activeIndex = active ? items.indexOf(active) : -1;
3246
- const [open, setOpen] = useState12(false);
3247
- const [query, setQuery] = useState12("");
3248
- const [creating, setCreating] = useState12(false);
3249
- const [draftName, setDraftName] = useState12("");
3250
- const [busy, setBusy] = useState12(false);
3839
+ const [open, setOpen] = useState14(false);
3840
+ const [query, setQuery] = useState14("");
3841
+ const [creating, setCreating] = useState14(false);
3842
+ const [draftName, setDraftName] = useState14("");
3843
+ const [busy, setBusy] = useState14(false);
3251
3844
  const entityLabel = info.label.toLowerCase();
3252
3845
  const close = () => {
3253
3846
  setOpen(false);
@@ -3264,7 +3857,7 @@ function AssociationEntitySelect({
3264
3857
  if (id) close();
3265
3858
  else notifier.error(`Couldn't create the ${entityLabel}`);
3266
3859
  };
3267
- return /* @__PURE__ */ jsxs11(
3860
+ return /* @__PURE__ */ jsxs12(
3268
3861
  "div",
3269
3862
  {
3270
3863
  className: cn10(
@@ -3272,7 +3865,7 @@ function AssociationEntitySelect({
3272
3865
  className
3273
3866
  ),
3274
3867
  children: [
3275
- showIcon ? /* @__PURE__ */ jsx13(
3868
+ showIcon ? /* @__PURE__ */ jsx15(
3276
3869
  InfoIcon,
3277
3870
  {
3278
3871
  className: cn10(
@@ -3282,7 +3875,7 @@ function AssociationEntitySelect({
3282
3875
  "aria-hidden": true
3283
3876
  }
3284
3877
  ) : null,
3285
- active ? /* @__PURE__ */ jsx13(
3878
+ active ? /* @__PURE__ */ jsx15(
3286
3879
  EditableLabel,
3287
3880
  {
3288
3881
  value: active.title,
@@ -3301,8 +3894,8 @@ function AssociationEntitySelect({
3301
3894
  inputClassName: "text-xs font-medium"
3302
3895
  }
3303
3896
  ) : null,
3304
- active && DoorControls ? /* @__PURE__ */ jsx13(DoorControls, { token, id: active.id, name: active.title }) : null,
3305
- !active ? /* @__PURE__ */ jsx13(
3897
+ active ? /* @__PURE__ */ jsx15(DoorControlsSlot, { token, id: active.id, name: active.title }) : null,
3898
+ !active ? /* @__PURE__ */ jsx15(
3306
3899
  "span",
3307
3900
  {
3308
3901
  className: cn10(
@@ -3312,13 +3905,13 @@ function AssociationEntitySelect({
3312
3905
  children: adapter.loading ? "\u2026" : emptyLabel ?? info.labelPlural
3313
3906
  }
3314
3907
  ) : null,
3315
- /* @__PURE__ */ jsxs11(
3908
+ /* @__PURE__ */ jsxs12(
3316
3909
  Popover,
3317
3910
  {
3318
3911
  open,
3319
3912
  onOpenChange: (next) => next ? setOpen(true) : close(),
3320
3913
  children: [
3321
- /* @__PURE__ */ jsx13(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
3914
+ /* @__PURE__ */ jsx15(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(
3322
3915
  "button",
3323
3916
  {
3324
3917
  type: "button",
@@ -3326,17 +3919,17 @@ function AssociationEntitySelect({
3326
3919
  title: `Switch or add ${info.labelPlural.toLowerCase()}`,
3327
3920
  "aria-label": `Switch or add ${info.labelPlural.toLowerCase()}`,
3328
3921
  children: [
3329
- items.length > 1 ? /* @__PURE__ */ jsxs11("span", { className: "tabular-nums", children: [
3922
+ items.length > 1 ? /* @__PURE__ */ jsxs12("span", { className: "tabular-nums", children: [
3330
3923
  activeIndex >= 0 ? activeIndex + 1 : "\u2014",
3331
3924
  "/",
3332
3925
  items.length
3333
3926
  ] }) : null,
3334
- /* @__PURE__ */ jsx13(ChevronDownIcon, { className: "size-3 opacity-60" })
3927
+ /* @__PURE__ */ jsx15(ChevronDownIcon, { className: "size-3 opacity-60" })
3335
3928
  ]
3336
3929
  }
3337
3930
  ) }),
3338
- /* @__PURE__ */ jsx13(PopoverContent, { className: "w-60 p-0", align, children: /* @__PURE__ */ jsxs11(Command, { children: [
3339
- items.length > 5 ? /* @__PURE__ */ jsx13(
3931
+ /* @__PURE__ */ jsx15(PopoverContent, { className: "w-60 p-0", align, children: /* @__PURE__ */ jsxs12(Command, { children: [
3932
+ items.length > 5 ? /* @__PURE__ */ jsx15(
3340
3933
  CommandInput,
3341
3934
  {
3342
3935
  value: query,
@@ -3344,9 +3937,9 @@ function AssociationEntitySelect({
3344
3937
  placeholder: `Search ${info.labelPlural.toLowerCase()}\u2026`
3345
3938
  }
3346
3939
  ) : null,
3347
- /* @__PURE__ */ jsxs11(CommandList, { children: [
3348
- /* @__PURE__ */ jsx13(CommandEmpty, { children: "No match." }),
3349
- items.length > 0 ? /* @__PURE__ */ jsx13(CommandGroup, { children: items.map((item) => /* @__PURE__ */ jsxs11(
3940
+ /* @__PURE__ */ jsxs12(CommandList, { children: [
3941
+ /* @__PURE__ */ jsx15(CommandEmpty, { children: "No match." }),
3942
+ items.length > 0 ? /* @__PURE__ */ jsx15(CommandGroup, { children: items.map((item) => /* @__PURE__ */ jsxs12(
3350
3943
  CommandItem,
3351
3944
  {
3352
3945
  value: `${item.title} ${item.id}`,
@@ -3357,7 +3950,7 @@ function AssociationEntitySelect({
3357
3950
  },
3358
3951
  className: "group/entity-ref group gap-2",
3359
3952
  children: [
3360
- /* @__PURE__ */ jsx13(
3953
+ /* @__PURE__ */ jsx15(
3361
3954
  CheckIcon,
3362
3955
  {
3363
3956
  className: cn10(
@@ -3366,8 +3959,8 @@ function AssociationEntitySelect({
3366
3959
  )
3367
3960
  }
3368
3961
  ),
3369
- /* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate", children: item.title }),
3370
- DoorControls ? /* @__PURE__ */ jsx13(
3962
+ /* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate", children: item.title }),
3963
+ /* @__PURE__ */ jsx15(
3371
3964
  "span",
3372
3965
  {
3373
3966
  className: "inline-flex shrink-0 items-center",
@@ -3375,8 +3968,8 @@ function AssociationEntitySelect({
3375
3968
  e.preventDefault();
3376
3969
  e.stopPropagation();
3377
3970
  },
3378
- children: /* @__PURE__ */ jsx13(
3379
- DoorControls,
3971
+ children: /* @__PURE__ */ jsx15(
3972
+ DoorControlsSlot,
3380
3973
  {
3381
3974
  token,
3382
3975
  id: item.id,
@@ -3384,8 +3977,8 @@ function AssociationEntitySelect({
3384
3977
  }
3385
3978
  )
3386
3979
  }
3387
- ) : null,
3388
- adapter.detach && item.id !== activeId ? /* @__PURE__ */ jsx13(
3980
+ ),
3981
+ adapter.detach && item.id !== activeId ? /* @__PURE__ */ jsx15(
3389
3982
  "button",
3390
3983
  {
3391
3984
  type: "button",
@@ -3400,7 +3993,7 @@ function AssociationEntitySelect({
3400
3993
  className: "grid size-5 shrink-0 place-items-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-destructive group-hover:opacity-100",
3401
3994
  title: `Remove this ${entityLabel} from here (does not delete it)`,
3402
3995
  "aria-label": `Remove ${item.title}`,
3403
- children: /* @__PURE__ */ jsx13(XIcon, { className: "size-3" })
3996
+ children: /* @__PURE__ */ jsx15(XIcon, { className: "size-3" })
3404
3997
  }
3405
3998
  ) : null
3406
3999
  ]
@@ -3408,9 +4001,9 @@ function AssociationEntitySelect({
3408
4001
  item.id
3409
4002
  )) }) : null
3410
4003
  ] }),
3411
- createSlot !== void 0 ? /* @__PURE__ */ jsx13("div", { className: "border-t border-border p-1", children: typeof createSlot === "function" ? createSlot(close) : createSlot }) : null,
3412
- createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ jsx13("div", { className: "border-t border-border p-1", children: creating ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 px-1 py-0.5", children: [
3413
- /* @__PURE__ */ jsx13(
4004
+ createSlot !== void 0 ? /* @__PURE__ */ jsx15("div", { className: "border-t border-border p-1", children: typeof createSlot === "function" ? createSlot(close) : createSlot }) : null,
4005
+ createSlot === void 0 && adapter.createAndAttach ? /* @__PURE__ */ jsx15("div", { className: "border-t border-border p-1", children: creating ? /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1 px-1 py-0.5", children: [
4006
+ /* @__PURE__ */ jsx15(
3414
4007
  "input",
3415
4008
  {
3416
4009
  autoFocus: true,
@@ -3434,17 +4027,17 @@ function AssociationEntitySelect({
3434
4027
  "aria-label": `New ${entityLabel} name`
3435
4028
  }
3436
4029
  ),
3437
- /* @__PURE__ */ jsx13(
4030
+ /* @__PURE__ */ jsx15(
3438
4031
  "button",
3439
4032
  {
3440
4033
  type: "button",
3441
4034
  disabled: busy || !draftName.trim(),
3442
4035
  onClick: () => void create(draftName),
3443
4036
  className: "inline-flex h-6 shrink-0 items-center rounded-md px-1.5 text-[10px] font-medium text-primary transition-colors hover:bg-accent disabled:opacity-50",
3444
- children: busy ? /* @__PURE__ */ jsx13(SpinnerIcon, { className: "size-3 animate-spin" }) : "Create"
4037
+ children: busy ? /* @__PURE__ */ jsx15(SpinnerIcon, { className: "size-3 animate-spin" }) : "Create"
3445
4038
  }
3446
4039
  )
3447
- ] }) : /* @__PURE__ */ jsxs11(
4040
+ ] }) : /* @__PURE__ */ jsxs12(
3448
4041
  "button",
3449
4042
  {
3450
4043
  type: "button",
@@ -3455,7 +4048,7 @@ function AssociationEntitySelect({
3455
4048
  },
3456
4049
  className: "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
3457
4050
  children: [
3458
- busy ? /* @__PURE__ */ jsx13(SpinnerIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx13(PlusIcon, { className: "size-3.5" }),
4051
+ busy ? /* @__PURE__ */ jsx15(SpinnerIcon, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx15(PlusIcon, { className: "size-3.5" }),
3459
4052
  query.trim() ? `Create "${query.trim()}"` : `New ${info.label}`
3460
4053
  ]
3461
4054
  }
@@ -3470,7 +4063,7 @@ function AssociationEntitySelect({
3470
4063
  }
3471
4064
 
3472
4065
  // src/react/components/CategorySelect.tsx
3473
- import { useState as useState13 } from "react";
4066
+ import { useState as useState15 } from "react";
3474
4067
  import {
3475
4068
  CreatablePicker,
3476
4069
  Select,
@@ -3545,7 +4138,7 @@ function buildCategoryHierarchy(categories) {
3545
4138
  }
3546
4139
 
3547
4140
  // src/react/components/CategorySelect.tsx
3548
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
4141
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
3549
4142
  var NONE = "__none__";
3550
4143
  var ROOT_PARENT = "__root__";
3551
4144
  function plural(noun) {
@@ -3572,7 +4165,7 @@ function CategorySelect({
3572
4165
  reload
3573
4166
  } = useCategories({ dimension });
3574
4167
  const hierarchy = buildCategoryHierarchy(categories);
3575
- const [createParentId, setCreateParentId] = useState13(ROOT_PARENT);
4168
+ const [createParentId, setCreateParentId] = useState15(ROOT_PARENT);
3576
4169
  const options = [
3577
4170
  ...allowNone ? [{ value: NONE, label: "None", keywords: "none clear empty" }] : [],
3578
4171
  ...hierarchy.hasHierarchy ? hierarchy.items.map(({ category, depth, parent }) => ({
@@ -3581,9 +4174,9 @@ function CategorySelect({
3581
4174
  // The type-ahead matches the parent's name too, so someone who knows
3582
4175
  // the branch but not the leaf still finds it.
3583
4176
  keywords: parent ? parent.name : "",
3584
- render: depth === 0 ? /* @__PURE__ */ jsx14("span", { className: "font-medium", children: category.name }) : /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1.5 pl-3 text-muted-foreground", children: [
3585
- /* @__PURE__ */ jsx14(CornerDownRightIcon, { className: "h-3.5 w-3.5 shrink-0" }),
3586
- /* @__PURE__ */ jsx14("span", { className: "text-foreground", children: category.name })
4177
+ render: depth === 0 ? /* @__PURE__ */ jsx16("span", { className: "font-medium", children: category.name }) : /* @__PURE__ */ jsxs13("span", { className: "flex items-center gap-1.5 pl-3 text-muted-foreground", children: [
4178
+ /* @__PURE__ */ jsx16(CornerDownRightIcon, { className: "h-3.5 w-3.5 shrink-0" }),
4179
+ /* @__PURE__ */ jsx16("span", { className: "text-foreground", children: category.name })
3587
4180
  ] })
3588
4181
  })) : categories.map((category) => ({
3589
4182
  value: category.id,
@@ -3630,8 +4223,8 @@ function CategorySelect({
3630
4223
  );
3631
4224
  return result.id;
3632
4225
  };
3633
- return /* @__PURE__ */ jsxs12("div", { children: [
3634
- /* @__PURE__ */ jsx14(
4226
+ return /* @__PURE__ */ jsxs13("div", { children: [
4227
+ /* @__PURE__ */ jsx16(
3635
4228
  CreatablePicker,
3636
4229
  {
3637
4230
  value: value ?? (allowNone ? NONE : null),
@@ -3647,18 +4240,18 @@ function CategorySelect({
3647
4240
  emptyLabel: `No ${noun} matches that.`,
3648
4241
  ...allowCreate ? { onCreate: create } : {},
3649
4242
  ...allowCreate && hierarchy.hasHierarchy ? {
3650
- createExtra: /* @__PURE__ */ jsxs12(Select, { value: createParentId, onValueChange: setCreateParentId, children: [
3651
- /* @__PURE__ */ jsx14(
4243
+ createExtra: /* @__PURE__ */ jsxs13(Select, { value: createParentId, onValueChange: setCreateParentId, children: [
4244
+ /* @__PURE__ */ jsx16(
3652
4245
  SelectTrigger,
3653
4246
  {
3654
4247
  className: "h-7 text-xs",
3655
4248
  "aria-label": `Put the new ${noun} under`,
3656
- children: /* @__PURE__ */ jsx14(SelectValue, {})
4249
+ children: /* @__PURE__ */ jsx16(SelectValue, {})
3657
4250
  }
3658
4251
  ),
3659
- /* @__PURE__ */ jsxs12(SelectContent, { children: [
3660
- /* @__PURE__ */ jsx14(SelectItem, { value: ROOT_PARENT, className: "text-xs", children: "Top level" }),
3661
- hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ jsxs12(
4252
+ /* @__PURE__ */ jsxs13(SelectContent, { children: [
4253
+ /* @__PURE__ */ jsx16(SelectItem, { value: ROOT_PARENT, className: "text-xs", children: "Top level" }),
4254
+ hierarchy.items.filter((item) => item.depth === 0).map((item) => /* @__PURE__ */ jsxs13(
3662
4255
  SelectItem,
3663
4256
  {
3664
4257
  value: item.category.id,
@@ -3678,18 +4271,18 @@ function CategorySelect({
3678
4271
  selected === null && value !== null ? (
3679
4272
  // A stored id whose row this reader cannot see is not "nothing chosen":
3680
4273
  // saying so beats a blank box that looks like an unsaved field.
3681
- /* @__PURE__ */ jsxs12("p", { className: "mt-1 text-xs text-muted-foreground", children: [
4274
+ /* @__PURE__ */ jsxs13("p", { className: "mt-1 text-xs text-muted-foreground", children: [
3682
4275
  "This ",
3683
4276
  noun,
3684
4277
  " is no longer available to you."
3685
4278
  ] })
3686
4279
  ) : null,
3687
- error ? /* @__PURE__ */ jsx14("p", { className: "mt-1 text-xs text-destructive", children: error }) : null
4280
+ error ? /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs text-destructive", children: error }) : null
3688
4281
  ] });
3689
4282
  }
3690
4283
 
3691
4284
  // src/react/components/CategoryTagPicker.tsx
3692
- import { useState as useState14 } from "react";
4285
+ import { useState as useState16 } from "react";
3693
4286
  import {
3694
4287
  Badge,
3695
4288
  Button as Button2,
@@ -3709,7 +4302,7 @@ import {
3709
4302
  SelectTrigger as SelectTrigger2,
3710
4303
  SelectValue as SelectValue2
3711
4304
  } from "@ai-matrx/design-system";
3712
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
4305
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
3713
4306
  var ROOT_PARENT2 = "__root__";
3714
4307
  function CategoryTagPicker({
3715
4308
  entityType,
@@ -3725,11 +4318,11 @@ function CategoryTagPicker({
3725
4318
  }) {
3726
4319
  const store = useAssociationsStore();
3727
4320
  const notifier = useNotifier();
3728
- const [open, setOpen] = useState14(false);
3729
- const [creating, setCreating] = useState14(false);
3730
- const [writing, setWriting] = useState14(false);
3731
- const [search, setSearch] = useState14("");
3732
- const [createParentId, setCreateParentId] = useState14(ROOT_PARENT2);
4321
+ const [open, setOpen] = useState16(false);
4322
+ const [creating, setCreating] = useState16(false);
4323
+ const [writing, setWriting] = useState16(false);
4324
+ const [search, setSearch] = useState16("");
4325
+ const [createParentId, setCreateParentId] = useState16(ROOT_PARENT2);
3733
4326
  const {
3734
4327
  categories,
3735
4328
  create: createCategory,
@@ -3833,44 +4426,44 @@ function CategoryTagPicker({
3833
4426
  const exactMatch = categories.some(
3834
4427
  (c) => c.name.toLowerCase() === search.trim().toLowerCase()
3835
4428
  );
3836
- return /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap items-center gap-1.5", children: [
3837
- selected.map((c) => /* @__PURE__ */ jsxs13(
4429
+ return /* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-1.5", children: [
4430
+ selected.map((c) => /* @__PURE__ */ jsxs14(
3838
4431
  Badge,
3839
4432
  {
3840
4433
  variant: "secondary",
3841
4434
  className: "gap-1 pr-1 text-xs font-medium",
3842
4435
  children: [
3843
4436
  showHierarchy ? hierarchyById.get(c.id)?.displayName ?? c.name : c.name,
3844
- /* @__PURE__ */ jsx15(
4437
+ /* @__PURE__ */ jsx17(
3845
4438
  "button",
3846
4439
  {
3847
4440
  type: "button",
3848
4441
  onClick: () => void toggle(c.id),
3849
4442
  className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
3850
4443
  "aria-label": `Remove ${c.name}`,
3851
- children: /* @__PURE__ */ jsx15(XIcon, { className: "h-2.5 w-2.5" })
4444
+ children: /* @__PURE__ */ jsx17(XIcon, { className: "h-2.5 w-2.5" })
3852
4445
  }
3853
4446
  )
3854
4447
  ]
3855
4448
  },
3856
4449
  c.id
3857
4450
  )),
3858
- /* @__PURE__ */ jsxs13(Popover2, { open, onOpenChange: setOpen, children: [
3859
- /* @__PURE__ */ jsx15(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs13(
4451
+ /* @__PURE__ */ jsxs14(Popover2, { open, onOpenChange: setOpen, children: [
4452
+ /* @__PURE__ */ jsx17(PopoverTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs14(
3860
4453
  Button2,
3861
4454
  {
3862
4455
  variant: "outline",
3863
4456
  size: "sm",
3864
4457
  className: "h-7 gap-1 px-2 text-xs",
3865
4458
  children: [
3866
- /* @__PURE__ */ jsx15(Icon, { className: "h-3.5 w-3.5" }),
4459
+ /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" }),
3867
4460
  selected.length === 0 ? addLabel : "Edit",
3868
- /* @__PURE__ */ jsx15(ChevronsUpDownIcon, { className: "h-3 w-3 opacity-50" })
4461
+ /* @__PURE__ */ jsx17(ChevronsUpDownIcon, { className: "h-3 w-3 opacity-50" })
3869
4462
  ]
3870
4463
  }
3871
4464
  ) }),
3872
- /* @__PURE__ */ jsx15(PopoverContent2, { className: "w-56 p-0", align: "start", children: /* @__PURE__ */ jsxs13(Command2, { shouldFilter: false, children: [
3873
- /* @__PURE__ */ jsx15(
4465
+ /* @__PURE__ */ jsx17(PopoverContent2, { className: "w-56 p-0", align: "start", children: /* @__PURE__ */ jsxs14(Command2, { shouldFilter: false, children: [
4466
+ /* @__PURE__ */ jsx17(
3874
4467
  CommandInput2,
3875
4468
  {
3876
4469
  placeholder: allowCreate ? "Search or create..." : "Search...",
@@ -3878,9 +4471,9 @@ function CategoryTagPicker({
3878
4471
  onValueChange: setSearch
3879
4472
  }
3880
4473
  ),
3881
- /* @__PURE__ */ jsxs13(CommandList2, { children: [
3882
- /* @__PURE__ */ jsx15(CommandEmpty2, { className: "px-2 py-3 text-xs text-muted-foreground", children: search.trim() ? "No match." : emptyText }),
3883
- /* @__PURE__ */ jsx15(CommandGroup2, { children: showHierarchy ? filteredHierarchy.map(({ category, depth, parent }) => /* @__PURE__ */ jsxs13(
4474
+ /* @__PURE__ */ jsxs14(CommandList2, { children: [
4475
+ /* @__PURE__ */ jsx17(CommandEmpty2, { className: "px-2 py-3 text-xs text-muted-foreground", children: search.trim() ? "No match." : emptyText }),
4476
+ /* @__PURE__ */ jsx17(CommandGroup2, { children: showHierarchy ? filteredHierarchy.map(({ category, depth, parent }) => /* @__PURE__ */ jsxs14(
3884
4477
  CommandItem2,
3885
4478
  {
3886
4479
  value: category.id,
@@ -3888,7 +4481,7 @@ function CategoryTagPicker({
3888
4481
  onSelect: () => void toggle(category.id),
3889
4482
  className: cn11("text-xs", depth === 1 && "pl-6"),
3890
4483
  children: [
3891
- /* @__PURE__ */ jsx15(
4484
+ /* @__PURE__ */ jsx17(
3892
4485
  CheckIcon,
3893
4486
  {
3894
4487
  className: cn11(
@@ -3897,19 +4490,19 @@ function CategoryTagPicker({
3897
4490
  )
3898
4491
  }
3899
4492
  ),
3900
- depth === 1 ? /* @__PURE__ */ jsx15(CornerDownRightIcon, { className: "mr-1.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }) : null,
3901
- /* @__PURE__ */ jsx15("span", { className: cn11(depth === 0 && "font-medium"), children: category.name })
4493
+ depth === 1 ? /* @__PURE__ */ jsx17(CornerDownRightIcon, { className: "mr-1.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }) : null,
4494
+ /* @__PURE__ */ jsx17("span", { className: cn11(depth === 0 && "font-medium"), children: category.name })
3902
4495
  ]
3903
4496
  },
3904
4497
  category.id
3905
- )) : filtered.map((c) => /* @__PURE__ */ jsxs13(
4498
+ )) : filtered.map((c) => /* @__PURE__ */ jsxs14(
3906
4499
  CommandItem2,
3907
4500
  {
3908
4501
  value: c.id,
3909
4502
  onSelect: () => void toggle(c.id),
3910
4503
  className: "text-xs",
3911
4504
  children: [
3912
- /* @__PURE__ */ jsx15(
4505
+ /* @__PURE__ */ jsx17(
3913
4506
  CheckIcon,
3914
4507
  {
3915
4508
  className: cn11(
@@ -3923,25 +4516,25 @@ function CategoryTagPicker({
3923
4516
  },
3924
4517
  c.id
3925
4518
  )) }),
3926
- allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ jsxs13(CommandGroup2, { children: [
3927
- showHierarchy ? /* @__PURE__ */ jsxs13("div", { className: "space-y-1.5 px-2 pb-2", children: [
3928
- /* @__PURE__ */ jsx15("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Place in" }),
3929
- /* @__PURE__ */ jsxs13(
4519
+ allowCreate && search.trim() && !exactMatch ? /* @__PURE__ */ jsxs14(CommandGroup2, { children: [
4520
+ showHierarchy ? /* @__PURE__ */ jsxs14("div", { className: "space-y-1.5 px-2 pb-2", children: [
4521
+ /* @__PURE__ */ jsx17("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Place in" }),
4522
+ /* @__PURE__ */ jsxs14(
3930
4523
  Select2,
3931
4524
  {
3932
4525
  value: createParentId,
3933
4526
  onValueChange: setCreateParentId,
3934
4527
  children: [
3935
- /* @__PURE__ */ jsx15(SelectTrigger2, { size: "sm", className: "bg-background", children: /* @__PURE__ */ jsx15(SelectValue2, {}) }),
3936
- /* @__PURE__ */ jsxs13(SelectContent2, { children: [
3937
- /* @__PURE__ */ jsx15(SelectItem2, { value: ROOT_PARENT2, children: "Top level" }),
3938
- hierarchy.roots.map((root) => /* @__PURE__ */ jsx15(SelectItem2, { value: root.id, children: root.name }, root.id))
4528
+ /* @__PURE__ */ jsx17(SelectTrigger2, { size: "sm", className: "bg-background", children: /* @__PURE__ */ jsx17(SelectValue2, {}) }),
4529
+ /* @__PURE__ */ jsxs14(SelectContent2, { children: [
4530
+ /* @__PURE__ */ jsx17(SelectItem2, { value: ROOT_PARENT2, children: "Top level" }),
4531
+ hierarchy.roots.map((root) => /* @__PURE__ */ jsx17(SelectItem2, { value: root.id, children: root.name }, root.id))
3939
4532
  ] })
3940
4533
  ]
3941
4534
  }
3942
4535
  )
3943
4536
  ] }) : null,
3944
- /* @__PURE__ */ jsxs13(
4537
+ /* @__PURE__ */ jsxs14(
3945
4538
  CommandItem2,
3946
4539
  {
3947
4540
  value: `__create__${search}`,
@@ -3949,7 +4542,7 @@ function CategoryTagPicker({
3949
4542
  disabled: creating,
3950
4543
  className: "text-xs text-primary",
3951
4544
  children: [
3952
- creating ? /* @__PURE__ */ jsx15(SpinnerIcon, { className: "mr-2 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx15(Icon, { className: "mr-2 h-3.5 w-3.5" }),
4545
+ creating ? /* @__PURE__ */ jsx17(SpinnerIcon, { className: "mr-2 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx17(Icon, { className: "mr-2 h-3.5 w-3.5" }),
3953
4546
  "Create \u201C",
3954
4547
  search.trim(),
3955
4548
  "\u201D"
@@ -3964,7 +4557,7 @@ function CategoryTagPicker({
3964
4557
  }
3965
4558
 
3966
4559
  // src/react/components/CommentThread.tsx
3967
- import { useState as useState15 } from "react";
4560
+ import { useState as useState17 } from "react";
3968
4561
  import { Button as Button3, Skeleton as Skeleton2, cn as cn12 } from "@ai-matrx/design-system";
3969
4562
 
3970
4563
  // src/react/relativeTime.ts
@@ -3992,7 +4585,7 @@ function formatRelativeTime(iso, now = Date.now()) {
3992
4585
  }
3993
4586
 
3994
4587
  // src/react/components/CommentThread.tsx
3995
- import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
4588
+ import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
3996
4589
  var AUTHOR_DOOR_TOKEN = "user";
3997
4590
  function resolveAuthor(comment, authorDisplay) {
3998
4591
  const base2 = {
@@ -4011,7 +4604,7 @@ function resolveAuthor(comment, authorDisplay) {
4011
4604
  }
4012
4605
  function AuthorAvatar({ author }) {
4013
4606
  if (author.avatarUrl) {
4014
- return /* @__PURE__ */ jsx16(
4607
+ return /* @__PURE__ */ jsx18(
4015
4608
  "img",
4016
4609
  {
4017
4610
  src: author.avatarUrl,
@@ -4020,7 +4613,7 @@ function AuthorAvatar({ author }) {
4020
4613
  }
4021
4614
  );
4022
4615
  }
4023
- return /* @__PURE__ */ jsx16(
4616
+ return /* @__PURE__ */ jsx18(
4024
4617
  "span",
4025
4618
  {
4026
4619
  "aria-hidden": true,
@@ -4035,7 +4628,7 @@ function AuthorName({
4035
4628
  }) {
4036
4629
  const DoorRef2 = entityDoors?.EntityRef;
4037
4630
  if (DoorRef2 && author.userId) {
4038
- return /* @__PURE__ */ jsx16(
4631
+ return /* @__PURE__ */ jsx18(
4039
4632
  DoorRef2,
4040
4633
  {
4041
4634
  token: AUTHOR_DOOR_TOKEN,
@@ -4046,7 +4639,7 @@ function AuthorName({
4046
4639
  }
4047
4640
  );
4048
4641
  }
4049
- return /* @__PURE__ */ jsx16("span", { className: "text-sm font-medium text-foreground", children: author.name });
4642
+ return /* @__PURE__ */ jsx18("span", { className: "text-sm font-medium text-foreground", children: author.name });
4050
4643
  }
4051
4644
  function CommentComposer({
4052
4645
  onSubmit,
@@ -4057,9 +4650,9 @@ function CommentComposer({
4057
4650
  autoFocus = false
4058
4651
  }) {
4059
4652
  const notifier = useNotifier();
4060
- const [body, setBody] = useState15(initialValue);
4061
- const [submitting, setSubmitting] = useState15(false);
4062
- const [error, setError] = useState15(null);
4653
+ const [body, setBody] = useState17(initialValue);
4654
+ const [submitting, setSubmitting] = useState17(false);
4655
+ const [error, setError] = useState17(null);
4063
4656
  async function submit(e) {
4064
4657
  e?.preventDefault();
4065
4658
  const trimmed = body.trim();
@@ -4076,8 +4669,8 @@ function CommentComposer({
4076
4669
  }
4077
4670
  setBody("");
4078
4671
  }
4079
- return /* @__PURE__ */ jsxs14("form", { onSubmit: submit, className: "flex flex-col gap-1.5", children: [
4080
- /* @__PURE__ */ jsx16(
4672
+ return /* @__PURE__ */ jsxs15("form", { onSubmit: submit, className: "flex flex-col gap-1.5", children: [
4673
+ /* @__PURE__ */ jsx18(
4081
4674
  "textarea",
4082
4675
  {
4083
4676
  value: body,
@@ -4092,10 +4685,10 @@ function CommentComposer({
4092
4685
  className: "w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
4093
4686
  }
4094
4687
  ),
4095
- error && /* @__PURE__ */ jsx16("p", { role: "alert", className: "text-xs text-destructive", children: error }),
4096
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
4097
- /* @__PURE__ */ jsxs14(Button3, { type: "submit", size: "sm", disabled: !body.trim() || submitting, children: [
4098
- submitting && /* @__PURE__ */ jsx16(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
4688
+ error && /* @__PURE__ */ jsx18("p", { role: "alert", className: "text-xs text-destructive", children: error }),
4689
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
4690
+ /* @__PURE__ */ jsxs15(Button3, { type: "submit", size: "sm", disabled: !body.trim() || submitting, children: [
4691
+ submitting && /* @__PURE__ */ jsx18(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
4099
4692
  submitLabel
4100
4693
  ] }),
4101
4694
  trailing
@@ -4111,10 +4704,10 @@ function CommentItem({
4111
4704
  }) {
4112
4705
  const { authorDisplay, entityDoors } = useAssociationsUiPorts();
4113
4706
  const notifier = useNotifier();
4114
- const [replying, setReplying] = useState15(false);
4115
- const [editing, setEditing] = useState15(false);
4116
- const [confirmingDelete, setConfirmingDelete] = useState15(false);
4117
- const [deleting, setDeleting] = useState15(false);
4707
+ const [replying, setReplying] = useState17(false);
4708
+ const [editing, setEditing] = useState17(false);
4709
+ const [confirmingDelete, setConfirmingDelete] = useState17(false);
4710
+ const [deleting, setDeleting] = useState17(false);
4118
4711
  const author = resolveAuthor(comment, authorDisplay);
4119
4712
  const isOwn = thread.currentUserId !== null && comment.createdBy === thread.currentUserId;
4120
4713
  const edited = comment.updatedAt !== comment.createdAt;
@@ -4128,7 +4721,7 @@ function CommentItem({
4128
4721
  notifier.error(res.error ?? "Could not delete the comment");
4129
4722
  }
4130
4723
  }
4131
- return /* @__PURE__ */ jsxs14(
4724
+ return /* @__PURE__ */ jsxs15(
4132
4725
  "div",
4133
4726
  {
4134
4727
  "data-comment-id": comment.id,
@@ -4137,10 +4730,10 @@ function CommentItem({
4137
4730
  depth > 0 && "border-l border-border pl-3"
4138
4731
  ),
4139
4732
  children: [
4140
- /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
4141
- /* @__PURE__ */ jsx16(AuthorAvatar, { author }),
4142
- /* @__PURE__ */ jsx16(AuthorName, { author, entityDoors }),
4143
- /* @__PURE__ */ jsx16(
4733
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
4734
+ /* @__PURE__ */ jsx18(AuthorAvatar, { author }),
4735
+ /* @__PURE__ */ jsx18(AuthorName, { author, entityDoors }),
4736
+ /* @__PURE__ */ jsx18(
4144
4737
  "span",
4145
4738
  {
4146
4739
  className: "text-xs text-muted-foreground",
@@ -4148,7 +4741,7 @@ function CommentItem({
4148
4741
  children: formatRelativeTime(comment.createdAt)
4149
4742
  }
4150
4743
  ),
4151
- edited && /* @__PURE__ */ jsx16(
4744
+ edited && /* @__PURE__ */ jsx18(
4152
4745
  "span",
4153
4746
  {
4154
4747
  className: "text-xs text-muted-foreground",
@@ -4157,7 +4750,7 @@ function CommentItem({
4157
4750
  }
4158
4751
  )
4159
4752
  ] }),
4160
- editing ? /* @__PURE__ */ jsx16("div", { className: "pl-8", children: /* @__PURE__ */ jsx16(
4753
+ editing ? /* @__PURE__ */ jsx18("div", { className: "pl-8", children: /* @__PURE__ */ jsx18(
4161
4754
  CommentComposer,
4162
4755
  {
4163
4756
  initialValue: comment.body,
@@ -4169,7 +4762,7 @@ function CommentItem({
4169
4762
  if (res.ok) setEditing(false);
4170
4763
  return res;
4171
4764
  },
4172
- trailing: /* @__PURE__ */ jsx16(
4765
+ trailing: /* @__PURE__ */ jsx18(
4173
4766
  Button3,
4174
4767
  {
4175
4768
  type: "button",
@@ -4180,10 +4773,10 @@ function CommentItem({
4180
4773
  }
4181
4774
  )
4182
4775
  }
4183
- ) }) : /* @__PURE__ */ jsx16("p", { className: "whitespace-pre-wrap pl-8 text-sm text-foreground", children: comment.body }),
4184
- !editing && /* @__PURE__ */ jsx16("div", { className: "flex items-center gap-1 pl-7", children: confirmingDelete ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
4185
- /* @__PURE__ */ jsx16("span", { className: "text-xs text-destructive", children: "Deletes this comment for everyone." }),
4186
- /* @__PURE__ */ jsxs14(
4776
+ ) }) : /* @__PURE__ */ jsx18("p", { className: "whitespace-pre-wrap pl-8 text-sm text-foreground", children: comment.body }),
4777
+ !editing && /* @__PURE__ */ jsx18("div", { className: "flex items-center gap-1 pl-7", children: confirmingDelete ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
4778
+ /* @__PURE__ */ jsx18("span", { className: "text-xs text-destructive", children: "Deletes this comment for everyone." }),
4779
+ /* @__PURE__ */ jsxs15(
4187
4780
  Button3,
4188
4781
  {
4189
4782
  type: "button",
@@ -4192,12 +4785,12 @@ function CommentItem({
4192
4785
  disabled: deleting,
4193
4786
  onClick: () => void confirmDelete(),
4194
4787
  children: [
4195
- deleting && /* @__PURE__ */ jsx16(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
4788
+ deleting && /* @__PURE__ */ jsx18(SpinnerIcon, { className: "mr-1 h-3 w-3 animate-spin" }),
4196
4789
  "Delete"
4197
4790
  ]
4198
4791
  }
4199
4792
  ),
4200
- /* @__PURE__ */ jsx16(
4793
+ /* @__PURE__ */ jsx18(
4201
4794
  Button3,
4202
4795
  {
4203
4796
  type: "button",
@@ -4208,8 +4801,8 @@ function CommentItem({
4208
4801
  children: "Cancel"
4209
4802
  }
4210
4803
  )
4211
- ] }) : /* @__PURE__ */ jsxs14(Fragment5, { children: [
4212
- /* @__PURE__ */ jsx16(
4804
+ ] }) : /* @__PURE__ */ jsxs15(Fragment5, { children: [
4805
+ /* @__PURE__ */ jsx18(
4213
4806
  "button",
4214
4807
  {
4215
4808
  type: "button",
@@ -4218,8 +4811,8 @@ function CommentItem({
4218
4811
  children: "Reply"
4219
4812
  }
4220
4813
  ),
4221
- isOwn && /* @__PURE__ */ jsxs14(Fragment5, { children: [
4222
- /* @__PURE__ */ jsx16(
4814
+ isOwn && /* @__PURE__ */ jsxs15(Fragment5, { children: [
4815
+ /* @__PURE__ */ jsx18(
4223
4816
  "button",
4224
4817
  {
4225
4818
  type: "button",
@@ -4228,7 +4821,7 @@ function CommentItem({
4228
4821
  children: "Edit"
4229
4822
  }
4230
4823
  ),
4231
- /* @__PURE__ */ jsx16(
4824
+ /* @__PURE__ */ jsx18(
4232
4825
  "button",
4233
4826
  {
4234
4827
  type: "button",
@@ -4239,9 +4832,9 @@ function CommentItem({
4239
4832
  )
4240
4833
  ] })
4241
4834
  ] }) }),
4242
- replying && /* @__PURE__ */ jsxs14("div", { className: "flex items-start gap-2 pl-8 pt-1", children: [
4243
- /* @__PURE__ */ jsx16(CornerDownRightIcon, { className: "mt-2 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
4244
- /* @__PURE__ */ jsx16("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx16(
4835
+ replying && /* @__PURE__ */ jsxs15("div", { className: "flex items-start gap-2 pl-8 pt-1", children: [
4836
+ /* @__PURE__ */ jsx18(CornerDownRightIcon, { className: "mt-2 h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
4837
+ /* @__PURE__ */ jsx18("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx18(
4245
4838
  CommentComposer,
4246
4839
  {
4247
4840
  submitLabel: "Reply",
@@ -4255,7 +4848,7 @@ function CommentItem({
4255
4848
  if (res.ok) setReplying(false);
4256
4849
  return res;
4257
4850
  },
4258
- trailing: /* @__PURE__ */ jsx16(
4851
+ trailing: /* @__PURE__ */ jsx18(
4259
4852
  Button3,
4260
4853
  {
4261
4854
  type: "button",
@@ -4268,7 +4861,7 @@ function CommentItem({
4268
4861
  }
4269
4862
  ) })
4270
4863
  ] }),
4271
- replies.length > 0 && /* @__PURE__ */ jsx16("div", { className: "flex flex-col gap-3 pl-8 pt-1", children: replies.map((reply) => /* @__PURE__ */ jsx16(
4864
+ replies.length > 0 && /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-3 pl-8 pt-1", children: replies.map((reply) => /* @__PURE__ */ jsx18(
4272
4865
  CommentItem,
4273
4866
  {
4274
4867
  comment: reply,
@@ -4308,11 +4901,11 @@ function CommentThread({
4308
4901
  const thread = useComments({ token, id });
4309
4902
  const { roots, childrenOf } = buildCommentTree(thread.comments);
4310
4903
  const loading = (thread.status === "loading" || thread.status === "idle") && thread.comments.length === 0;
4311
- return /* @__PURE__ */ jsxs14("section", { className: cn12("flex flex-col gap-3", className), children: [
4312
- showHeader && /* @__PURE__ */ jsxs14("header", { className: "flex items-center gap-2", children: [
4313
- /* @__PURE__ */ jsx16("h3", { className: "text-sm font-semibold text-foreground", children: "Comments" }),
4314
- /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground tabular-nums", children: thread.comments.length }),
4315
- /* @__PURE__ */ jsx16(
4904
+ return /* @__PURE__ */ jsxs15("section", { className: cn12("flex flex-col gap-3", className), children: [
4905
+ showHeader && /* @__PURE__ */ jsxs15("header", { className: "flex items-center gap-2", children: [
4906
+ /* @__PURE__ */ jsx18("h3", { className: "text-sm font-semibold text-foreground", children: "Comments" }),
4907
+ /* @__PURE__ */ jsx18("span", { className: "text-xs text-muted-foreground tabular-nums", children: thread.comments.length }),
4908
+ /* @__PURE__ */ jsx18(
4316
4909
  "button",
4317
4910
  {
4318
4911
  type: "button",
@@ -4320,18 +4913,18 @@ function CommentThread({
4320
4913
  "aria-label": "Refresh comments",
4321
4914
  title: "Refresh comments",
4322
4915
  className: "ml-auto flex h-6 w-6 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
4323
- children: thread.status === "loading" ? /* @__PURE__ */ jsx16(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx16(RefreshIcon, { className: "h-3.5 w-3.5" })
4916
+ children: thread.status === "loading" ? /* @__PURE__ */ jsx18(SpinnerIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx18(RefreshIcon, { className: "h-3.5 w-3.5" })
4324
4917
  }
4325
4918
  )
4326
4919
  ] }),
4327
- thread.error && /* @__PURE__ */ jsxs14(
4920
+ thread.error && /* @__PURE__ */ jsxs15(
4328
4921
  "div",
4329
4922
  {
4330
4923
  role: "alert",
4331
4924
  className: "flex items-center gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
4332
4925
  children: [
4333
- /* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1", children: thread.error }),
4334
- /* @__PURE__ */ jsx16(
4926
+ /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1", children: thread.error }),
4927
+ /* @__PURE__ */ jsx18(
4335
4928
  Button3,
4336
4929
  {
4337
4930
  type: "button",
@@ -4345,10 +4938,10 @@ function CommentThread({
4345
4938
  ]
4346
4939
  }
4347
4940
  ),
4348
- loading ? /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3", "aria-hidden": true, "data-testid": "comments-loading", children: [
4349
- /* @__PURE__ */ jsx16(Skeleton2, { className: "h-12 w-full" }),
4350
- /* @__PURE__ */ jsx16(Skeleton2, { className: "h-12 w-4/5" })
4351
- ] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground", children: "No comments yet." }) : /* @__PURE__ */ jsx16("div", { className: "flex flex-col gap-4", children: roots.map((comment) => /* @__PURE__ */ jsx16(
4941
+ loading ? /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3", "aria-hidden": true, "data-testid": "comments-loading", children: [
4942
+ /* @__PURE__ */ jsx18(Skeleton2, { className: "h-12 w-full" }),
4943
+ /* @__PURE__ */ jsx18(Skeleton2, { className: "h-12 w-4/5" })
4944
+ ] }) : roots.length === 0 && !thread.error ? /* @__PURE__ */ jsx18("p", { className: "text-sm text-muted-foreground", children: "No comments yet." }) : /* @__PURE__ */ jsx18("div", { className: "flex flex-col gap-4", children: roots.map((comment) => /* @__PURE__ */ jsx18(
4352
4945
  CommentItem,
4353
4946
  {
4354
4947
  comment,
@@ -4359,7 +4952,7 @@ function CommentThread({
4359
4952
  },
4360
4953
  comment.id
4361
4954
  )) }),
4362
- /* @__PURE__ */ jsx16(
4955
+ /* @__PURE__ */ jsx18(
4363
4956
  CommentComposer,
4364
4957
  {
4365
4958
  onSubmit: (body) => thread.add(body, { orgId: orgId ?? null })
@@ -4385,6 +4978,8 @@ export {
4385
4978
  CommentComposer,
4386
4979
  CommentThread,
4387
4980
  DefaultEntityIcon,
4981
+ DefaultWindowShell,
4982
+ DoorControlsSlot,
4388
4983
  DoorRef,
4389
4984
  PrimaryEntityProvider,
4390
4985
  UniversalAssociationPicker,
@@ -4393,8 +4988,11 @@ export {
4393
4988
  buildCommentTree,
4394
4989
  formatRelativeTime,
4395
4990
  getContentRoleMeta,
4991
+ lazyPickerOverride,
4992
+ lazyWindowShell,
4396
4993
  useAssociationCandidates,
4397
4994
  useAssociationEntitySelectAdapter,
4995
+ useAssociationPickerBridge,
4398
4996
  useAssociations,
4399
4997
  useAssociationsStore,
4400
4998
  useAssociationsUiPorts,