dsh-context-memory 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/memory.web.js CHANGED
@@ -107,42 +107,541 @@ var en = {
107
107
  };
108
108
 
109
109
  // src/client/view.tsx
110
+ var import_react2 = require("react");
111
+
112
+ // src/client/ui.tsx
110
113
  var import_react = require("react");
111
114
  var import_jsx_runtime = require("react/jsx-runtime");
112
- var PANEL_PATH = "/api/context-memory.panel";
113
- var RECALL_PATH = "/api/context-memory.recall";
114
- var REMEMBER_PATH = "/api/context-memory.remember";
115
- var FORGET_PATH = "/api/context-memory.forget";
116
- var wrap = { display: "flex", flexDirection: "column", gap: 12, maxWidth: 820, fontFamily: "inherit" };
117
- var head = { display: "flex", alignItems: "baseline", gap: 12, flexWrap: "wrap" };
118
- var muted = { fontSize: 12, opacity: 0.75 };
119
- var table = { borderCollapse: "collapse", width: "100%" };
120
- var th = { textAlign: "left", padding: "4px 10px 4px 0", fontWeight: 600, fontSize: 12, opacity: 0.8, borderBottom: "0.5px solid rgba(128,128,128,0.4)" };
121
- var td = { padding: "6px 10px 6px 0", fontSize: 13, borderBottom: "0.5px solid rgba(128,128,128,0.18)" };
122
- var list = { margin: 0, paddingLeft: 18, fontSize: 13 };
123
- var card = { padding: "8px 12px", borderRadius: 6, border: "1px solid rgba(128,128,128,0.2)", fontSize: 13 };
124
- var btn = { fontSize: 12, cursor: "pointer", padding: "3px 10px", borderRadius: 4, border: "0.5px solid rgba(128,128,128,0.4)" };
125
- var dangerBtn = { ...btn, color: "#e55", borderColor: "#e55" };
126
- var inputStyle = { fontSize: 13, padding: "4px 8px", borderRadius: 4, border: "0.5px solid rgba(128,128,128,0.4)", flex: 1 };
127
- function usePanel() {
128
- const [state, setState] = (0, import_react.useState)({ payload: null, error: null });
115
+ var T = {
116
+ accent: "var(--accent, #4B8BBE)",
117
+ accentHover: "var(--accent-hover, #3a6f9e)",
118
+ error: "var(--error, #e53935)",
119
+ success: "var(--success, #2e7d32)",
120
+ warning: "var(--warning, #ed6c02)",
121
+ bg: "var(--bg-secondary, rgba(128,128,128,0.04))",
122
+ bgHover: "var(--bg-tertiary, rgba(128,128,128,0.08))",
123
+ border: "var(--border, rgba(128,128,128,0.2))",
124
+ text: "var(--text-primary, inherit)",
125
+ muted: "var(--text-secondary, rgba(128,128,128,0.65))",
126
+ surface: "var(--bg-primary, #fff)"
127
+ };
128
+ var injected = false;
129
+ function ensureStyles() {
130
+ if (injected || typeof document === "undefined") return;
131
+ injected = true;
132
+ const el = document.createElement("style");
133
+ el.textContent = `
134
+ @keyframes dsh-fade-in{from{opacity:0}to{opacity:1}}
135
+ @keyframes dsh-slide-up{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
136
+ @keyframes dsh-spin{to{transform:rotate(360deg)}}
137
+ .dsh-modal-overlay{animation:dsh-fade-in .15s ease}
138
+ .dsh-modal-body{animation:dsh-slide-up .2s ease}
139
+ .dsh-toast{animation:dsh-slide-up .2s ease}
140
+ .dsh-spin{animation:dsh-spin .6s linear infinite}
141
+ `;
142
+ document.head.appendChild(el);
143
+ }
144
+ function Modal({
145
+ title,
146
+ onClose,
147
+ children,
148
+ footer,
149
+ width = 520
150
+ }) {
151
+ (0, import_react.useEffect)(() => {
152
+ ensureStyles();
153
+ const handler = (e) => {
154
+ if (e.key === "Escape") onClose();
155
+ };
156
+ document.addEventListener("keydown", handler);
157
+ return () => document.removeEventListener("keydown", handler);
158
+ }, [onClose]);
159
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
160
+ "div",
161
+ {
162
+ className: "dsh-modal-overlay",
163
+ style: {
164
+ position: "fixed",
165
+ inset: 0,
166
+ zIndex: 1e3,
167
+ display: "flex",
168
+ alignItems: "center",
169
+ justifyContent: "center",
170
+ background: "rgba(0,0,0,0.45)",
171
+ backdropFilter: "blur(3px)",
172
+ WebkitBackdropFilter: "blur(3px)"
173
+ },
174
+ onClick: onClose,
175
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
176
+ "div",
177
+ {
178
+ className: "dsh-modal-body",
179
+ style: {
180
+ background: T.surface,
181
+ borderRadius: 14,
182
+ boxShadow: "0 12px 40px rgba(0,0,0,0.25)",
183
+ width: `min(92vw, ${width}px)`,
184
+ maxHeight: "85vh",
185
+ display: "flex",
186
+ flexDirection: "column",
187
+ overflow: "hidden"
188
+ },
189
+ onClick: (e) => e.stopPropagation(),
190
+ children: [
191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
192
+ "div",
193
+ {
194
+ style: {
195
+ display: "flex",
196
+ alignItems: "center",
197
+ justifyContent: "space-between",
198
+ padding: "16px 22px",
199
+ borderBottom: `1px solid ${T.border}`
200
+ },
201
+ children: [
202
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { margin: 0, fontSize: 15, fontWeight: 600 }, children: title }),
203
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
204
+ "button",
205
+ {
206
+ type: "button",
207
+ onClick: onClose,
208
+ style: {
209
+ background: "none",
210
+ border: "none",
211
+ cursor: "pointer",
212
+ fontSize: 20,
213
+ color: T.muted,
214
+ padding: "0 4px",
215
+ lineHeight: 1,
216
+ borderRadius: 4
217
+ },
218
+ "aria-label": "Close",
219
+ children: "\xD7"
220
+ }
221
+ )
222
+ ]
223
+ }
224
+ ),
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: 22, overflow: "auto", flex: 1 }, children }),
226
+ footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
227
+ "div",
228
+ {
229
+ style: {
230
+ padding: "14px 22px",
231
+ borderTop: `1px solid ${T.border}`,
232
+ display: "flex",
233
+ justifyContent: "flex-end",
234
+ gap: 10,
235
+ background: T.bg
236
+ },
237
+ children: footer
238
+ }
239
+ )
240
+ ]
241
+ }
242
+ )
243
+ }
244
+ );
245
+ }
246
+ function ConfirmDialog({
247
+ title,
248
+ message,
249
+ confirmLabel,
250
+ cancelLabel = "Cancel",
251
+ onConfirm,
252
+ onClose,
253
+ danger
254
+ }) {
255
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
256
+ Modal,
257
+ {
258
+ title,
259
+ onClose,
260
+ width: 420,
261
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
262
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, { variant: "secondary", onClick: onClose, children: cancelLabel }),
263
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
264
+ Button,
265
+ {
266
+ variant: danger === true ? "danger" : "primary",
267
+ onClick: () => {
268
+ onConfirm();
269
+ onClose();
270
+ },
271
+ children: confirmLabel
272
+ }
273
+ )
274
+ ] }),
275
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: 14, lineHeight: 1.6 }, children: message })
276
+ }
277
+ );
278
+ }
279
+ function Button({
280
+ variant = "secondary",
281
+ size = "md",
282
+ children,
283
+ style,
284
+ ...rest
285
+ }) {
286
+ const base = {
287
+ cursor: "pointer",
288
+ borderRadius: 7,
289
+ fontWeight: 500,
290
+ transition: "all 0.15s ease",
291
+ border: "none",
292
+ display: "inline-flex",
293
+ alignItems: "center",
294
+ gap: 4,
295
+ fontSize: size === "sm" ? 12 : 13,
296
+ padding: size === "sm" ? "5px 12px" : "8px 18px",
297
+ fontFamily: "inherit"
298
+ };
299
+ const variants = {
300
+ primary: { background: T.accent, color: "#fff" },
301
+ secondary: {
302
+ background: T.bg,
303
+ color: T.text,
304
+ border: `1px solid ${T.border}`
305
+ },
306
+ danger: {
307
+ background: "transparent",
308
+ color: T.error,
309
+ border: `1px solid ${T.error}`
310
+ },
311
+ ghost: { background: "transparent", color: T.muted, border: "none" }
312
+ };
313
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...base, ...variants[variant], ...style }, ...rest, children });
314
+ }
315
+ function Card({
316
+ title,
317
+ icon,
318
+ children,
319
+ actions,
320
+ style,
321
+ padding = 14
322
+ }) {
323
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
324
+ "div",
325
+ {
326
+ style: {
327
+ borderRadius: 10,
328
+ border: `1px solid ${T.border}`,
329
+ background: T.bg,
330
+ overflow: "hidden",
331
+ ...style
332
+ },
333
+ children: [
334
+ (title !== void 0 || actions !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
335
+ "div",
336
+ {
337
+ style: {
338
+ display: "flex",
339
+ alignItems: "center",
340
+ justifyContent: "space-between",
341
+ padding: "12px 16px",
342
+ borderBottom: title !== void 0 ? `1px solid ${T.border}` : "none"
343
+ },
344
+ children: [
345
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 13, fontWeight: 600, display: "flex", alignItems: "center", gap: 6 }, children: [
346
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: icon }),
347
+ title
348
+ ] }),
349
+ actions
350
+ ]
351
+ }
352
+ ),
353
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding }, children })
354
+ ]
355
+ }
356
+ );
357
+ }
358
+ function StatCard({
359
+ value,
360
+ label,
361
+ color,
362
+ unit
363
+ }) {
364
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
365
+ "div",
366
+ {
367
+ style: {
368
+ flex: 1,
369
+ minWidth: 90,
370
+ textAlign: "center",
371
+ padding: "14px 10px",
372
+ borderRadius: 10,
373
+ border: `1px solid ${T.border}`,
374
+ background: T.bg
375
+ },
376
+ children: [
377
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 24, fontWeight: 700, color: color ?? T.text, lineHeight: 1.2 }, children: [
378
+ value,
379
+ unit !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, fontWeight: 500, opacity: 0.7, marginLeft: 2 }, children: unit })
380
+ ] }),
381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 11, color: T.muted, marginTop: 4 }, children: label })
382
+ ]
383
+ }
384
+ );
385
+ }
386
+ function Badge({
387
+ children,
388
+ color = "default"
389
+ }) {
390
+ const colors = {
391
+ default: { bg: "rgba(128,128,128,0.12)", fg: T.muted },
392
+ success: { bg: "rgba(46,125,50,0.12)", fg: T.success },
393
+ error: { bg: "rgba(229,57,53,0.12)", fg: T.error },
394
+ warning: { bg: "rgba(245,124,0,0.12)", fg: T.warning },
395
+ info: { bg: "rgba(75,139,190,0.12)", fg: T.accent }
396
+ };
397
+ const c = colors[color];
398
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
+ "span",
400
+ {
401
+ style: {
402
+ display: "inline-block",
403
+ padding: "2px 9px",
404
+ borderRadius: 10,
405
+ fontSize: 11,
406
+ fontWeight: 600,
407
+ background: c.bg,
408
+ color: c.fg
409
+ },
410
+ children
411
+ }
412
+ );
413
+ }
414
+ function Input({
415
+ style,
416
+ ...rest
417
+ }) {
418
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
419
+ "input",
420
+ {
421
+ ...rest,
422
+ style: {
423
+ fontSize: 13,
424
+ padding: "8px 12px",
425
+ borderRadius: 7,
426
+ border: `1px solid ${T.border}`,
427
+ background: T.surface,
428
+ color: T.text,
429
+ width: "100%",
430
+ boxSizing: "border-box",
431
+ fontFamily: "inherit",
432
+ outline: "none",
433
+ transition: "border-color 0.15s",
434
+ ...style
435
+ }
436
+ }
437
+ );
438
+ }
439
+ function Select({
440
+ style,
441
+ children,
442
+ ...rest
443
+ }) {
444
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
445
+ "select",
446
+ {
447
+ ...rest,
448
+ style: {
449
+ fontSize: 13,
450
+ padding: "8px 12px",
451
+ borderRadius: 7,
452
+ border: `1px solid ${T.border}`,
453
+ background: T.surface,
454
+ color: T.text,
455
+ cursor: "pointer",
456
+ fontFamily: "inherit",
457
+ outline: "none",
458
+ ...style
459
+ },
460
+ children
461
+ }
462
+ );
463
+ }
464
+ var ToastContext = (0, import_react.createContext)(
465
+ () => {
466
+ }
467
+ );
468
+ function ToastProvider({ children }) {
469
+ const [toasts, setToasts] = (0, import_react.useState)([]);
470
+ const show = (0, import_react.useCallback)((type, message) => {
471
+ const id = Date.now() + Math.random();
472
+ setToasts((t) => [...t, { id, type, message }]);
473
+ setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3500);
474
+ }, []);
475
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ToastContext.Provider, { value: show, children: [
476
+ children,
477
+ toasts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
478
+ "div",
479
+ {
480
+ style: {
481
+ position: "fixed",
482
+ bottom: 24,
483
+ right: 24,
484
+ zIndex: 2e3,
485
+ display: "flex",
486
+ flexDirection: "column",
487
+ gap: 8
488
+ },
489
+ children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
490
+ "div",
491
+ {
492
+ className: "dsh-toast",
493
+ style: {
494
+ padding: "12px 18px",
495
+ borderRadius: 8,
496
+ fontSize: 13,
497
+ fontWeight: 500,
498
+ boxShadow: "0 6px 20px rgba(0,0,0,0.2)",
499
+ color: "#fff",
500
+ background: t.type === "success" ? T.success : t.type === "error" ? T.error : T.accent,
501
+ maxWidth: 360
502
+ },
503
+ children: t.message
504
+ },
505
+ t.id
506
+ ))
507
+ }
508
+ )
509
+ ] });
510
+ }
511
+ function useToast() {
512
+ return (0, import_react.useContext)(ToastContext);
513
+ }
514
+ function Spinner({ size = 16 }) {
515
+ ensureStyles();
516
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
517
+ "span",
518
+ {
519
+ className: "dsh-spin",
520
+ style: {
521
+ display: "inline-block",
522
+ width: size,
523
+ height: size,
524
+ border: `2px solid ${T.border}`,
525
+ borderTopColor: T.accent,
526
+ borderRadius: "50%"
527
+ }
528
+ }
529
+ );
530
+ }
531
+ function EmptyState({
532
+ icon,
533
+ message
534
+ }) {
535
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
536
+ "div",
537
+ {
538
+ style: {
539
+ textAlign: "center",
540
+ padding: "36px 16px",
541
+ color: T.muted
542
+ },
543
+ children: [
544
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 36, marginBottom: 10, opacity: 0.4 }, children: icon }),
545
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 13 }, children: message })
546
+ ]
547
+ }
548
+ );
549
+ }
550
+ function SectionTitle({
551
+ icon,
552
+ children,
553
+ actions
554
+ }) {
555
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
556
+ "div",
557
+ {
558
+ style: {
559
+ display: "flex",
560
+ alignItems: "center",
561
+ justifyContent: "space-between",
562
+ marginTop: 6,
563
+ marginBottom: 8
564
+ },
565
+ children: [
566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
567
+ "span",
568
+ {
569
+ style: {
570
+ fontSize: 14,
571
+ fontWeight: 600,
572
+ display: "flex",
573
+ alignItems: "center",
574
+ gap: 6
575
+ },
576
+ children: [
577
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: icon }),
578
+ children
579
+ ]
580
+ }
581
+ ),
582
+ actions
583
+ ]
584
+ }
585
+ );
586
+ }
587
+ var tableStyles = {
588
+ table: {
589
+ borderCollapse: "collapse",
590
+ width: "100%"
591
+ },
592
+ th: {
593
+ textAlign: "left",
594
+ padding: "8px 12px 8px 0",
595
+ fontWeight: 600,
596
+ fontSize: 12,
597
+ color: T.muted,
598
+ borderBottom: `1px solid ${T.border}`
599
+ },
600
+ td: {
601
+ padding: "8px 12px 8px 0",
602
+ fontSize: 13,
603
+ borderBottom: "1px solid rgba(128,128,128,0.08)"
604
+ },
605
+ clickRow: { cursor: "pointer" }
606
+ };
607
+ function Field({
608
+ label,
609
+ children,
610
+ hint
611
+ }) {
612
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
613
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { style: { fontSize: 12, fontWeight: 600, color: T.text }, children: label }),
614
+ children,
615
+ hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 11, color: T.muted }, children: hint })
616
+ ] });
617
+ }
618
+ function usePanel(path) {
619
+ const [payload, setPayload] = (0, import_react.useState)(null);
620
+ const [error, setError] = (0, import_react.useState)(null);
129
621
  const [tick, setTick] = (0, import_react.useState)(0);
130
622
  const reload = (0, import_react.useCallback)(() => setTick((v) => v + 1), []);
131
623
  (0, import_react.useEffect)(() => {
132
624
  const c = new AbortController();
133
- setState((p) => ({ ...p, error: null }));
134
- fetch(PANEL_PATH, { signal: c.signal }).then(async (r) => {
625
+ setError(null);
626
+ fetch(path, { signal: c.signal }).then(async (r) => {
135
627
  if (!r.ok) throw new Error(String(r.status));
136
628
  return r.json();
137
- }).then((payload) => {
138
- if (!c.signal.aborted) setState({ payload, error: null });
629
+ }).then((p) => {
630
+ if (!c.signal.aborted) setPayload(p);
139
631
  }).catch((e) => {
140
- if (!c.signal.aborted) setState({ payload: null, error: e instanceof Error ? e.message : String(e) });
632
+ if (!c.signal.aborted) setPayload(null), setError(e instanceof Error ? e.message : String(e));
141
633
  });
142
634
  return () => c.abort();
143
- }, [tick]);
144
- return { ...state, reload };
635
+ }, [tick, path]);
636
+ return (0, import_react.useMemo)(() => ({ payload, error, reload }), [payload, error, reload]);
145
637
  }
638
+
639
+ // src/client/view.tsx
640
+ var import_jsx_runtime2 = require("react/jsx-runtime");
641
+ var PANEL_PATH = "/api/context-memory.panel";
642
+ var RECALL_PATH = "/api/context-memory.recall";
643
+ var REMEMBER_PATH = "/api/context-memory.remember";
644
+ var FORGET_PATH = "/api/context-memory.forget";
146
645
  function checkLabel(memory, t) {
147
646
  if (!memory.guard) return t("checkNone");
148
647
  switch (memory.verification?.outcome) {
@@ -157,211 +656,203 @@ function checkLabel(memory, t) {
157
656
  }
158
657
  }
159
658
  function provenance(memory) {
160
- return [
161
- memory.source,
162
- memory.sessionId !== void 0 ? `session ${memory.sessionId}` : null,
163
- memory.step !== void 0 ? `step ${String(memory.step)}` : null
164
- ].filter((part) => part !== null).join(" \xB7 ");
659
+ return [memory.source, memory.sessionId !== void 0 ? `session ${memory.sessionId}` : null, memory.step !== void 0 ? `step ${String(memory.step)}` : null].filter((part) => part !== null).join(" \xB7 ");
165
660
  }
166
- function SearchBar({ t, onResult }) {
167
- const [query, setQuery] = (0, import_react.useState)("");
168
- const [loading, setLoading] = (0, import_react.useState)(false);
169
- const handleSearch = (0, import_react.useCallback)(async () => {
170
- if (!query.trim()) {
171
- onResult(null);
172
- return;
173
- }
174
- setLoading(true);
661
+ function AddMemoryModal({ t, onClose, onAdded }) {
662
+ const toast = useToast();
663
+ const [text, setText] = (0, import_react2.useState)("");
664
+ const [subject, setSubject] = (0, import_react2.useState)("");
665
+ const [kind, setKind] = (0, import_react2.useState)("fact");
666
+ const [adding, setAdding] = (0, import_react2.useState)(false);
667
+ const handleAdd = (0, import_react2.useCallback)(async () => {
668
+ if (!text.trim()) return;
669
+ setAdding(true);
175
670
  try {
176
- const r = await fetch(`${RECALL_PATH}?q=${encodeURIComponent(query)}&limit=10`);
671
+ const r = await fetch(REMEMBER_PATH, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ text, subject: subject || void 0, kind, source: "user" }) });
177
672
  if (r.ok) {
178
- const data = await r.json();
179
- onResult(data.hits);
673
+ toast("success", t("memoryAdded"));
674
+ onAdded();
675
+ onClose();
180
676
  }
181
677
  } finally {
182
- setLoading(false);
678
+ setAdding(false);
183
679
  }
184
- }, [query, onResult]);
185
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
186
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: inputStyle, placeholder: t("searchPlaceholder"), value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: (e) => {
187
- if (e.key === "Enter") handleSearch();
188
- } }),
189
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: btn, disabled: loading, onClick: handleSearch, children: loading ? "\u2026" : t("search") })
190
- ] });
680
+ }, [text, subject, kind, t, toast, onAdded, onClose]);
681
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
682
+ Modal,
683
+ {
684
+ title: t("addMemory"),
685
+ onClose,
686
+ width: 500,
687
+ footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
688
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { variant: "secondary", onClick: onClose, children: t("cancel") }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Button, { variant: "primary", disabled: adding || !text.trim(), onClick: handleAdd, children: [
690
+ adding ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: 14 }) : null,
691
+ " ",
692
+ t("add")
693
+ ] })
694
+ ] }),
695
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 14 }, children: [
696
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Field, { label: t("memoryText"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Input, { value: text, onChange: (e) => setText(e.target.value), placeholder: t("memoryTextPlaceholder") }) }),
697
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Field, { label: t("subjectOptional"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Input, { value: subject, onChange: (e) => setSubject(e.target.value), placeholder: t("subjectPlaceholder") }) }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Field, { label: t("kind"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Select, { value: kind, onChange: (e) => setKind(e.target.value), style: { width: "100%" }, children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fact", children: t("kindFact") }),
700
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "decision", children: t("kindDecision") }),
701
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "preference", children: t("kindPreference") }),
702
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "pitfall", children: t("kindPitfall") })
703
+ ] }) })
704
+ ] })
705
+ }
706
+ );
191
707
  }
192
- function AddMemoryForm({ t, onAdded }) {
193
- const [text, setText] = (0, import_react.useState)("");
194
- const [subject, setSubject] = (0, import_react.useState)("");
195
- const [kind, setKind] = (0, import_react.useState)("fact");
196
- const [adding, setAdding] = (0, import_react.useState)(false);
197
- const handleAdd = (0, import_react.useCallback)(async () => {
198
- if (!text.trim()) return;
199
- setAdding(true);
708
+ function ContextMemoryPanelInner({ t }) {
709
+ const { payload, error, reload } = usePanel(PANEL_PATH);
710
+ const toast = useToast();
711
+ const [searchQuery, setSearchQuery] = (0, import_react2.useState)("");
712
+ const [searchHits, setSearchHits] = (0, import_react2.useState)(null);
713
+ const [searching, setSearching] = (0, import_react2.useState)(false);
714
+ const [addOpen, setAddOpen] = (0, import_react2.useState)(false);
715
+ const [forgetTarget, setForgetTarget] = (0, import_react2.useState)(null);
716
+ const handleSearch = (0, import_react2.useCallback)(async () => {
717
+ if (!searchQuery.trim()) {
718
+ setSearchHits(null);
719
+ return;
720
+ }
721
+ setSearching(true);
200
722
  try {
201
- await fetch(REMEMBER_PATH, {
202
- method: "POST",
203
- headers: { "content-type": "application/json" },
204
- body: JSON.stringify({ text, subject: subject || void 0, kind, source: "user" })
205
- });
206
- setText("");
207
- setSubject("");
208
- setKind("fact");
209
- onAdded();
723
+ const r = await fetch(`${RECALL_PATH}?q=${encodeURIComponent(searchQuery)}&limit=10`);
724
+ if (r.ok) {
725
+ setSearchHits((await r.json()).hits);
726
+ }
210
727
  } finally {
211
- setAdding(false);
728
+ setSearching(false);
729
+ }
730
+ }, [searchQuery]);
731
+ const handleForget = (0, import_react2.useCallback)(async () => {
732
+ if (forgetTarget === null) return;
733
+ const r = await fetch(FORGET_PATH, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(forgetTarget) });
734
+ if (r.ok) {
735
+ toast("success", t("forgotten"));
736
+ setForgetTarget(null);
737
+ reload();
212
738
  }
213
- }, [text, subject, kind, onAdded]);
214
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...card, display: "flex", flexDirection: "column", gap: 6 }, children: [
215
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 12 }, children: [
739
+ }, [forgetTarget, t, toast, reload]);
740
+ const header = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("header", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 4 }, children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { style: { fontSize: 15 }, children: [
742
+ "\u{1F9E0} ",
743
+ t("title")
744
+ ] }),
745
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { flex: 1 } }),
746
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Button, { variant: "primary", size: "sm", onClick: () => setAddOpen(true), children: [
216
747
  "\u2795 ",
217
748
  t("addMemory")
218
749
  ] }),
219
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: inputStyle, placeholder: t("memoryText"), value: text, onChange: (e) => setText(e.target.value) }),
220
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: inputStyle, placeholder: t("subjectOptional"), value: subject, onChange: (e) => setSubject(e.target.value) }),
222
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { style: { ...btn, flex: "0 0 auto" }, value: kind, onChange: (e) => setKind(e.target.value), children: [
223
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "fact", children: t("kindFact") }),
224
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "decision", children: t("kindDecision") }),
225
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "preference", children: t("kindPreference") }),
226
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "pitfall", children: t("kindPitfall") })
227
- ] }),
228
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: btn, disabled: adding, onClick: handleAdd, children: adding ? "\u2026" : t("add") })
229
- ] })
750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { variant: "secondary", size: "sm", onClick: reload, children: t("refresh") })
230
751
  ] });
231
- }
232
- function ContextMemoryPanel({ t }) {
233
- const { payload, error, reload } = usePanel();
234
- const [searchHits, setSearchHits] = (0, import_react.useState)(null);
235
- const handleForget = (0, import_react.useCallback)(async (id, reason) => {
236
- await fetch(FORGET_PATH, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ id, reason }) });
237
- reload();
238
- }, [reload]);
239
- const header = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { style: head, children: [
240
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 13 }, children: [
241
- "\u{1F9E0} ",
242
- t("title")
243
- ] }),
244
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
245
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: btn, onClick: reload, children: t("refresh") })
752
+ if (error !== null) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: 820 }, children: [
753
+ header,
754
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { role: "alert", style: { margin: 0, fontSize: 13, color: "var(--error, #e53935)" }, children: [
755
+ t("failed"),
756
+ ": ",
757
+ error
758
+ ] }) })
246
759
  ] });
247
- if (error !== null) {
248
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: wrap, children: [
249
- header,
250
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", style: { margin: 0, fontSize: 13 }, children: [
251
- t("failed"),
252
- ": ",
253
- error
254
- ] }),
255
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: reload, style: { ...btn, alignSelf: "flex-start" }, children: t("retry") })
256
- ] });
257
- }
258
- if (payload === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: muted, "aria-live": "polite", children: t("loading") });
259
- const { totals } = payload;
260
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: wrap, children: [
760
+ if (payload === null) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: 820 }, children: [
761
+ header,
762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: 40 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: 28 }) })
763
+ ] });
764
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 14, maxWidth: 820 }, children: [
261
765
  header,
262
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: muted, children: [
263
- t("active"),
264
- " ",
265
- totals.active,
266
- " \xB7 ",
267
- t("checkPassed"),
268
- " ",
269
- totals.verified,
270
- " \xB7 ",
271
- t("unverified"),
272
- " ",
273
- totals.unverified,
274
- " \xB7 ",
275
- t("superseded"),
276
- " ",
277
- totals.superseded
766
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 10, flexWrap: "wrap" }, children: [
767
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.totals.active, label: t("active") }),
768
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.totals.verified, label: t("checkPassed") }),
769
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.totals.unverified, label: t("unverified") }),
770
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.totals.superseded, label: t("superseded") })
278
771
  ] }),
279
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SearchBar, { t, onResult: setSearchHits }),
280
- searchHits !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: card, children: [
281
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 12 }, children: [
282
- t("searchResults"),
283
- " (",
284
- searchHits.length,
285
- ")"
772
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { title: t("search"), icon: "\u{1F50D}", children: [
773
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
775
+ Input,
776
+ {
777
+ value: searchQuery,
778
+ onChange: (e) => setSearchQuery(e.target.value),
779
+ placeholder: t("searchPlaceholder"),
780
+ onKeyDown: (e) => {
781
+ if (e.key === "Enter") handleSearch();
782
+ }
783
+ }
784
+ ),
785
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Button, { variant: "secondary", onClick: handleSearch, disabled: searching, children: [
786
+ searching ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: 14 }) : null,
787
+ " ",
788
+ t("search")
789
+ ] })
286
790
  ] }),
287
- searchHits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: muted, children: t("noResults") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: list, children: searchHits.map((hit) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { marginBottom: 4 }, children: [
288
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontSize: 11 }, children: hit.memory.id }),
289
- " (",
290
- hit.score.toFixed(2),
291
- ") ",
292
- hit.memory.text,
293
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { ...muted, marginLeft: 8 }, children: [
791
+ searchHits !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: 10 }, children: searchHits.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { message: t("noResults") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: searchHits.map((hit) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "baseline" }, children: [
792
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { color: "info", children: hit.score.toFixed(2) }),
793
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 12 }, children: hit.memory.text }),
794
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { fontSize: 10, opacity: 0.5 }, children: [
294
795
  "\u2014 ",
295
796
  hit.why
296
797
  ] })
297
- ] }, hit.memory.id)) })
298
- ] }),
299
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddMemoryForm, { t, onAdded: reload }),
300
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 13 }, children: [
301
- "\u26A0\uFE0F ",
302
- t("conflicts")
798
+ ] }, hit.memory.id)) }) })
303
799
  ] }),
304
- payload.conflicts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: muted, children: t("noConflicts") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: list, children: payload.conflicts.map((conflict) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
305
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: conflict.subject }),
306
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { ...list, fontSize: 12, opacity: 0.85 }, children: conflict.memories.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
307
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontSize: 11 }, children: memory.id }),
308
- " ",
309
- memory.text,
310
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...dangerBtn, marginLeft: 8 }, onClick: () => handleForget(memory.id, `conflict resolved: ${conflict.subject}`), children: t("resolve") })
311
- ] }, memory.id)) })
312
- ] }, conflict.subject)) }),
313
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 13 }, children: [
314
- "\u2705 ",
315
- t("active")
800
+ payload.conflicts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionTitle, { icon: "\u26A0\uFE0F", children: t("conflicts") }),
802
+ payload.conflicts.map((conflict) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: conflict.subject, children: conflict.memories.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
803
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: { fontSize: 11 }, children: memory.id }),
804
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 12, flex: 1 }, children: memory.text }),
805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { variant: "danger", size: "sm", onClick: () => setForgetTarget({ id: memory.id, reason: `conflict resolved: ${conflict.subject}` }), children: t("resolve") })
806
+ ] }, memory.id)) }, conflict.subject))
316
807
  ] }),
317
- payload.active.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: 13, opacity: 0.8 }, children: t("empty") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: table, children: [
318
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
319
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: "Id" }),
320
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("memory") }),
321
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("kind") }),
322
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("status") }),
323
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("from") }),
324
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th })
808
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionTitle, { icon: "\u2705", children: t("active") }),
809
+ payload.active.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { icon: "\u{1F4ED}", message: t("empty") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { padding: 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: tableStyles.table, children: [
810
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
811
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: "Id" }),
812
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("memory") }),
813
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("kind") }),
814
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("status") }),
815
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("from") }),
816
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th })
325
817
  ] }) }),
326
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: payload.active.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
327
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontSize: 11 }, children: memory.id }) }),
328
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: memory.text }),
329
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: memory.kind }),
330
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: checkLabel(memory, t) }),
331
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: provenance(memory) }),
332
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", style: dangerBtn, onClick: () => handleForget(memory.id, "superseded from panel"), children: [
333
- "\u{1F5D1} ",
334
- t("forget")
335
- ] }) })
818
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: payload.active.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
819
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: { fontSize: 11 }, children: memory.id }) }),
820
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: memory.text }),
821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { children: memory.kind }) }),
822
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: checkLabel(memory, t) }),
823
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: { ...tableStyles.td, fontSize: 11, opacity: 0.6 }, children: provenance(memory) }),
824
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { variant: "danger", size: "sm", onClick: () => setForgetTarget({ id: memory.id, reason: "superseded from panel" }), children: "\u{1F5D1}" }) })
336
825
  ] }, memory.id)) })
337
- ] }),
338
- payload.superseded.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
339
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 13 }, children: [
340
- "\u{1F4E6} ",
826
+ ] }) }),
827
+ payload.superseded.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
828
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(SectionTitle, { icon: "\u{1F4E6}", children: [
341
829
  t("superseded"),
342
830
  " (",
343
831
  payload.superseded.length,
344
832
  ")"
345
833
  ] }),
346
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: table, children: [
347
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
348
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: "Id" }),
349
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("memory") }),
350
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("kind") }),
351
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("status") }),
352
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("from") })
834
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { padding: 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: tableStyles.table, children: [
835
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
836
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: "Id" }),
837
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("memory") }),
838
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("kind") }),
839
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("status") })
353
840
  ] }) }),
354
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: payload.superseded.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
355
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontSize: 11 }, children: memory.id }) }),
356
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: memory.text }),
357
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: memory.kind }),
358
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: checkLabel(memory, t) }),
359
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: provenance(memory) })
841
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: payload.superseded.map((memory) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
842
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: { fontSize: 11 }, children: memory.id }) }),
843
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: memory.text }),
844
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { children: memory.kind }) }),
845
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: checkLabel(memory, t) })
360
846
  ] }, memory.id)) })
361
- ] })
362
- ] })
847
+ ] }) })
848
+ ] }),
849
+ addOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AddMemoryModal, { t, onClose: () => setAddOpen(false), onAdded: reload }),
850
+ forgetTarget !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ConfirmDialog, { title: t("forget"), message: t("confirmForget"), confirmLabel: t("forget"), danger: true, onConfirm: handleForget, onClose: () => setForgetTarget(null) })
363
851
  ] });
364
852
  }
853
+ function ContextMemoryPanel({ t }) {
854
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToastProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ContextMemoryPanelInner, { t }) });
855
+ }
365
856
 
366
857
  // src/client/index.tsx
367
858
  var inject = ["slots", "locale"];