@ai-matrx/associations 0.5.2 → 0.6.1

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