kiro-memory 1.2.2 → 1.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/package.json +5 -1
- package/plugin/dist/cli/contextkit.js +165 -10
- package/plugin/dist/hooks/agentSpawn.js +15 -0
- package/plugin/dist/hooks/kiro-hooks.js +15 -0
- package/plugin/dist/hooks/postToolUse.js +15 -0
- package/plugin/dist/hooks/stop.js +15 -0
- package/plugin/dist/hooks/userPromptSubmit.js +15 -0
- package/plugin/dist/index.js +15 -0
- package/plugin/dist/sdk/index.js +15 -0
- package/plugin/dist/services/sqlite/Database.js +15 -0
- package/plugin/dist/services/sqlite/index.js +15 -0
- package/plugin/dist/viewer.html +100 -630
- package/plugin/dist/viewer.js +359 -150
- package/plugin/dist/worker-service.js +50 -0
package/plugin/dist/viewer.js
CHANGED
|
@@ -1083,7 +1083,7 @@ var require_react_development = __commonJS({
|
|
|
1083
1083
|
}
|
|
1084
1084
|
return dispatcher.useContext(Context);
|
|
1085
1085
|
}
|
|
1086
|
-
function
|
|
1086
|
+
function useState8(initialState) {
|
|
1087
1087
|
var dispatcher = resolveDispatcher();
|
|
1088
1088
|
return dispatcher.useState(initialState);
|
|
1089
1089
|
}
|
|
@@ -1091,11 +1091,11 @@ var require_react_development = __commonJS({
|
|
|
1091
1091
|
var dispatcher = resolveDispatcher();
|
|
1092
1092
|
return dispatcher.useReducer(reducer, initialArg, init);
|
|
1093
1093
|
}
|
|
1094
|
-
function
|
|
1094
|
+
function useRef4(initialValue) {
|
|
1095
1095
|
var dispatcher = resolveDispatcher();
|
|
1096
1096
|
return dispatcher.useRef(initialValue);
|
|
1097
1097
|
}
|
|
1098
|
-
function
|
|
1098
|
+
function useEffect7(create, deps) {
|
|
1099
1099
|
var dispatcher = resolveDispatcher();
|
|
1100
1100
|
return dispatcher.useEffect(create, deps);
|
|
1101
1101
|
}
|
|
@@ -1107,7 +1107,7 @@ var require_react_development = __commonJS({
|
|
|
1107
1107
|
var dispatcher = resolveDispatcher();
|
|
1108
1108
|
return dispatcher.useLayoutEffect(create, deps);
|
|
1109
1109
|
}
|
|
1110
|
-
function
|
|
1110
|
+
function useCallback4(callback, deps) {
|
|
1111
1111
|
var dispatcher = resolveDispatcher();
|
|
1112
1112
|
return dispatcher.useCallback(callback, deps);
|
|
1113
1113
|
}
|
|
@@ -1874,19 +1874,19 @@ var require_react_development = __commonJS({
|
|
|
1874
1874
|
exports.memo = memo;
|
|
1875
1875
|
exports.startTransition = startTransition;
|
|
1876
1876
|
exports.unstable_act = act;
|
|
1877
|
-
exports.useCallback =
|
|
1877
|
+
exports.useCallback = useCallback4;
|
|
1878
1878
|
exports.useContext = useContext;
|
|
1879
1879
|
exports.useDebugValue = useDebugValue;
|
|
1880
1880
|
exports.useDeferredValue = useDeferredValue;
|
|
1881
|
-
exports.useEffect =
|
|
1881
|
+
exports.useEffect = useEffect7;
|
|
1882
1882
|
exports.useId = useId;
|
|
1883
1883
|
exports.useImperativeHandle = useImperativeHandle;
|
|
1884
1884
|
exports.useInsertionEffect = useInsertionEffect;
|
|
1885
1885
|
exports.useLayoutEffect = useLayoutEffect;
|
|
1886
1886
|
exports.useMemo = useMemo2;
|
|
1887
1887
|
exports.useReducer = useReducer;
|
|
1888
|
-
exports.useRef =
|
|
1889
|
-
exports.useState =
|
|
1888
|
+
exports.useRef = useRef4;
|
|
1889
|
+
exports.useState = useState8;
|
|
1890
1890
|
exports.useSyncExternalStore = useSyncExternalStore;
|
|
1891
1891
|
exports.useTransition = useTransition;
|
|
1892
1892
|
exports.version = ReactVersion;
|
|
@@ -23581,11 +23581,11 @@ var require_client = __commonJS({
|
|
|
23581
23581
|
});
|
|
23582
23582
|
|
|
23583
23583
|
// src/ui/viewer/index.tsx
|
|
23584
|
-
var
|
|
23584
|
+
var import_react9 = __toESM(require_react(), 1);
|
|
23585
23585
|
var import_client = __toESM(require_client(), 1);
|
|
23586
23586
|
|
|
23587
23587
|
// src/ui/viewer/App.tsx
|
|
23588
|
-
var
|
|
23588
|
+
var import_react8 = __toESM(require_react(), 1);
|
|
23589
23589
|
|
|
23590
23590
|
// src/ui/viewer/components/Header.tsx
|
|
23591
23591
|
var import_react2 = __toESM(require_react(), 1);
|
|
@@ -23594,40 +23594,40 @@ var import_react2 = __toESM(require_react(), 1);
|
|
|
23594
23594
|
var import_react = __toESM(require_react(), 1);
|
|
23595
23595
|
|
|
23596
23596
|
// src/ui/viewer/utils/format.ts
|
|
23597
|
-
function
|
|
23597
|
+
function getTypeBadgeClasses(type) {
|
|
23598
23598
|
const map = {
|
|
23599
|
-
"file-write": "
|
|
23600
|
-
"file-read": "
|
|
23601
|
-
"command": "
|
|
23602
|
-
"research": "
|
|
23603
|
-
"delegation": "
|
|
23604
|
-
"tool-use": "
|
|
23599
|
+
"file-write": { bg: "bg-emerald-500/10 dark:bg-emerald-500/10", text: "text-emerald-600 dark:text-emerald-400", dot: "bg-emerald-500" },
|
|
23600
|
+
"file-read": { bg: "bg-cyan-500/10 dark:bg-cyan-500/10", text: "text-cyan-600 dark:text-cyan-400", dot: "bg-cyan-500" },
|
|
23601
|
+
"command": { bg: "bg-amber-500/10 dark:bg-amber-500/10", text: "text-amber-600 dark:text-amber-400", dot: "bg-amber-500" },
|
|
23602
|
+
"research": { bg: "bg-blue-500/10 dark:bg-blue-500/10", text: "text-blue-600 dark:text-blue-400", dot: "bg-blue-500" },
|
|
23603
|
+
"delegation": { bg: "bg-violet-500/10 dark:bg-violet-500/10", text: "text-violet-600 dark:text-violet-400", dot: "bg-violet-500" },
|
|
23604
|
+
"tool-use": { bg: "bg-zinc-500/10 dark:bg-zinc-500/10", text: "text-zinc-600 dark:text-zinc-400", dot: "bg-zinc-500" }
|
|
23605
23605
|
};
|
|
23606
|
-
return map[type] || "
|
|
23606
|
+
return map[type] || { bg: "bg-zinc-500/10 dark:bg-zinc-500/10", text: "text-zinc-600 dark:text-zinc-400", dot: "bg-zinc-500" };
|
|
23607
23607
|
}
|
|
23608
23608
|
function timeAgo(epochSeconds) {
|
|
23609
23609
|
const now = Date.now() / 1e3;
|
|
23610
23610
|
const diff = Math.max(0, now - epochSeconds);
|
|
23611
|
-
if (diff < 60) return "
|
|
23611
|
+
if (diff < 60) return "just now";
|
|
23612
23612
|
if (diff < 3600) {
|
|
23613
23613
|
const m = Math.floor(diff / 60);
|
|
23614
|
-
return `${m}
|
|
23614
|
+
return `${m}m ago`;
|
|
23615
23615
|
}
|
|
23616
23616
|
if (diff < 86400) {
|
|
23617
23617
|
const h = Math.floor(diff / 3600);
|
|
23618
|
-
return `${h}h
|
|
23618
|
+
return `${h}h ago`;
|
|
23619
23619
|
}
|
|
23620
|
-
if (diff < 172800) return "
|
|
23620
|
+
if (diff < 172800) return "yesterday";
|
|
23621
23621
|
if (diff < 604800) {
|
|
23622
23622
|
const d = Math.floor(diff / 86400);
|
|
23623
|
-
return `${d}
|
|
23623
|
+
return `${d}d ago`;
|
|
23624
23624
|
}
|
|
23625
23625
|
if (diff < 2592e3) {
|
|
23626
23626
|
const w = Math.floor(diff / 604800);
|
|
23627
|
-
return `${w}
|
|
23627
|
+
return `${w}w ago`;
|
|
23628
23628
|
}
|
|
23629
23629
|
const date = new Date(epochSeconds * 1e3);
|
|
23630
|
-
return date.toLocaleDateString("
|
|
23630
|
+
return date.toLocaleDateString("en-US", { day: "numeric", month: "short" });
|
|
23631
23631
|
}
|
|
23632
23632
|
|
|
23633
23633
|
// src/ui/viewer/components/SearchBar.tsx
|
|
@@ -23636,25 +23636,23 @@ function SearchBar() {
|
|
|
23636
23636
|
const [results, setResults] = (0, import_react.useState)(null);
|
|
23637
23637
|
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
23638
23638
|
const [isSearching, setIsSearching] = (0, import_react.useState)(false);
|
|
23639
|
+
const [selectedIndex, setSelectedIndex] = (0, import_react.useState)(0);
|
|
23639
23640
|
const inputRef = (0, import_react.useRef)(null);
|
|
23640
|
-
const containerRef = (0, import_react.useRef)(null);
|
|
23641
23641
|
const debounceRef = (0, import_react.useRef)();
|
|
23642
23642
|
const doSearch = (0, import_react.useCallback)(async (q) => {
|
|
23643
23643
|
if (!q.trim()) {
|
|
23644
23644
|
setResults(null);
|
|
23645
|
-
setIsOpen(false);
|
|
23646
23645
|
return;
|
|
23647
23646
|
}
|
|
23648
23647
|
setIsSearching(true);
|
|
23649
23648
|
try {
|
|
23650
|
-
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=
|
|
23649
|
+
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=8`);
|
|
23651
23650
|
if (res.ok) {
|
|
23652
|
-
|
|
23653
|
-
|
|
23654
|
-
setIsOpen(true);
|
|
23651
|
+
setResults(await res.json());
|
|
23652
|
+
setSelectedIndex(0);
|
|
23655
23653
|
}
|
|
23656
|
-
} catch (
|
|
23657
|
-
console.error("
|
|
23654
|
+
} catch (err) {
|
|
23655
|
+
console.error("Search failed:", err);
|
|
23658
23656
|
} finally {
|
|
23659
23657
|
setIsSearching(false);
|
|
23660
23658
|
}
|
|
@@ -23663,136 +23661,257 @@ function SearchBar() {
|
|
|
23663
23661
|
const value = e.target.value;
|
|
23664
23662
|
setQuery(value);
|
|
23665
23663
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
23666
|
-
debounceRef.current = setTimeout(() => doSearch(value),
|
|
23664
|
+
debounceRef.current = setTimeout(() => doSearch(value), 250);
|
|
23667
23665
|
}, [doSearch]);
|
|
23666
|
+
const close = (0, import_react.useCallback)(() => {
|
|
23667
|
+
setIsOpen(false);
|
|
23668
|
+
setQuery("");
|
|
23669
|
+
setResults(null);
|
|
23670
|
+
setSelectedIndex(0);
|
|
23671
|
+
}, []);
|
|
23668
23672
|
(0, import_react.useEffect)(() => {
|
|
23669
23673
|
const handler = (e) => {
|
|
23670
23674
|
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
23671
23675
|
e.preventDefault();
|
|
23672
|
-
|
|
23673
|
-
|
|
23674
|
-
if (e.key === "Escape") {
|
|
23675
|
-
setIsOpen(false);
|
|
23676
|
-
inputRef.current?.blur();
|
|
23676
|
+
setIsOpen(true);
|
|
23677
|
+
setTimeout(() => inputRef.current?.focus(), 50);
|
|
23677
23678
|
}
|
|
23679
|
+
if (e.key === "Escape") close();
|
|
23678
23680
|
};
|
|
23679
23681
|
window.addEventListener("keydown", handler);
|
|
23680
23682
|
return () => window.removeEventListener("keydown", handler);
|
|
23681
|
-
}, []);
|
|
23682
|
-
|
|
23683
|
-
|
|
23684
|
-
|
|
23685
|
-
|
|
23686
|
-
|
|
23687
|
-
|
|
23688
|
-
|
|
23689
|
-
|
|
23690
|
-
|
|
23691
|
-
|
|
23692
|
-
|
|
23683
|
+
}, [close]);
|
|
23684
|
+
const total = results ? results.observations.length + results.summaries.length : 0;
|
|
23685
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(
|
|
23686
|
+
"button",
|
|
23687
|
+
{
|
|
23688
|
+
onClick: () => {
|
|
23689
|
+
setIsOpen(true);
|
|
23690
|
+
setTimeout(() => inputRef.current?.focus(), 50);
|
|
23691
|
+
},
|
|
23692
|
+
className: "flex items-center gap-2.5 flex-1 max-w-md px-3 py-2 rounded-lg bg-surface-2 border border-border text-zinc-500 hover:text-zinc-300 hover:border-border-hover transition-all cursor-text"
|
|
23693
|
+
},
|
|
23694
|
+
/* @__PURE__ */ import_react.default.createElement("svg", { className: "w-4 h-4 flex-shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "11", cy: "11", r: "8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "m21 21-4.3-4.3" })),
|
|
23695
|
+
/* @__PURE__ */ import_react.default.createElement("span", { className: "text-sm" }, "Search memories..."),
|
|
23696
|
+
/* @__PURE__ */ import_react.default.createElement("kbd", { className: "ml-auto hidden sm:inline text-[11px] text-zinc-600 bg-surface-3 px-1.5 py-0.5 rounded font-mono border border-border" }, typeof navigator !== "undefined" && navigator.platform?.includes("Mac") ? "\u2318K" : "Ctrl+K")
|
|
23697
|
+
), isOpen && /* @__PURE__ */ import_react.default.createElement("div", { className: "fixed inset-0 z-[999] bg-black/60 backdrop-blur-sm animate-fade-in", onClick: close }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mx-auto mt-[12vh] w-full max-w-xl animate-scale-in px-4", onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react.default.createElement("div", { className: "bg-surface-1 border border-border rounded-xl shadow-2xl overflow-hidden" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-3 px-4 py-3.5 border-b border-border" }, /* @__PURE__ */ import_react.default.createElement("svg", { className: "w-5 h-5 text-accent-violet flex-shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react.default.createElement("circle", { cx: "11", cy: "11", r: "8" }), /* @__PURE__ */ import_react.default.createElement("path", { d: "m21 21-4.3-4.3" })), /* @__PURE__ */ import_react.default.createElement(
|
|
23693
23698
|
"input",
|
|
23694
23699
|
{
|
|
23695
23700
|
ref: inputRef,
|
|
23696
23701
|
type: "text",
|
|
23697
|
-
className: "
|
|
23698
|
-
placeholder: "Search observations, summaries...",
|
|
23702
|
+
className: "flex-1 bg-transparent border-none outline-none text-sm text-zinc-100 cmd-input",
|
|
23703
|
+
placeholder: "Search observations, summaries, concepts...",
|
|
23699
23704
|
value: query,
|
|
23700
23705
|
onChange: handleChange,
|
|
23701
|
-
|
|
23702
|
-
if (results && totalResults > 0) setIsOpen(true);
|
|
23703
|
-
}
|
|
23706
|
+
autoFocus: true
|
|
23704
23707
|
}
|
|
23705
|
-
), /* @__PURE__ */ import_react.default.createElement("
|
|
23708
|
+
), isSearching && /* @__PURE__ */ import_react.default.createElement("div", { className: "w-4 h-4 border-2 border-accent-violet/30 border-t-accent-violet rounded-full animate-spin" }), /* @__PURE__ */ import_react.default.createElement("kbd", { className: "text-[10px] text-zinc-500 bg-surface-3 px-1.5 py-0.5 rounded font-mono border border-border cursor-pointer", onClick: close }, "ESC")), results && /* @__PURE__ */ import_react.default.createElement("div", { className: "max-h-[360px] overflow-y-auto" }, total === 0 && !isSearching && query.trim() && /* @__PURE__ */ import_react.default.createElement("div", { className: "px-4 py-10 text-center" }, /* @__PURE__ */ import_react.default.createElement("p", { className: "text-sm text-zinc-500" }, 'No results for "', query, '"')), results.observations.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-4 py-2 text-[11px] font-semibold uppercase tracking-wider text-zinc-500" }, "Observations"), results.observations.map((obs, idx) => {
|
|
23709
|
+
const badge = getTypeBadgeClasses(obs.type);
|
|
23710
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { key: `obs-${obs.id}`, className: `flex items-start gap-3 px-4 py-2.5 transition-colors ${idx === selectedIndex ? "bg-surface-2" : "hover:bg-surface-2/50"}` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `w-2 h-2 rounded-full mt-1.5 flex-shrink-0 ${badge.dot}` }), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "text-sm text-zinc-200 truncate" }, obs.title), obs.text && /* @__PURE__ */ import_react.default.createElement("div", { className: "text-xs text-zinc-500 truncate mt-0.5" }, obs.text.substring(0, 100)), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-2 mt-1" }, /* @__PURE__ */ import_react.default.createElement("span", { className: `text-[10px] font-medium px-1.5 py-0.5 rounded ${badge.bg} ${badge.text}` }, obs.type), /* @__PURE__ */ import_react.default.createElement("span", { className: "text-[10px] text-zinc-600 font-mono" }, timeAgo(obs.created_at_epoch)))));
|
|
23711
|
+
})), results.summaries.length > 0 && /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "px-4 py-2 text-[11px] font-semibold uppercase tracking-wider text-zinc-500 border-t border-border" }, "Summaries"), results.summaries.map((sum) => /* @__PURE__ */ import_react.default.createElement("div", { key: `sum-${sum.id}`, className: "flex items-start gap-3 px-4 py-2.5 hover:bg-surface-2/50 transition-colors" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "w-2 h-2 rounded-full mt-1.5 flex-shrink-0 bg-accent-cyan" }), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "text-sm text-zinc-200 truncate" }, sum.request || "Session Summary"), sum.completed && /* @__PURE__ */ import_react.default.createElement("div", { className: "text-xs text-zinc-500 truncate mt-0.5" }, sum.completed.substring(0, 100)), /* @__PURE__ */ import_react.default.createElement("span", { className: "text-[10px] text-zinc-600 font-mono" }, timeAgo(sum.created_at_epoch))))))), /* @__PURE__ */ import_react.default.createElement("div", { className: "flex items-center gap-4 px-4 py-2.5 border-t border-border text-[11px] text-zinc-600" }, /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("kbd", { className: "px-1 py-0.5 rounded bg-surface-3 border border-border font-mono mr-1" }, "\u2191\u2193"), "navigate"), /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("kbd", { className: "px-1 py-0.5 rounded bg-surface-3 border border-border font-mono mr-1" }, "\u21B5"), "open"), /* @__PURE__ */ import_react.default.createElement("span", null, /* @__PURE__ */ import_react.default.createElement("kbd", { className: "px-1 py-0.5 rounded bg-surface-3 border border-border font-mono mr-1" }, "esc"), "close"))))));
|
|
23706
23712
|
}
|
|
23707
23713
|
|
|
23708
23714
|
// src/ui/viewer/components/Header.tsx
|
|
23709
23715
|
function Header({ isConnected, resolvedTheme, onThemeToggle }) {
|
|
23710
|
-
return /* @__PURE__ */ import_react2.default.createElement("header", { className: "
|
|
23716
|
+
return /* @__PURE__ */ import_react2.default.createElement("header", { className: "flex items-center gap-4 px-6 h-14 bg-surface-1 border-b border-border z-50" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "flex items-center gap-3 flex-shrink-0" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "w-8 h-8 rounded-lg bg-accent-violet flex items-center justify-center" }, /* @__PURE__ */ import_react2.default.createElement("svg", { className: "w-[18px] h-[18px] text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react2.default.createElement("path", { d: "M12 2a4 4 0 0 1 4 4c0 1.95-1.4 3.58-3.25 3.93a1 1 0 0 0-.75.97V13" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M12 2a4 4 0 0 0-4 4c0 1.95 1.4 3.58 3.25 3.93a1 1 0 0 1 .75.97V13" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M9 18h6" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M10 22h4" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M12 13v5" }))), /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h1", { className: "text-[15px] font-bold text-zinc-100 leading-none" }, "ContextKit"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "text-[11px] text-zinc-500 mt-0.5 block" }, "Memory Dashboard"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "hidden md:block w-px h-6 bg-border" }), /* @__PURE__ */ import_react2.default.createElement(SearchBar, null), /* @__PURE__ */ import_react2.default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ import_react2.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 rounded-lg bg-surface-2 border border-border" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: `w-2 h-2 rounded-full ${isConnected ? "bg-accent-green animate-pulse-dot" : "bg-zinc-500"}` }), /* @__PURE__ */ import_react2.default.createElement("span", { className: `text-xs font-medium ${isConnected ? "text-accent-green" : "text-zinc-500"}` }, isConnected ? "Live" : "Offline")), /* @__PURE__ */ import_react2.default.createElement(
|
|
23711
23717
|
"button",
|
|
23712
23718
|
{
|
|
23713
|
-
className: "theme-btn",
|
|
23714
23719
|
onClick: onThemeToggle,
|
|
23715
|
-
|
|
23720
|
+
className: "w-8 h-8 rounded-lg bg-surface-2 border border-border text-zinc-400 hover:text-zinc-100 hover:bg-surface-3 hover:border-border-hover transition-all flex items-center justify-center",
|
|
23721
|
+
title: resolvedTheme === "dark" ? "Light mode" : "Dark mode"
|
|
23716
23722
|
},
|
|
23717
|
-
resolvedTheme === "dark" ? "
|
|
23718
|
-
))
|
|
23723
|
+
resolvedTheme === "dark" ? /* @__PURE__ */ import_react2.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "12", cy: "12", r: "4" }), /* @__PURE__ */ import_react2.default.createElement("path", { d: "M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" })) : /* @__PURE__ */ import_react2.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react2.default.createElement("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }))
|
|
23724
|
+
));
|
|
23719
23725
|
}
|
|
23720
23726
|
|
|
23721
23727
|
// src/ui/viewer/components/Sidebar.tsx
|
|
23722
23728
|
var import_react3 = __toESM(require_react(), 1);
|
|
23723
|
-
var
|
|
23724
|
-
"file-write": "
|
|
23725
|
-
"
|
|
23726
|
-
"
|
|
23727
|
-
"
|
|
23728
|
-
"
|
|
23729
|
+
var TYPE_CONFIG = {
|
|
23730
|
+
"file-write": { color: "bg-accent-green", label: "File writes" },
|
|
23731
|
+
"file-read": { color: "bg-accent-cyan", label: "File reads" },
|
|
23732
|
+
"command": { color: "bg-accent-amber", label: "Commands" },
|
|
23733
|
+
"research": { color: "bg-accent-blue", label: "Research" },
|
|
23734
|
+
"delegation": { color: "bg-accent-violet", label: "Delegations" },
|
|
23735
|
+
"tool-use": { color: "bg-zinc-400", label: "Tool usage" }
|
|
23729
23736
|
};
|
|
23737
|
+
var PROJECT_COLORS = [
|
|
23738
|
+
{ bg: "bg-accent-violet/15", text: "text-accent-violet", ring: "ring-accent-violet/30" },
|
|
23739
|
+
{ bg: "bg-accent-blue/15", text: "text-accent-blue", ring: "ring-accent-blue/30" },
|
|
23740
|
+
{ bg: "bg-accent-green/15", text: "text-accent-green", ring: "ring-accent-green/30" },
|
|
23741
|
+
{ bg: "bg-accent-amber/15", text: "text-accent-amber", ring: "ring-accent-amber/30" },
|
|
23742
|
+
{ bg: "bg-accent-rose/15", text: "text-accent-rose", ring: "ring-accent-rose/30" },
|
|
23743
|
+
{ bg: "bg-accent-cyan/15", text: "text-accent-cyan", ring: "ring-accent-cyan/30" },
|
|
23744
|
+
{ bg: "bg-accent-orange/15", text: "text-accent-orange", ring: "ring-accent-orange/30" }
|
|
23745
|
+
];
|
|
23746
|
+
function getProjectColorByName(name) {
|
|
23747
|
+
let hash = 0;
|
|
23748
|
+
for (let i = 0; i < name.length; i++) hash = (hash << 5) - hash + name.charCodeAt(i) | 0;
|
|
23749
|
+
return PROJECT_COLORS[Math.abs(hash) % PROJECT_COLORS.length];
|
|
23750
|
+
}
|
|
23730
23751
|
function Sidebar({
|
|
23731
23752
|
projects,
|
|
23732
23753
|
currentFilter,
|
|
23733
23754
|
onFilterChange,
|
|
23734
23755
|
activeTypes,
|
|
23735
23756
|
onToggleType,
|
|
23736
|
-
stats
|
|
23757
|
+
stats,
|
|
23758
|
+
getDisplayName,
|
|
23759
|
+
onRenameProject
|
|
23737
23760
|
}) {
|
|
23738
|
-
|
|
23739
|
-
|
|
23740
|
-
|
|
23741
|
-
|
|
23742
|
-
|
|
23743
|
-
|
|
23744
|
-
|
|
23745
|
-
|
|
23746
|
-
|
|
23761
|
+
const [editingProject, setEditingProject] = (0, import_react3.useState)(null);
|
|
23762
|
+
const [editValue, setEditValue] = (0, import_react3.useState)("");
|
|
23763
|
+
const editInputRef = (0, import_react3.useRef)(null);
|
|
23764
|
+
(0, import_react3.useEffect)(() => {
|
|
23765
|
+
if (editingProject && editInputRef.current) {
|
|
23766
|
+
editInputRef.current.focus();
|
|
23767
|
+
editInputRef.current.select();
|
|
23768
|
+
}
|
|
23769
|
+
}, [editingProject]);
|
|
23770
|
+
const startEditing = (project, e) => {
|
|
23771
|
+
e.stopPropagation();
|
|
23772
|
+
setEditingProject(project);
|
|
23773
|
+
setEditValue(getDisplayName(project));
|
|
23774
|
+
};
|
|
23775
|
+
const confirmEdit = async () => {
|
|
23776
|
+
if (editingProject && editValue.trim()) {
|
|
23777
|
+
await onRenameProject(editingProject, editValue.trim());
|
|
23778
|
+
}
|
|
23779
|
+
setEditingProject(null);
|
|
23780
|
+
};
|
|
23781
|
+
const cancelEdit = () => {
|
|
23782
|
+
setEditingProject(null);
|
|
23783
|
+
setEditValue("");
|
|
23784
|
+
};
|
|
23785
|
+
const handleKeyDown = (e) => {
|
|
23786
|
+
if (e.key === "Enter") confirmEdit();
|
|
23787
|
+
if (e.key === "Escape") cancelEdit();
|
|
23788
|
+
};
|
|
23789
|
+
return /* @__PURE__ */ import_react3.default.createElement("aside", { className: "h-full overflow-y-auto bg-surface-1 border-r border-border flex flex-col" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "p-4" }, /* @__PURE__ */ import_react3.default.createElement("h3", { className: "text-[11px] font-semibold uppercase tracking-wider text-zinc-500 mb-3 px-2" }, "Projects"), /* @__PURE__ */ import_react3.default.createElement(
|
|
23790
|
+
"button",
|
|
23747
23791
|
{
|
|
23748
|
-
|
|
23749
|
-
className: `
|
|
23750
|
-
onClick: () => onFilterChange(project)
|
|
23792
|
+
onClick: () => onFilterChange(""),
|
|
23793
|
+
className: `w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-all text-left mb-0.5 ${currentFilter === "" ? "bg-accent-violet/10 text-accent-violet font-semibold" : "text-zinc-400 hover:text-zinc-200 hover:bg-surface-2"}`
|
|
23751
23794
|
},
|
|
23752
|
-
|
|
23753
|
-
|
|
23754
|
-
"
|
|
23755
|
-
|
|
23756
|
-
|
|
23757
|
-
|
|
23758
|
-
|
|
23759
|
-
|
|
23760
|
-
|
|
23795
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: "w-7 h-7 rounded-md bg-accent-violet/15 flex items-center justify-center flex-shrink-0" }, /* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-3.5 h-3.5 text-accent-violet", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react3.default.createElement("rect", { x: "3", y: "3", width: "7", height: "7" }), /* @__PURE__ */ import_react3.default.createElement("rect", { x: "14", y: "3", width: "7", height: "7" }), /* @__PURE__ */ import_react3.default.createElement("rect", { x: "3", y: "14", width: "7", height: "7" }), /* @__PURE__ */ import_react3.default.createElement("rect", { x: "14", y: "14", width: "7", height: "7" }))),
|
|
23796
|
+
/* @__PURE__ */ import_react3.default.createElement("span", { className: "flex-1" }, "All projects"),
|
|
23797
|
+
/* @__PURE__ */ import_react3.default.createElement("span", { className: "text-xs text-zinc-600 font-mono tabular-nums" }, projects.length)
|
|
23798
|
+
), /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex flex-col gap-0.5 mt-1" }, projects.map((project) => {
|
|
23799
|
+
const pc = getProjectColorByName(project);
|
|
23800
|
+
const isEditing = editingProject === project;
|
|
23801
|
+
const isActive = currentFilter === project;
|
|
23802
|
+
const initials = getDisplayName(project).substring(0, 2).toUpperCase();
|
|
23803
|
+
return /* @__PURE__ */ import_react3.default.createElement("div", { key: project, className: "group" }, isEditing ? /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex items-center gap-2 px-3 py-1.5 rounded-lg bg-surface-3 border border-border" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
23804
|
+
"input",
|
|
23805
|
+
{
|
|
23806
|
+
ref: editInputRef,
|
|
23807
|
+
type: "text",
|
|
23808
|
+
value: editValue,
|
|
23809
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
23810
|
+
onKeyDown: handleKeyDown,
|
|
23811
|
+
onBlur: confirmEdit,
|
|
23812
|
+
className: "flex-1 min-w-0 bg-transparent border-none outline-none text-sm text-zinc-200"
|
|
23813
|
+
}
|
|
23814
|
+
), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: confirmEdit, className: "text-accent-green hover:text-accent-green/80 p-0.5" }, /* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5" }, /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "20 6 9 17 4 12" }))), /* @__PURE__ */ import_react3.default.createElement("button", { onClick: cancelEdit, className: "text-zinc-500 hover:text-zinc-300 p-0.5" }, /* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5" }, /* @__PURE__ */ import_react3.default.createElement("path", { d: "M18 6 6 18M6 6l12 12" })))) : /* @__PURE__ */ import_react3.default.createElement(
|
|
23815
|
+
"button",
|
|
23816
|
+
{
|
|
23817
|
+
onClick: () => onFilterChange(project),
|
|
23818
|
+
className: `w-full flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-all text-left ${isActive ? "bg-surface-3 text-zinc-100 font-medium" : "text-zinc-400 hover:text-zinc-200 hover:bg-surface-2"}`
|
|
23819
|
+
},
|
|
23820
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: `w-7 h-7 rounded-md flex items-center justify-center flex-shrink-0 text-[11px] font-bold ${pc.bg} ${pc.text}` }, initials),
|
|
23821
|
+
/* @__PURE__ */ import_react3.default.createElement("span", { className: "flex-1 truncate" }, getDisplayName(project)),
|
|
23822
|
+
/* @__PURE__ */ import_react3.default.createElement(
|
|
23823
|
+
"span",
|
|
23824
|
+
{
|
|
23825
|
+
onClick: (e) => startEditing(project, e),
|
|
23826
|
+
className: "opacity-0 group-hover:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all p-0.5",
|
|
23827
|
+
title: "Rename"
|
|
23828
|
+
},
|
|
23829
|
+
/* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react3.default.createElement("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }))
|
|
23830
|
+
)
|
|
23831
|
+
));
|
|
23832
|
+
}))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mx-4 h-px bg-border" }), /* @__PURE__ */ import_react3.default.createElement("div", { className: "p-4" }, /* @__PURE__ */ import_react3.default.createElement("h3", { className: "text-[11px] font-semibold uppercase tracking-wider text-zinc-500 mb-3 px-2" }, "Filters"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "flex flex-col gap-0.5" }, Object.entries(TYPE_CONFIG).map(([type, config]) => {
|
|
23833
|
+
const isActive = activeTypes.has(type);
|
|
23834
|
+
return /* @__PURE__ */ import_react3.default.createElement(
|
|
23835
|
+
"label",
|
|
23836
|
+
{
|
|
23837
|
+
key: type,
|
|
23838
|
+
className: `flex items-center gap-3 px-3 py-2 rounded-lg text-sm cursor-pointer transition-all ${isActive ? "text-zinc-300 hover:text-zinc-100" : "text-zinc-600 hover:text-zinc-400"}`
|
|
23839
|
+
},
|
|
23840
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: `w-4 h-4 rounded border flex items-center justify-center flex-shrink-0 transition-all ${isActive ? "bg-accent-violet border-accent-violet" : "bg-transparent border-zinc-600"}` }, isActive && /* @__PURE__ */ import_react3.default.createElement("svg", { className: "w-2.5 h-2.5 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3" }, /* @__PURE__ */ import_react3.default.createElement("polyline", { points: "20 6 9 17 4 12" }))),
|
|
23841
|
+
/* @__PURE__ */ import_react3.default.createElement("input", { type: "checkbox", checked: isActive, onChange: () => onToggleType(type), className: "sr-only" }),
|
|
23842
|
+
/* @__PURE__ */ import_react3.default.createElement("div", { className: `w-2.5 h-2.5 rounded-full flex-shrink-0 ${config.color} ${isActive ? "opacity-100" : "opacity-30"}` }),
|
|
23843
|
+
/* @__PURE__ */ import_react3.default.createElement("span", { className: "flex-1" }, config.label)
|
|
23844
|
+
);
|
|
23845
|
+
}))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mx-4 h-px bg-border" }), /* @__PURE__ */ import_react3.default.createElement("div", { className: "p-4" }, /* @__PURE__ */ import_react3.default.createElement("h3", { className: "text-[11px] font-semibold uppercase tracking-wider text-zinc-500 mb-3 px-2" }, "Statistics"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "grid grid-cols-2 gap-2" }, [
|
|
23846
|
+
{ label: "Observations", value: stats.observations, color: "text-accent-violet" },
|
|
23847
|
+
{ label: "Summaries", value: stats.summaries, color: "text-accent-cyan" },
|
|
23848
|
+
{ label: "Prompts", value: stats.prompts, color: "text-accent-amber" },
|
|
23849
|
+
{ label: "Projects", value: projects.length, color: "text-accent-green" }
|
|
23850
|
+
].map((item) => /* @__PURE__ */ import_react3.default.createElement("div", { key: item.label, className: "rounded-lg bg-surface-2 border border-border px-3 py-3 text-center" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: `text-xl font-bold tabular-nums ${item.color}` }, item.value), /* @__PURE__ */ import_react3.default.createElement("div", { className: "text-[10px] uppercase tracking-wider text-zinc-600 mt-1" }, item.label))))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mt-auto px-4 py-4" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "text-[10px] text-zinc-700 font-mono text-center" }, "ContextKit v1.4.0")));
|
|
23761
23851
|
}
|
|
23762
23852
|
|
|
23763
23853
|
// src/ui/viewer/components/Feed.tsx
|
|
23764
23854
|
var import_react4 = __toESM(require_react(), 1);
|
|
23765
|
-
|
|
23855
|
+
var TYPE_STYLES = {
|
|
23856
|
+
"file-write": { border: "border-l-emerald-500", bg: "bg-emerald-500/10", text: "text-emerald-400", dot: "bg-emerald-500", label: "file-write" },
|
|
23857
|
+
"file-read": { border: "border-l-cyan-500", bg: "bg-cyan-500/10", text: "text-cyan-400", dot: "bg-cyan-500", label: "file-read" },
|
|
23858
|
+
"command": { border: "border-l-amber-500", bg: "bg-amber-500/10", text: "text-amber-400", dot: "bg-amber-500", label: "command" },
|
|
23859
|
+
"research": { border: "border-l-blue-500", bg: "bg-blue-500/10", text: "text-blue-400", dot: "bg-blue-500", label: "research" },
|
|
23860
|
+
"delegation": { border: "border-l-violet-500", bg: "bg-violet-500/10", text: "text-violet-400", dot: "bg-violet-500", label: "delegation" },
|
|
23861
|
+
"tool-use": { border: "border-l-zinc-500", bg: "bg-zinc-500/10", text: "text-zinc-400", dot: "bg-zinc-500", label: "tool-use" }
|
|
23862
|
+
};
|
|
23863
|
+
function getTypeStyle(type) {
|
|
23864
|
+
return TYPE_STYLES[type] || TYPE_STYLES["tool-use"];
|
|
23865
|
+
}
|
|
23866
|
+
function Feed({ observations, summaries, prompts, onLoadMore, isLoading, hasMore, getDisplayName }) {
|
|
23766
23867
|
const items = [...observations, ...summaries, ...prompts].sort(
|
|
23767
23868
|
(a, b) => b.created_at_epoch - a.created_at_epoch
|
|
23768
23869
|
);
|
|
23769
|
-
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "
|
|
23870
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "space-y-3" }, items.map((item, index) => {
|
|
23871
|
+
const stagger = index < 8 ? `stagger-${index + 1}` : "";
|
|
23770
23872
|
if ("type" in item && "title" in item) {
|
|
23771
|
-
return /* @__PURE__ */ import_react4.default.createElement(
|
|
23873
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { key: `obs-${item.id}`, className: `opacity-0 animate-slide-up ${stagger}` }, /* @__PURE__ */ import_react4.default.createElement(ObservationCard, { obs: item, getDisplayName }));
|
|
23772
23874
|
} else if ("request" in item) {
|
|
23773
|
-
return /* @__PURE__ */ import_react4.default.createElement(
|
|
23875
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { key: `sum-${item.id}`, className: `opacity-0 animate-slide-up ${stagger}` }, /* @__PURE__ */ import_react4.default.createElement(SummaryCard, { summary: item, getDisplayName }));
|
|
23774
23876
|
} else {
|
|
23775
|
-
return /* @__PURE__ */ import_react4.default.createElement(
|
|
23877
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { key: `prompt-${item.id}`, className: `opacity-0 animate-slide-up ${stagger}` }, /* @__PURE__ */ import_react4.default.createElement(PromptCard, { prompt: item, getDisplayName }));
|
|
23776
23878
|
}
|
|
23777
|
-
}), hasMore && /* @__PURE__ */ import_react4.default.createElement(
|
|
23879
|
+
}), hasMore && items.length > 0 && /* @__PURE__ */ import_react4.default.createElement("div", { className: "pt-2" }, /* @__PURE__ */ import_react4.default.createElement(
|
|
23778
23880
|
"button",
|
|
23779
23881
|
{
|
|
23780
|
-
className: "load-more-btn",
|
|
23781
23882
|
onClick: onLoadMore,
|
|
23782
|
-
disabled: isLoading
|
|
23883
|
+
disabled: isLoading,
|
|
23884
|
+
className: "flex items-center justify-center gap-2 w-full py-3 rounded-lg transition-all text-sm font-medium bg-surface-2 border border-border text-zinc-400 hover:bg-surface-3 hover:text-zinc-200 hover:border-border-hover disabled:opacity-40 disabled:cursor-not-allowed"
|
|
23783
23885
|
},
|
|
23784
|
-
isLoading ? "
|
|
23785
|
-
), items.length === 0 && !isLoading && /* @__PURE__ */ import_react4.default.createElement("div", { className: "
|
|
23886
|
+
isLoading ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-4 h-4 border-2 border-accent-violet/30 border-t-accent-violet rounded-full animate-spin" }), "Loading...") : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-4 h-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "m6 9 6 6 6-6" })), "Load more")
|
|
23887
|
+
)), items.length === 0 && !isLoading && /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex flex-col items-center justify-center py-20 text-center" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-16 h-16 rounded-2xl bg-surface-2 border border-border flex items-center justify-center mb-5" }, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-7 h-7 text-zinc-600", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M12 2a4 4 0 0 1 4 4c0 1.95-1.4 3.58-3.25 3.93a1 1 0 0 0-.75.97V13" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M12 2a4 4 0 0 0-4 4c0 1.95 1.4 3.58 3.25 3.93a1 1 0 0 1 .75.97V13" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M9 18h6" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M10 22h4" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M12 13v5" }))), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-base font-semibold text-zinc-300 mb-2" }, "No memories yet"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-sm text-zinc-500 max-w-xs leading-relaxed" }, "Start a coding session to begin capturing context automatically.")), items.length === 0 && isLoading && /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex flex-col items-center justify-center py-20" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-6 h-6 border-2 border-accent-violet/30 border-t-accent-violet rounded-full animate-spin mb-4" }), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-sm text-zinc-500" }, "Loading memories...")));
|
|
23786
23888
|
}
|
|
23787
|
-
function ObservationCard({ obs }) {
|
|
23788
|
-
const
|
|
23789
|
-
|
|
23889
|
+
function ObservationCard({ obs, getDisplayName }) {
|
|
23890
|
+
const style = getTypeStyle(obs.type);
|
|
23891
|
+
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
23892
|
+
const longContent = obs.text && obs.text.length > 300;
|
|
23893
|
+
const displayText = longContent && !expanded ? obs.text.substring(0, 280) + "..." : obs.text;
|
|
23894
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: `bg-surface-1 border border-border rounded-lg border-l-[3px] ${style.border} shadow-card hover:shadow-card-hover hover:border-border-hover transition-all` }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pt-4 pb-2" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide px-2 py-0.5 rounded-md ${style.bg} ${style.text}` }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `w-1.5 h-1.5 rounded-full ${style.dot}` }), style.label), /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center text-[11px] font-medium px-2 py-0.5 rounded-md bg-accent-violet/10 text-accent-violet" }, getDisplayName(obs.project)), /* @__PURE__ */ import_react4.default.createElement("span", { className: "text-xs text-zinc-600 font-mono ml-auto" }, timeAgo(obs.created_at_epoch))), /* @__PURE__ */ import_react4.default.createElement("h3", { className: "text-[15px] font-semibold text-zinc-100 leading-snug" }, obs.title)), obs.subtitle && /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pb-1" }, /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-xs italic text-zinc-500" }, obs.subtitle)), obs.text && /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pb-3" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "text-sm text-zinc-400 leading-relaxed whitespace-pre-wrap break-words" }, displayText), longContent && /* @__PURE__ */ import_react4.default.createElement(
|
|
23895
|
+
"button",
|
|
23896
|
+
{
|
|
23897
|
+
onClick: () => setExpanded(!expanded),
|
|
23898
|
+
className: "text-xs text-accent-violet hover:text-accent-violet/80 mt-1.5 font-medium transition-colors"
|
|
23899
|
+
},
|
|
23900
|
+
expanded ? "Show less" : "Show more"
|
|
23901
|
+
)), obs.narrative && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mx-4 mb-3 p-3 rounded-md bg-surface-2 border border-border" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "block text-[10px] font-semibold uppercase tracking-wider text-blue-400 mb-1" }, "Narrative"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-xs text-zinc-400 leading-relaxed" }, obs.narrative)), obs.facts && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mx-4 mb-3 p-3 rounded-md bg-surface-2 border border-border" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "block text-[10px] font-semibold uppercase tracking-wider text-cyan-400 mb-1" }, "Facts"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-xs text-zinc-400 leading-relaxed" }, obs.facts)), (obs.files_modified || obs.files_read) && /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex flex-wrap gap-2 px-4 pb-3" }, obs.files_modified && /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center gap-1.5 text-[11px] font-medium text-emerald-400 bg-emerald-500/10 px-2 py-0.5 rounded-md" }, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M14 2v6h6" })), obs.files_modified.split(",").length, " modified"), obs.files_read && /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center gap-1.5 text-[11px] font-medium text-blue-400 bg-blue-500/10 px-2 py-0.5 rounded-md" }, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7Z" })), obs.files_read.split(",").length, " read")), obs.concepts && /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex flex-wrap gap-1.5 px-4 pb-4" }, obs.concepts.split(", ").map((concept, i) => /* @__PURE__ */ import_react4.default.createElement("span", { key: i, className: "text-[11px] text-zinc-500 bg-surface-3 px-2 py-0.5 rounded-md border border-border" }, concept))));
|
|
23790
23902
|
}
|
|
23791
|
-
function SummaryCard({ summary }) {
|
|
23792
|
-
|
|
23903
|
+
function SummaryCard({ summary, getDisplayName }) {
|
|
23904
|
+
const sections = [
|
|
23905
|
+
{ label: "Investigated", value: summary.investigated, color: "text-blue-400" },
|
|
23906
|
+
{ label: "Learned", value: summary.learned, color: "text-emerald-400" },
|
|
23907
|
+
{ label: "Completed", value: summary.completed, color: "text-violet-400" },
|
|
23908
|
+
{ label: "Next steps", value: summary.next_steps, color: "text-amber-400" },
|
|
23909
|
+
{ label: "Notes", value: summary.notes, color: "text-zinc-400" }
|
|
23910
|
+
].filter((s) => s.value);
|
|
23911
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "bg-surface-1 border border-border rounded-lg border-l-[3px] border-l-cyan-500 shadow-card hover:shadow-card-hover hover:border-border-hover transition-all" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pt-4 pb-2" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide px-2 py-0.5 rounded-md bg-cyan-500/10 text-cyan-400" }, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" }), /* @__PURE__ */ import_react4.default.createElement("path", { d: "M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" })), "Summary"), /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center text-[11px] font-medium px-2 py-0.5 rounded-md bg-accent-violet/10 text-accent-violet" }, getDisplayName(summary.project)), /* @__PURE__ */ import_react4.default.createElement("span", { className: "text-xs text-zinc-600 font-mono ml-auto" }, timeAgo(summary.created_at_epoch))), summary.request && /* @__PURE__ */ import_react4.default.createElement("h3", { className: "text-[15px] font-semibold text-zinc-100 leading-snug" }, summary.request)), /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pb-4 space-y-2" }, sections.map(({ label, value, color }) => /* @__PURE__ */ import_react4.default.createElement("div", { key: label, className: "p-3 rounded-md bg-surface-2 border border-border" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `block text-[10px] font-semibold uppercase tracking-wider mb-1 ${color}` }, label), /* @__PURE__ */ import_react4.default.createElement("p", { className: "text-xs text-zinc-400 leading-relaxed" }, value)))));
|
|
23793
23912
|
}
|
|
23794
|
-
function PromptCard({ prompt }) {
|
|
23795
|
-
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "card card
|
|
23913
|
+
function PromptCard({ prompt, getDisplayName }) {
|
|
23914
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "bg-surface-1 border border-border rounded-lg border-l-[3px] border-l-rose-500 shadow-card hover:shadow-card-hover hover:border-border-hover transition-all" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pt-4 pb-2" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide px-2 py-0.5 rounded-md bg-rose-500/10 text-rose-400" }, /* @__PURE__ */ import_react4.default.createElement("svg", { className: "w-3 h-3", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })), "Prompt #", prompt.prompt_number), /* @__PURE__ */ import_react4.default.createElement("span", { className: "inline-flex items-center text-[11px] font-medium px-2 py-0.5 rounded-md bg-accent-violet/10 text-accent-violet" }, getDisplayName(prompt.project)), /* @__PURE__ */ import_react4.default.createElement("span", { className: "text-xs text-zinc-600 font-mono ml-auto" }, timeAgo(prompt.created_at_epoch)))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "px-4 pb-4" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "p-3 rounded-md bg-surface-0 border border-border font-mono text-sm text-zinc-300 leading-relaxed whitespace-pre-wrap break-words" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "text-rose-400 select-none mr-2" }, "$"), prompt.prompt_text)));
|
|
23796
23915
|
}
|
|
23797
23916
|
|
|
23798
23917
|
// src/ui/viewer/hooks/useSSE.ts
|
|
@@ -23820,7 +23939,7 @@ function useSSE() {
|
|
|
23820
23939
|
setState((prev) => ({ ...prev, observations }));
|
|
23821
23940
|
}
|
|
23822
23941
|
} catch (err) {
|
|
23823
|
-
console.error("
|
|
23942
|
+
console.error("Failed to fetch observations:", err);
|
|
23824
23943
|
}
|
|
23825
23944
|
};
|
|
23826
23945
|
const fetchSummaries = async () => {
|
|
@@ -23831,7 +23950,7 @@ function useSSE() {
|
|
|
23831
23950
|
setState((prev) => ({ ...prev, summaries }));
|
|
23832
23951
|
}
|
|
23833
23952
|
} catch (err) {
|
|
23834
|
-
console.error("
|
|
23953
|
+
console.error("Failed to fetch summaries:", err);
|
|
23835
23954
|
}
|
|
23836
23955
|
};
|
|
23837
23956
|
const fetchPrompts = async () => {
|
|
@@ -23842,7 +23961,7 @@ function useSSE() {
|
|
|
23842
23961
|
setState((prev) => ({ ...prev, prompts }));
|
|
23843
23962
|
}
|
|
23844
23963
|
} catch (err) {
|
|
23845
|
-
console.error("
|
|
23964
|
+
console.error("Failed to fetch prompts:", err);
|
|
23846
23965
|
}
|
|
23847
23966
|
};
|
|
23848
23967
|
const fetchProjects = async () => {
|
|
@@ -23853,7 +23972,7 @@ function useSSE() {
|
|
|
23853
23972
|
setState((prev) => ({ ...prev, projects }));
|
|
23854
23973
|
}
|
|
23855
23974
|
} catch (err) {
|
|
23856
|
-
console.error("
|
|
23975
|
+
console.error("Failed to fetch projects:", err);
|
|
23857
23976
|
}
|
|
23858
23977
|
};
|
|
23859
23978
|
const connect = () => {
|
|
@@ -23901,8 +24020,8 @@ function useSSE() {
|
|
|
23901
24020
|
// src/ui/viewer/hooks/useTheme.ts
|
|
23902
24021
|
var import_react6 = __toESM(require_react(), 1);
|
|
23903
24022
|
function useTheme() {
|
|
23904
|
-
const [preference, setPreference] = (0, import_react6.useState)("
|
|
23905
|
-
const [resolvedTheme, setResolvedTheme] = (0, import_react6.useState)("
|
|
24023
|
+
const [preference, setPreference] = (0, import_react6.useState)("dark");
|
|
24024
|
+
const [resolvedTheme, setResolvedTheme] = (0, import_react6.useState)("dark");
|
|
23906
24025
|
(0, import_react6.useEffect)(() => {
|
|
23907
24026
|
const saved = localStorage.getItem("kiro-memory-theme");
|
|
23908
24027
|
if (saved) {
|
|
@@ -23910,19 +24029,31 @@ function useTheme() {
|
|
|
23910
24029
|
}
|
|
23911
24030
|
}, []);
|
|
23912
24031
|
(0, import_react6.useEffect)(() => {
|
|
23913
|
-
|
|
23914
|
-
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
24032
|
+
let resolved;
|
|
24033
|
+
if (preference === "system") {
|
|
24034
|
+
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
24035
|
+
resolved = prefersDark ? "dark" : "light";
|
|
24036
|
+
} else {
|
|
24037
|
+
resolved = preference;
|
|
24038
|
+
}
|
|
24039
|
+
setResolvedTheme(resolved);
|
|
24040
|
+
if (resolved === "dark") {
|
|
24041
|
+
document.documentElement.classList.add("dark");
|
|
24042
|
+
} else {
|
|
24043
|
+
document.documentElement.classList.remove("dark");
|
|
24044
|
+
}
|
|
24045
|
+
}, [preference]);
|
|
24046
|
+
(0, import_react6.useEffect)(() => {
|
|
23922
24047
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
23923
24048
|
const handler = (e) => {
|
|
23924
24049
|
if (preference === "system") {
|
|
23925
|
-
|
|
24050
|
+
const resolved = e.matches ? "dark" : "light";
|
|
24051
|
+
setResolvedTheme(resolved);
|
|
24052
|
+
if (resolved === "dark") {
|
|
24053
|
+
document.documentElement.classList.add("dark");
|
|
24054
|
+
} else {
|
|
24055
|
+
document.documentElement.classList.remove("dark");
|
|
24056
|
+
}
|
|
23926
24057
|
}
|
|
23927
24058
|
};
|
|
23928
24059
|
mediaQuery.addEventListener("change", handler);
|
|
@@ -23935,6 +24066,48 @@ function useTheme() {
|
|
|
23935
24066
|
return { preference, resolvedTheme, setThemePreference };
|
|
23936
24067
|
}
|
|
23937
24068
|
|
|
24069
|
+
// src/ui/viewer/hooks/useProjectAliases.ts
|
|
24070
|
+
var import_react7 = __toESM(require_react(), 1);
|
|
24071
|
+
function useProjectAliases() {
|
|
24072
|
+
const [aliases, setAliases] = (0, import_react7.useState)({});
|
|
24073
|
+
const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
|
|
24074
|
+
(0, import_react7.useEffect)(() => {
|
|
24075
|
+
const fetchAliases = async () => {
|
|
24076
|
+
try {
|
|
24077
|
+
const res = await fetch("/api/project-aliases");
|
|
24078
|
+
if (res.ok) {
|
|
24079
|
+
const data = await res.json();
|
|
24080
|
+
setAliases(data);
|
|
24081
|
+
}
|
|
24082
|
+
} catch (err) {
|
|
24083
|
+
console.error("Failed to fetch project aliases:", err);
|
|
24084
|
+
}
|
|
24085
|
+
};
|
|
24086
|
+
fetchAliases();
|
|
24087
|
+
}, []);
|
|
24088
|
+
const getDisplayName = (0, import_react7.useCallback)((project) => {
|
|
24089
|
+
return aliases[project] || project;
|
|
24090
|
+
}, [aliases]);
|
|
24091
|
+
const updateAlias = (0, import_react7.useCallback)(async (project, displayName) => {
|
|
24092
|
+
setIsLoading(true);
|
|
24093
|
+
try {
|
|
24094
|
+
const res = await fetch(`/api/project-aliases/${encodeURIComponent(project)}`, {
|
|
24095
|
+
method: "PUT",
|
|
24096
|
+
headers: { "Content-Type": "application/json" },
|
|
24097
|
+
body: JSON.stringify({ displayName })
|
|
24098
|
+
});
|
|
24099
|
+
if (res.ok) {
|
|
24100
|
+
setAliases((prev) => ({ ...prev, [project]: displayName }));
|
|
24101
|
+
}
|
|
24102
|
+
} catch (err) {
|
|
24103
|
+
console.error("Failed to update project alias:", err);
|
|
24104
|
+
} finally {
|
|
24105
|
+
setIsLoading(false);
|
|
24106
|
+
}
|
|
24107
|
+
}, []);
|
|
24108
|
+
return { aliases, getDisplayName, updateAlias, isLoading };
|
|
24109
|
+
}
|
|
24110
|
+
|
|
23938
24111
|
// src/ui/viewer/utils/data.ts
|
|
23939
24112
|
function mergeAndDeduplicateByProject(liveData, paginatedData) {
|
|
23940
24113
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -23959,39 +24132,40 @@ function mergeAndDeduplicateByProject(liveData, paginatedData) {
|
|
|
23959
24132
|
}
|
|
23960
24133
|
|
|
23961
24134
|
// src/ui/viewer/App.tsx
|
|
23962
|
-
var TYPE_FILTERS = ["file-write", "command", "research", "delegation", "tool-use"];
|
|
24135
|
+
var TYPE_FILTERS = ["file-write", "file-read", "command", "research", "delegation", "tool-use"];
|
|
23963
24136
|
function App() {
|
|
23964
|
-
const [currentFilter, setCurrentFilter] = (0,
|
|
23965
|
-
const [activeTypes, setActiveTypes] = (0,
|
|
23966
|
-
const [paginatedObservations, setPaginatedObservations] = (0,
|
|
23967
|
-
const [paginatedSummaries, setPaginatedSummaries] = (0,
|
|
23968
|
-
const [paginatedPrompts, setPaginatedPrompts] = (0,
|
|
23969
|
-
const [isLoadingMore, setIsLoadingMore] = (0,
|
|
23970
|
-
const [hasMore, setHasMore] = (0,
|
|
24137
|
+
const [currentFilter, setCurrentFilter] = (0, import_react8.useState)("");
|
|
24138
|
+
const [activeTypes, setActiveTypes] = (0, import_react8.useState)(new Set(TYPE_FILTERS));
|
|
24139
|
+
const [paginatedObservations, setPaginatedObservations] = (0, import_react8.useState)([]);
|
|
24140
|
+
const [paginatedSummaries, setPaginatedSummaries] = (0, import_react8.useState)([]);
|
|
24141
|
+
const [paginatedPrompts, setPaginatedPrompts] = (0, import_react8.useState)([]);
|
|
24142
|
+
const [isLoadingMore, setIsLoadingMore] = (0, import_react8.useState)(false);
|
|
24143
|
+
const [hasMore, setHasMore] = (0, import_react8.useState)(true);
|
|
23971
24144
|
const { observations, summaries, prompts, projects, isConnected } = useSSE();
|
|
23972
24145
|
const { resolvedTheme, setThemePreference } = useTheme();
|
|
23973
|
-
const
|
|
24146
|
+
const { getDisplayName, updateAlias } = useProjectAliases();
|
|
24147
|
+
const allObservations = (0, import_react8.useMemo)(() => {
|
|
23974
24148
|
if (currentFilter) return paginatedObservations;
|
|
23975
24149
|
return mergeAndDeduplicateByProject(observations, paginatedObservations);
|
|
23976
24150
|
}, [observations, paginatedObservations, currentFilter]);
|
|
23977
|
-
const allSummaries = (0,
|
|
24151
|
+
const allSummaries = (0, import_react8.useMemo)(() => {
|
|
23978
24152
|
if (currentFilter) return paginatedSummaries;
|
|
23979
24153
|
return mergeAndDeduplicateByProject(summaries, paginatedSummaries);
|
|
23980
24154
|
}, [summaries, paginatedSummaries, currentFilter]);
|
|
23981
|
-
const allPrompts = (0,
|
|
24155
|
+
const allPrompts = (0, import_react8.useMemo)(() => {
|
|
23982
24156
|
if (currentFilter) return paginatedPrompts;
|
|
23983
24157
|
return mergeAndDeduplicateByProject(prompts, paginatedPrompts);
|
|
23984
24158
|
}, [prompts, paginatedPrompts, currentFilter]);
|
|
23985
|
-
const filteredObservations = (0,
|
|
24159
|
+
const filteredObservations = (0, import_react8.useMemo)(
|
|
23986
24160
|
() => allObservations.filter((o) => activeTypes.has(o.type)),
|
|
23987
24161
|
[allObservations, activeTypes]
|
|
23988
24162
|
);
|
|
23989
|
-
const stats = (0,
|
|
24163
|
+
const stats = (0, import_react8.useMemo)(() => ({
|
|
23990
24164
|
observations: allObservations.length,
|
|
23991
24165
|
summaries: allSummaries.length,
|
|
23992
24166
|
prompts: allPrompts.length
|
|
23993
24167
|
}), [allObservations, allSummaries, allPrompts]);
|
|
23994
|
-
const toggleType = (0,
|
|
24168
|
+
const toggleType = (0, import_react8.useCallback)((type) => {
|
|
23995
24169
|
setActiveTypes((prev) => {
|
|
23996
24170
|
const next = new Set(prev);
|
|
23997
24171
|
if (next.has(type)) next.delete(type);
|
|
@@ -23999,15 +24173,36 @@ function App() {
|
|
|
23999
24173
|
return next;
|
|
24000
24174
|
});
|
|
24001
24175
|
}, []);
|
|
24002
|
-
const
|
|
24176
|
+
const fetchForProject = (0, import_react8.useCallback)(async (project) => {
|
|
24177
|
+
setIsLoadingMore(true);
|
|
24178
|
+
try {
|
|
24179
|
+
const params = new URLSearchParams({
|
|
24180
|
+
offset: "0",
|
|
24181
|
+
limit: "30",
|
|
24182
|
+
...project && { project }
|
|
24183
|
+
});
|
|
24184
|
+
const [obsRes, sumRes, promptRes] = await Promise.all([
|
|
24185
|
+
fetch(`/api/observations?${params}`),
|
|
24186
|
+
fetch(`/api/summaries?${params}`),
|
|
24187
|
+
fetch(`/api/prompts?${params}`)
|
|
24188
|
+
]);
|
|
24189
|
+
if (obsRes.ok) setPaginatedObservations(await obsRes.json());
|
|
24190
|
+
if (sumRes.ok) setPaginatedSummaries(await sumRes.json());
|
|
24191
|
+
if (promptRes.ok) setPaginatedPrompts(await promptRes.json());
|
|
24192
|
+
} catch (error) {
|
|
24193
|
+
console.error("Failed to load data:", error);
|
|
24194
|
+
} finally {
|
|
24195
|
+
setIsLoadingMore(false);
|
|
24196
|
+
}
|
|
24197
|
+
}, []);
|
|
24198
|
+
const handleLoadMore = (0, import_react8.useCallback)(async () => {
|
|
24003
24199
|
if (isLoadingMore) return;
|
|
24004
24200
|
setIsLoadingMore(true);
|
|
24005
24201
|
try {
|
|
24006
24202
|
const offset = paginatedObservations.length;
|
|
24007
|
-
const limit = 20;
|
|
24008
24203
|
const params = new URLSearchParams({
|
|
24009
24204
|
offset: String(offset),
|
|
24010
|
-
limit:
|
|
24205
|
+
limit: "20",
|
|
24011
24206
|
...currentFilter && { project: currentFilter }
|
|
24012
24207
|
});
|
|
24013
24208
|
const [obsRes, sumRes, promptRes] = await Promise.all([
|
|
@@ -24033,25 +24228,28 @@ function App() {
|
|
|
24033
24228
|
}
|
|
24034
24229
|
if (newItems === 0) setHasMore(false);
|
|
24035
24230
|
} catch (error) {
|
|
24036
|
-
console.error("
|
|
24231
|
+
console.error("Failed to load more data:", error);
|
|
24037
24232
|
} finally {
|
|
24038
24233
|
setIsLoadingMore(false);
|
|
24039
24234
|
}
|
|
24040
24235
|
}, [currentFilter, paginatedObservations.length, isLoadingMore]);
|
|
24041
|
-
(0,
|
|
24236
|
+
(0, import_react8.useEffect)(() => {
|
|
24042
24237
|
setPaginatedObservations([]);
|
|
24043
24238
|
setPaginatedSummaries([]);
|
|
24044
24239
|
setPaginatedPrompts([]);
|
|
24045
24240
|
setHasMore(true);
|
|
24046
|
-
|
|
24047
|
-
|
|
24241
|
+
if (currentFilter) {
|
|
24242
|
+
fetchForProject(currentFilter);
|
|
24243
|
+
}
|
|
24244
|
+
}, [currentFilter, fetchForProject]);
|
|
24245
|
+
return /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-screen overflow-hidden flex flex-col bg-surface-0" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
24048
24246
|
Header,
|
|
24049
24247
|
{
|
|
24050
24248
|
isConnected,
|
|
24051
24249
|
resolvedTheme,
|
|
24052
24250
|
onThemeToggle: () => setThemePreference(resolvedTheme === "dark" ? "light" : "dark")
|
|
24053
24251
|
}
|
|
24054
|
-
), /* @__PURE__ */
|
|
24252
|
+
), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-1 overflow-hidden" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "hidden md:flex w-[260px] flex-shrink-0" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
24055
24253
|
Sidebar,
|
|
24056
24254
|
{
|
|
24057
24255
|
projects,
|
|
@@ -24059,9 +24257,19 @@ function App() {
|
|
|
24059
24257
|
onFilterChange: setCurrentFilter,
|
|
24060
24258
|
activeTypes,
|
|
24061
24259
|
onToggleType: toggleType,
|
|
24062
|
-
stats
|
|
24260
|
+
stats,
|
|
24261
|
+
getDisplayName,
|
|
24262
|
+
onRenameProject: updateAlias
|
|
24063
24263
|
}
|
|
24064
|
-
), /* @__PURE__ */
|
|
24264
|
+
)), /* @__PURE__ */ import_react8.default.createElement("main", { className: "flex-1 overflow-y-auto bg-surface-0" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "max-w-3xl mx-auto px-6 py-6" }, currentFilter && /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-3 mb-6 animate-fade-in" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-3" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "w-9 h-9 rounded-lg bg-accent-violet/15 flex items-center justify-center" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-xs font-bold text-accent-violet" }, getDisplayName(currentFilter).substring(0, 2).toUpperCase())), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("h2", { className: "text-lg font-bold text-zinc-100" }, getDisplayName(currentFilter)), currentFilter !== getDisplayName(currentFilter) && /* @__PURE__ */ import_react8.default.createElement("span", { className: "text-[11px] font-mono text-zinc-600" }, currentFilter))), /* @__PURE__ */ import_react8.default.createElement(
|
|
24265
|
+
"button",
|
|
24266
|
+
{
|
|
24267
|
+
onClick: () => setCurrentFilter(""),
|
|
24268
|
+
className: "ml-auto flex items-center gap-1.5 text-xs text-zinc-500 hover:text-zinc-300 transition-colors px-3 py-1.5 rounded-lg hover:bg-surface-2 border border-transparent hover:border-border"
|
|
24269
|
+
},
|
|
24270
|
+
/* @__PURE__ */ import_react8.default.createElement("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, /* @__PURE__ */ import_react8.default.createElement("path", { d: "M18 6 6 18M6 6l12 12" })),
|
|
24271
|
+
"Clear filter"
|
|
24272
|
+
)), /* @__PURE__ */ import_react8.default.createElement(
|
|
24065
24273
|
Feed,
|
|
24066
24274
|
{
|
|
24067
24275
|
observations: filteredObservations,
|
|
@@ -24069,15 +24277,16 @@ function App() {
|
|
|
24069
24277
|
prompts: allPrompts,
|
|
24070
24278
|
onLoadMore: handleLoadMore,
|
|
24071
24279
|
isLoading: isLoadingMore,
|
|
24072
|
-
hasMore
|
|
24280
|
+
hasMore,
|
|
24281
|
+
getDisplayName
|
|
24073
24282
|
}
|
|
24074
|
-
)));
|
|
24283
|
+
)))));
|
|
24075
24284
|
}
|
|
24076
24285
|
|
|
24077
24286
|
// src/ui/viewer/index.tsx
|
|
24078
24287
|
var root = import_client.default.createRoot(document.getElementById("root"));
|
|
24079
24288
|
root.render(
|
|
24080
|
-
/* @__PURE__ */
|
|
24289
|
+
/* @__PURE__ */ import_react9.default.createElement(import_react9.default.StrictMode, null, /* @__PURE__ */ import_react9.default.createElement(App, null))
|
|
24081
24290
|
);
|
|
24082
24291
|
/*! Bundled license information:
|
|
24083
24292
|
|