@ai-matrx/associations 0.7.4 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog — @ai-matrx/associations
2
2
 
3
+ ## 0.7.6
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/associations/v0.7.5..npm/associations/v0.7.6 -- apps/shared/associations`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.7.5 — 2026-09-02 (recents in token-specific attach pickers)
10
+
11
+ - The per-token picker opened by an association card's `+` control now shows
12
+ favorited and recently viewed rows under **Recent**, while retaining the
13
+ deduplicated general candidate list under **All** and the existing search,
14
+ attach/detach, and create-and-attach workflows.
15
+ - A failing-then-passing integration regression opens the exact
16
+ **Attach conversations** path from `AssociationCard` and proves a favorite
17
+ with no `last_viewed_at` surfaces before an ordinary conversation. Full
18
+ package suite: 194 tests.
19
+
3
20
  ## 0.7.4 — 2026-09-02 (bounded universal-picker results)
4
21
 
5
22
  - The universal picker now keeps type filters in one horizontally scrollable
@@ -2183,6 +2183,15 @@ function EntityCandidateList({
2183
2183
  enabled,
2184
2184
  ...search.trim() ? { search: search.trim() } : {}
2185
2185
  });
2186
+ const { results: recentCandidates, loading: recentsLoading } = useUniversalEntitySearch({
2187
+ query: "",
2188
+ tokens: [token],
2189
+ enabled: enabled && !search.trim()
2190
+ });
2191
+ const visibleRecents = search.trim() ? [] : recentCandidates;
2192
+ const recentIds = new Set(visibleRecents.map((candidate) => candidate.id));
2193
+ const ordinaryCandidates = search.trim() ? candidates : candidates.filter((candidate) => !recentIds.has(candidate.id));
2194
+ const visibleCount = visibleRecents.length + ordinaryCandidates.length;
2186
2195
  const canCreate = info.titleColumn !== null && info.listCandidates === null;
2187
2196
  const toggle = async (id, title) => {
2188
2197
  if (busyId) return;
@@ -2213,7 +2222,7 @@ function EntityCandidateList({
2213
2222
  }
2214
2223
  )
2215
2224
  ] }),
2216
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: loading && candidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ListMessage, { children: [
2225
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto -mx-1 px-1", children: (loading || recentsLoading) && visibleCount === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ListMessage, { children: [
2217
2226
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
2218
2227
  "Loading\u2026"
2219
2228
  ] }) : error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
@@ -2228,23 +2237,69 @@ function EntityCandidateList({
2228
2237
  children: "Retry"
2229
2238
  }
2230
2239
  )
2231
- ] }) : candidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "space-y-0.5", children: candidates.map((c) => {
2232
- const attached = attachedIds.has(c.id);
2233
- const busy = busyId === c.id;
2240
+ ] }) : visibleCount === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ListMessage, { children: canCreate ? `Nothing to attach yet \u2014 create a new ${info.label.toLowerCase()} below.` : "Nothing to attach." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2", children: [
2241
+ visibleRecents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2242
+ CandidateSection,
2243
+ {
2244
+ label: "Recent",
2245
+ candidates: visibleRecents,
2246
+ attachedIds,
2247
+ busyId,
2248
+ icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2249
+ onToggle: toggle
2250
+ }
2251
+ ),
2252
+ ordinaryCandidates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2253
+ CandidateSection,
2254
+ {
2255
+ label: visibleRecents.length > 0 ? `All ${info.labelPlural}` : null,
2256
+ candidates: ordinaryCandidates,
2257
+ attachedIds,
2258
+ busyId,
2259
+ icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2260
+ onToggle: toggle
2261
+ }
2262
+ )
2263
+ ] }) }),
2264
+ canCreate && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2265
+ CreateAndAttachFooter,
2266
+ {
2267
+ token,
2268
+ orgId,
2269
+ seed: search.trim(),
2270
+ onAttach,
2271
+ onCreated: reload
2272
+ }
2273
+ )
2274
+ ] });
2275
+ }
2276
+ function CandidateSection({
2277
+ label,
2278
+ candidates,
2279
+ attachedIds,
2280
+ busyId,
2281
+ icon,
2282
+ onToggle
2283
+ }) {
2284
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "space-y-0.5", children: [
2285
+ label && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "px-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground/60", children: label }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "space-y-0.5", children: candidates.map((candidate) => {
2287
+ const attached = attachedIds.has(candidate.id);
2288
+ const busy = busyId === candidate.id;
2234
2289
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2235
2290
  "button",
2236
2291
  {
2237
2292
  type: "button",
2238
2293
  disabled: busy,
2239
- onClick: () => toggle(c.id, c.title),
2294
+ onClick: () => void onToggle(candidate.id, candidate.title),
2240
2295
  className: (0, import_design_system2.cn)(
2241
2296
  "group flex min-h-11 w-full items-center gap-2 rounded-md px-2.5 py-2 text-left text-sm transition-colors md:min-h-0",
2242
2297
  "hover:bg-accent disabled:opacity-50",
2243
2298
  attached && "bg-accent/40"
2244
2299
  ),
2245
2300
  children: [
2246
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
2247
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "flex-1 min-w-0 truncate text-foreground", children: c.title }),
2301
+ icon,
2302
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "flex-1 min-w-0 truncate text-foreground", children: candidate.title }),
2248
2303
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2249
2304
  "span",
2250
2305
  {
@@ -2257,18 +2312,8 @@ function EntityCandidateList({
2257
2312
  )
2258
2313
  ]
2259
2314
  }
2260
- ) }, c.id);
2261
- }) }) }),
2262
- canCreate && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2263
- CreateAndAttachFooter,
2264
- {
2265
- token,
2266
- orgId,
2267
- seed: search.trim(),
2268
- onAttach,
2269
- onCreated: reload
2270
- }
2271
- )
2315
+ ) }, candidate.id);
2316
+ }) })
2272
2317
  ] });
2273
2318
  }
2274
2319
  function CreateAndAttachFooter({