kiro-memory 1.0.4 → 1.1.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/README.md +0 -1
- package/package.json +1 -1
- package/plugin/dist/cli/contextkit.js +0 -1
- package/plugin/dist/hooks/agentSpawn.js +41 -1
- package/plugin/dist/viewer.html +509 -122
- package/plugin/dist/viewer.js +306 -143
- package/plugin/dist/worker-service.js +80 -6
package/plugin/dist/viewer.js
CHANGED
|
@@ -1091,7 +1091,7 @@ var require_react_development = __commonJS({
|
|
|
1091
1091
|
var dispatcher = resolveDispatcher();
|
|
1092
1092
|
return dispatcher.useReducer(reducer, initialArg, init);
|
|
1093
1093
|
}
|
|
1094
|
-
function
|
|
1094
|
+
function useRef3(initialValue) {
|
|
1095
1095
|
var dispatcher = resolveDispatcher();
|
|
1096
1096
|
return dispatcher.useRef(initialValue);
|
|
1097
1097
|
}
|
|
@@ -1885,7 +1885,7 @@ var require_react_development = __commonJS({
|
|
|
1885
1885
|
exports.useLayoutEffect = useLayoutEffect;
|
|
1886
1886
|
exports.useMemo = useMemo2;
|
|
1887
1887
|
exports.useReducer = useReducer;
|
|
1888
|
-
exports.useRef =
|
|
1888
|
+
exports.useRef = useRef3;
|
|
1889
1889
|
exports.useState = useState5;
|
|
1890
1890
|
exports.useSyncExternalStore = useSyncExternalStore;
|
|
1891
1891
|
exports.useTransition = useTransition;
|
|
@@ -2382,9 +2382,9 @@ var require_react_dom_development = __commonJS({
|
|
|
2382
2382
|
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === "function") {
|
|
2383
2383
|
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
|
|
2384
2384
|
}
|
|
2385
|
-
var
|
|
2385
|
+
var React7 = require_react();
|
|
2386
2386
|
var Scheduler = require_scheduler();
|
|
2387
|
-
var ReactSharedInternals =
|
|
2387
|
+
var ReactSharedInternals = React7.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
2388
2388
|
var suppressWarning = false;
|
|
2389
2389
|
function setSuppressWarning(newSuppressWarning) {
|
|
2390
2390
|
{
|
|
@@ -3991,7 +3991,7 @@ var require_react_dom_development = __commonJS({
|
|
|
3991
3991
|
{
|
|
3992
3992
|
if (props.value == null) {
|
|
3993
3993
|
if (typeof props.children === "object" && props.children !== null) {
|
|
3994
|
-
|
|
3994
|
+
React7.Children.forEach(props.children, function(child) {
|
|
3995
3995
|
if (child == null) {
|
|
3996
3996
|
return;
|
|
3997
3997
|
}
|
|
@@ -23581,196 +23581,334 @@ var require_client = __commonJS({
|
|
|
23581
23581
|
});
|
|
23582
23582
|
|
|
23583
23583
|
// src/ui/viewer/index.tsx
|
|
23584
|
-
var
|
|
23584
|
+
var import_react8 = __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_react7 = __toESM(require_react(), 1);
|
|
23589
23589
|
|
|
23590
23590
|
// src/ui/viewer/components/Header.tsx
|
|
23591
|
+
var import_react2 = __toESM(require_react(), 1);
|
|
23592
|
+
|
|
23593
|
+
// src/ui/viewer/components/SearchBar.tsx
|
|
23591
23594
|
var import_react = __toESM(require_react(), 1);
|
|
23592
|
-
|
|
23593
|
-
|
|
23595
|
+
|
|
23596
|
+
// src/ui/viewer/utils/format.ts
|
|
23597
|
+
function getBadgeClass(type) {
|
|
23598
|
+
const map = {
|
|
23599
|
+
"file-write": "badge--file-write",
|
|
23600
|
+
"command": "badge--command",
|
|
23601
|
+
"research": "badge--research",
|
|
23602
|
+
"delegation": "badge--delegation",
|
|
23603
|
+
"tool-use": "badge--tool-use"
|
|
23604
|
+
};
|
|
23605
|
+
return map[type] || "badge--default";
|
|
23606
|
+
}
|
|
23607
|
+
function timeAgo(epochSeconds) {
|
|
23608
|
+
const now = Date.now() / 1e3;
|
|
23609
|
+
const diff = Math.max(0, now - epochSeconds);
|
|
23610
|
+
if (diff < 60) return "ora";
|
|
23611
|
+
if (diff < 3600) {
|
|
23612
|
+
const m = Math.floor(diff / 60);
|
|
23613
|
+
return `${m} min fa`;
|
|
23614
|
+
}
|
|
23615
|
+
if (diff < 86400) {
|
|
23616
|
+
const h = Math.floor(diff / 3600);
|
|
23617
|
+
return `${h}h fa`;
|
|
23618
|
+
}
|
|
23619
|
+
if (diff < 172800) return "ieri";
|
|
23620
|
+
if (diff < 604800) {
|
|
23621
|
+
const d = Math.floor(diff / 86400);
|
|
23622
|
+
return `${d} giorni fa`;
|
|
23623
|
+
}
|
|
23624
|
+
if (diff < 2592e3) {
|
|
23625
|
+
const w = Math.floor(diff / 604800);
|
|
23626
|
+
return `${w} sett. fa`;
|
|
23627
|
+
}
|
|
23628
|
+
const date = new Date(epochSeconds * 1e3);
|
|
23629
|
+
return date.toLocaleDateString("it-IT", { day: "numeric", month: "short" });
|
|
23630
|
+
}
|
|
23631
|
+
|
|
23632
|
+
// src/ui/viewer/components/SearchBar.tsx
|
|
23633
|
+
function SearchBar() {
|
|
23634
|
+
const [query, setQuery] = (0, import_react.useState)("");
|
|
23635
|
+
const [results, setResults] = (0, import_react.useState)(null);
|
|
23636
|
+
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
23637
|
+
const [isSearching, setIsSearching] = (0, import_react.useState)(false);
|
|
23638
|
+
const inputRef = (0, import_react.useRef)(null);
|
|
23639
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
23640
|
+
const debounceRef = (0, import_react.useRef)();
|
|
23641
|
+
const doSearch = (0, import_react.useCallback)(async (q) => {
|
|
23642
|
+
if (!q.trim()) {
|
|
23643
|
+
setResults(null);
|
|
23644
|
+
setIsOpen(false);
|
|
23645
|
+
return;
|
|
23646
|
+
}
|
|
23647
|
+
setIsSearching(true);
|
|
23648
|
+
try {
|
|
23649
|
+
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=10`);
|
|
23650
|
+
if (res.ok) {
|
|
23651
|
+
const data = await res.json();
|
|
23652
|
+
setResults(data);
|
|
23653
|
+
setIsOpen(true);
|
|
23654
|
+
}
|
|
23655
|
+
} catch (error) {
|
|
23656
|
+
console.error("Ricerca fallita:", error);
|
|
23657
|
+
} finally {
|
|
23658
|
+
setIsSearching(false);
|
|
23659
|
+
}
|
|
23660
|
+
}, []);
|
|
23661
|
+
const handleChange = (0, import_react.useCallback)((e) => {
|
|
23662
|
+
const value = e.target.value;
|
|
23663
|
+
setQuery(value);
|
|
23664
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
23665
|
+
debounceRef.current = setTimeout(() => doSearch(value), 300);
|
|
23666
|
+
}, [doSearch]);
|
|
23667
|
+
(0, import_react.useEffect)(() => {
|
|
23668
|
+
const handler = (e) => {
|
|
23669
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
23670
|
+
e.preventDefault();
|
|
23671
|
+
inputRef.current?.focus();
|
|
23672
|
+
}
|
|
23673
|
+
if (e.key === "Escape") {
|
|
23674
|
+
setIsOpen(false);
|
|
23675
|
+
inputRef.current?.blur();
|
|
23676
|
+
}
|
|
23677
|
+
};
|
|
23678
|
+
window.addEventListener("keydown", handler);
|
|
23679
|
+
return () => window.removeEventListener("keydown", handler);
|
|
23680
|
+
}, []);
|
|
23681
|
+
(0, import_react.useEffect)(() => {
|
|
23682
|
+
const handler = (e) => {
|
|
23683
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
23684
|
+
setIsOpen(false);
|
|
23685
|
+
}
|
|
23686
|
+
};
|
|
23687
|
+
document.addEventListener("mousedown", handler);
|
|
23688
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
23689
|
+
}, []);
|
|
23690
|
+
const totalResults = results ? results.observations.length + results.summaries.length : 0;
|
|
23691
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "search-container", ref: containerRef }, /* @__PURE__ */ import_react.default.createElement("div", { className: "search-input-wrapper" }, /* @__PURE__ */ import_react.default.createElement("svg", { className: "search-icon", viewBox: "0 0 16 16", fill: "currentColor" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z" })), /* @__PURE__ */ import_react.default.createElement(
|
|
23692
|
+
"input",
|
|
23693
|
+
{
|
|
23694
|
+
ref: inputRef,
|
|
23695
|
+
type: "text",
|
|
23696
|
+
className: "search-input",
|
|
23697
|
+
placeholder: "Search observations, summaries...",
|
|
23698
|
+
value: query,
|
|
23699
|
+
onChange: handleChange,
|
|
23700
|
+
onFocus: () => {
|
|
23701
|
+
if (results && totalResults > 0) setIsOpen(true);
|
|
23702
|
+
}
|
|
23703
|
+
}
|
|
23704
|
+
), /* @__PURE__ */ import_react.default.createElement("span", { className: "search-shortcut" }, navigator.platform.includes("Mac") ? "\u2318K" : "Ctrl+K")), isOpen && results && /* @__PURE__ */ import_react.default.createElement("div", { className: "search-results" }, totalResults === 0 && !isSearching && /* @__PURE__ */ import_react.default.createElement("div", { className: "search-empty" }, "No results for \u201C", query, "\u201D"), results.observations.map((obs) => /* @__PURE__ */ import_react.default.createElement("div", { key: `obs-${obs.id}`, className: "search-result-item" }, /* @__PURE__ */ import_react.default.createElement("span", { className: `badge ${getBadgeClass(obs.type)}` }, obs.type), /* @__PURE__ */ import_react.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-title" }, obs.title), obs.text && /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-snippet" }, obs.text.substring(0, 120)), /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-meta" }, obs.project, " \xB7 ", timeAgo(obs.created_at_epoch))))), results.summaries.map((sum) => /* @__PURE__ */ import_react.default.createElement("div", { key: `sum-${sum.id}`, className: "search-result-item" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "badge badge--summary" }, "summary"), /* @__PURE__ */ import_react.default.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-title" }, sum.request || "Session Summary"), sum.completed && /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-snippet" }, sum.completed.substring(0, 120)), /* @__PURE__ */ import_react.default.createElement("div", { className: "search-result-meta" }, sum.project, " \xB7 ", timeAgo(sum.created_at_epoch)))))));
|
|
23705
|
+
}
|
|
23706
|
+
|
|
23707
|
+
// src/ui/viewer/components/Header.tsx
|
|
23708
|
+
function Header({ isConnected, resolvedTheme, onThemeToggle }) {
|
|
23709
|
+
return /* @__PURE__ */ import_react2.default.createElement("header", { className: "header" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "header-brand" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: `status-dot ${isConnected ? "connected" : "disconnected"}` }), /* @__PURE__ */ import_react2.default.createElement("h1", null, "Kiro Memory")), /* @__PURE__ */ import_react2.default.createElement(SearchBar, null), /* @__PURE__ */ import_react2.default.createElement("div", { className: "header-controls" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
23710
|
+
"button",
|
|
23711
|
+
{
|
|
23712
|
+
className: "theme-btn",
|
|
23713
|
+
onClick: onThemeToggle,
|
|
23714
|
+
title: resolvedTheme === "dark" ? "Switch to light mode" : "Switch to dark mode"
|
|
23715
|
+
},
|
|
23716
|
+
resolvedTheme === "dark" ? "\u2600" : "\u263E"
|
|
23717
|
+
)));
|
|
23718
|
+
}
|
|
23719
|
+
|
|
23720
|
+
// src/ui/viewer/components/Sidebar.tsx
|
|
23721
|
+
var import_react3 = __toESM(require_react(), 1);
|
|
23722
|
+
var TYPE_COLORS = {
|
|
23723
|
+
"file-write": "var(--green)",
|
|
23724
|
+
"command": "var(--amber)",
|
|
23725
|
+
"research": "var(--blue)",
|
|
23726
|
+
"delegation": "var(--accent)",
|
|
23727
|
+
"tool-use": "var(--text-muted)"
|
|
23728
|
+
};
|
|
23729
|
+
function Sidebar({
|
|
23594
23730
|
projects,
|
|
23595
23731
|
currentFilter,
|
|
23596
23732
|
onFilterChange,
|
|
23597
|
-
|
|
23598
|
-
|
|
23733
|
+
activeTypes,
|
|
23734
|
+
onToggleType,
|
|
23735
|
+
stats
|
|
23599
23736
|
}) {
|
|
23600
|
-
return /* @__PURE__ */
|
|
23601
|
-
"
|
|
23737
|
+
return /* @__PURE__ */ import_react3.default.createElement("aside", { className: "sidebar" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-section" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-title" }, "Projects"), /* @__PURE__ */ import_react3.default.createElement(
|
|
23738
|
+
"div",
|
|
23602
23739
|
{
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
className: "project-filter"
|
|
23740
|
+
className: `sidebar-item ${currentFilter === "" ? "active" : ""}`,
|
|
23741
|
+
onClick: () => onFilterChange("")
|
|
23606
23742
|
},
|
|
23607
|
-
|
|
23608
|
-
|
|
23609
|
-
|
|
23610
|
-
"select",
|
|
23743
|
+
"All Projects"
|
|
23744
|
+
), projects.map((project) => /* @__PURE__ */ import_react3.default.createElement(
|
|
23745
|
+
"div",
|
|
23611
23746
|
{
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
|
|
23747
|
+
key: project,
|
|
23748
|
+
className: `sidebar-item ${currentFilter === project ? "active" : ""}`,
|
|
23749
|
+
onClick: () => onFilterChange(project)
|
|
23615
23750
|
},
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23751
|
+
project
|
|
23752
|
+
))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-section" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-title" }, "Type Filters"), Object.entries(TYPE_COLORS).map(([type, color]) => /* @__PURE__ */ import_react3.default.createElement("label", { key: type, className: "filter-checkbox" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
23753
|
+
"input",
|
|
23754
|
+
{
|
|
23755
|
+
type: "checkbox",
|
|
23756
|
+
checked: activeTypes.has(type),
|
|
23757
|
+
onChange: () => onToggleType(type)
|
|
23758
|
+
}
|
|
23759
|
+
), /* @__PURE__ */ import_react3.default.createElement("span", { className: "filter-dot", style: { background: color } }), type))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-section" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "sidebar-title" }, "Stats"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stats-grid" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-card" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-value" }, stats.observations), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-label" }, "Observations")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-card" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-value" }, stats.summaries), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-label" }, "Summaries")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-card" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-value" }, stats.prompts), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-label" }, "Prompts")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-card" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-value" }, projects.length), /* @__PURE__ */ import_react3.default.createElement("div", { className: "stat-label" }, "Projects")))));
|
|
23620
23760
|
}
|
|
23621
23761
|
|
|
23622
23762
|
// src/ui/viewer/components/Feed.tsx
|
|
23623
|
-
var
|
|
23763
|
+
var import_react4 = __toESM(require_react(), 1);
|
|
23624
23764
|
function Feed({ observations, summaries, prompts, onLoadMore, isLoading, hasMore }) {
|
|
23625
23765
|
const items = [...observations, ...summaries, ...prompts].sort(
|
|
23626
23766
|
(a, b) => b.created_at_epoch - a.created_at_epoch
|
|
23627
23767
|
);
|
|
23628
|
-
return /* @__PURE__ */
|
|
23629
|
-
if ("type" in item) {
|
|
23630
|
-
return /* @__PURE__ */
|
|
23768
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "feed" }, items.map((item) => {
|
|
23769
|
+
if ("type" in item && "title" in item) {
|
|
23770
|
+
return /* @__PURE__ */ import_react4.default.createElement(ObservationCard, { key: `obs-${item.id}`, obs: item });
|
|
23631
23771
|
} else if ("request" in item) {
|
|
23632
|
-
return /* @__PURE__ */
|
|
23772
|
+
return /* @__PURE__ */ import_react4.default.createElement(SummaryCard, { key: `sum-${item.id}`, summary: item });
|
|
23633
23773
|
} else {
|
|
23634
|
-
return /* @__PURE__ */
|
|
23774
|
+
return /* @__PURE__ */ import_react4.default.createElement(PromptCard, { key: `prompt-${item.id}`, prompt: item });
|
|
23635
23775
|
}
|
|
23636
|
-
}), hasMore && /* @__PURE__ */
|
|
23776
|
+
}), hasMore && /* @__PURE__ */ import_react4.default.createElement(
|
|
23637
23777
|
"button",
|
|
23638
23778
|
{
|
|
23639
23779
|
className: "load-more-btn",
|
|
23640
23780
|
onClick: onLoadMore,
|
|
23641
23781
|
disabled: isLoading
|
|
23642
23782
|
},
|
|
23643
|
-
isLoading ? "
|
|
23644
|
-
), items.length === 0 && !isLoading && /* @__PURE__ */
|
|
23783
|
+
isLoading ? "Caricamento..." : "Carica altri"
|
|
23784
|
+
), items.length === 0 && !isLoading && /* @__PURE__ */ import_react4.default.createElement("div", { className: "empty-state" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "empty-state-icon" }, /* @__PURE__ */ import_react4.default.createElement("svg", { viewBox: "0 0 24 24", width: "48", height: "48", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M12 6v6l4 2", strokeLinecap: "round" }), /* @__PURE__ */ import_react4.default.createElement("circle", { cx: "12", cy: "12", r: "10" }))), /* @__PURE__ */ import_react4.default.createElement("p", null, "Nessun dato disponibile."), /* @__PURE__ */ import_react4.default.createElement("p", { className: "empty-state-hint" }, "Avvia una sessione con Kiro per iniziare a raccogliere contesto.")));
|
|
23645
23785
|
}
|
|
23646
|
-
function ObservationCard({
|
|
23647
|
-
|
|
23786
|
+
function ObservationCard({ obs }) {
|
|
23787
|
+
const cardClass = `card card--${obs.type.replace(/\s+/g, "-")}`;
|
|
23788
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: cardClass }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-header" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `badge ${getBadgeClass(obs.type)}` }, obs.type), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-project" }, obs.project), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-time" }, timeAgo(obs.created_at_epoch))), /* @__PURE__ */ import_react4.default.createElement("h3", { className: "card-title" }, obs.title), obs.subtitle && /* @__PURE__ */ import_react4.default.createElement("p", { className: "card-subtitle" }, obs.subtitle), obs.text && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-content" }, /* @__PURE__ */ import_react4.default.createElement("p", null, obs.text)), obs.narrative && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Narrativa"), /* @__PURE__ */ import_react4.default.createElement("p", null, obs.narrative)), obs.facts && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Fatti"), /* @__PURE__ */ import_react4.default.createElement("p", null, obs.facts)), (obs.files_modified || obs.files_read) && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-files" }, obs.files_modified && /* @__PURE__ */ import_react4.default.createElement("span", { className: "file-pill file-pill--modified", title: "File modificati" }, "\u270E ", obs.files_modified.split(",").length, " file"), obs.files_read && /* @__PURE__ */ import_react4.default.createElement("span", { className: "file-pill file-pill--read", title: "File letti" }, "\u25C9 ", obs.files_read.split(",").length, " file")), obs.concepts && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-tags" }, obs.concepts.split(", ").map((concept, i) => /* @__PURE__ */ import_react4.default.createElement("span", { key: i, className: "tag" }, concept))));
|
|
23648
23789
|
}
|
|
23649
23790
|
function SummaryCard({ summary }) {
|
|
23650
|
-
return /* @__PURE__ */
|
|
23791
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "card card--summary" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-header" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "badge badge--summary" }, "summary"), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-project" }, summary.project), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-time" }, timeAgo(summary.created_at_epoch))), summary.request && /* @__PURE__ */ import_react4.default.createElement("h3", { className: "card-title" }, summary.request), summary.investigated && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Indagato"), /* @__PURE__ */ import_react4.default.createElement("p", null, summary.investigated)), summary.learned && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Appreso"), /* @__PURE__ */ import_react4.default.createElement("p", null, summary.learned)), summary.completed && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Completato"), /* @__PURE__ */ import_react4.default.createElement("p", null, summary.completed)), summary.next_steps && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Prossimi passi"), /* @__PURE__ */ import_react4.default.createElement("p", null, summary.next_steps)), summary.notes && /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-section" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-section-label" }, "Note"), /* @__PURE__ */ import_react4.default.createElement("p", null, summary.notes)));
|
|
23651
23792
|
}
|
|
23652
23793
|
function PromptCard({ prompt }) {
|
|
23653
|
-
return /* @__PURE__ */
|
|
23794
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "card card--prompt" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-header" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "badge badge--prompt" }, "prompt #", prompt.prompt_number), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-project" }, prompt.project), /* @__PURE__ */ import_react4.default.createElement("span", { className: "card-time" }, timeAgo(prompt.created_at_epoch))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "card-content card-content--mono" }, /* @__PURE__ */ import_react4.default.createElement("p", null, prompt.prompt_text)));
|
|
23654
23795
|
}
|
|
23655
23796
|
|
|
23656
23797
|
// src/ui/viewer/hooks/useSSE.ts
|
|
23657
|
-
var
|
|
23798
|
+
var import_react5 = __toESM(require_react(), 1);
|
|
23658
23799
|
function useSSE() {
|
|
23659
|
-
const [state, setState] = (0,
|
|
23800
|
+
const [state, setState] = (0, import_react5.useState)({
|
|
23660
23801
|
observations: [],
|
|
23661
23802
|
summaries: [],
|
|
23662
23803
|
prompts: [],
|
|
23663
23804
|
projects: [],
|
|
23664
23805
|
isConnected: false
|
|
23665
23806
|
});
|
|
23666
|
-
(0,
|
|
23667
|
-
|
|
23668
|
-
|
|
23669
|
-
|
|
23670
|
-
|
|
23671
|
-
|
|
23672
|
-
|
|
23673
|
-
};
|
|
23674
|
-
eventSource.addEventListener("observation-created", (event) => {
|
|
23675
|
-
const data = JSON.parse(event.data);
|
|
23676
|
-
fetchObservations();
|
|
23677
|
-
});
|
|
23678
|
-
eventSource.addEventListener("summary-created", (event) => {
|
|
23679
|
-
const data = JSON.parse(event.data);
|
|
23680
|
-
fetchSummaries();
|
|
23681
|
-
});
|
|
23807
|
+
const mountedRef = (0, import_react5.useRef)(true);
|
|
23808
|
+
(0, import_react5.useEffect)(() => {
|
|
23809
|
+
mountedRef.current = true;
|
|
23810
|
+
let eventSource = null;
|
|
23811
|
+
let retryTimeout = null;
|
|
23812
|
+
let retryCount = 0;
|
|
23813
|
+
const MAX_RETRY_DELAY = 3e4;
|
|
23682
23814
|
const fetchObservations = async () => {
|
|
23683
23815
|
try {
|
|
23684
23816
|
const res = await fetch("/api/observations?limit=50");
|
|
23685
|
-
if (res.ok) {
|
|
23817
|
+
if (res.ok && mountedRef.current) {
|
|
23686
23818
|
const observations = await res.json();
|
|
23687
23819
|
setState((prev) => ({ ...prev, observations }));
|
|
23688
23820
|
}
|
|
23689
|
-
} catch (
|
|
23690
|
-
console.error("
|
|
23821
|
+
} catch (err) {
|
|
23822
|
+
console.error("Fetch observations fallito:", err);
|
|
23691
23823
|
}
|
|
23692
23824
|
};
|
|
23693
23825
|
const fetchSummaries = async () => {
|
|
23694
23826
|
try {
|
|
23695
23827
|
const res = await fetch("/api/summaries?limit=20");
|
|
23696
|
-
if (res.ok) {
|
|
23828
|
+
if (res.ok && mountedRef.current) {
|
|
23697
23829
|
const summaries = await res.json();
|
|
23698
23830
|
setState((prev) => ({ ...prev, summaries }));
|
|
23699
23831
|
}
|
|
23700
|
-
} catch (
|
|
23701
|
-
console.error("
|
|
23832
|
+
} catch (err) {
|
|
23833
|
+
console.error("Fetch summaries fallito:", err);
|
|
23834
|
+
}
|
|
23835
|
+
};
|
|
23836
|
+
const fetchPrompts = async () => {
|
|
23837
|
+
try {
|
|
23838
|
+
const res = await fetch("/api/prompts?limit=50");
|
|
23839
|
+
if (res.ok && mountedRef.current) {
|
|
23840
|
+
const prompts = await res.json();
|
|
23841
|
+
setState((prev) => ({ ...prev, prompts }));
|
|
23842
|
+
}
|
|
23843
|
+
} catch (err) {
|
|
23844
|
+
console.error("Fetch prompts fallito:", err);
|
|
23702
23845
|
}
|
|
23703
23846
|
};
|
|
23704
23847
|
const fetchProjects = async () => {
|
|
23705
23848
|
try {
|
|
23706
23849
|
const res = await fetch("/api/projects");
|
|
23707
|
-
if (res.ok) {
|
|
23850
|
+
if (res.ok && mountedRef.current) {
|
|
23708
23851
|
const projects = await res.json();
|
|
23709
23852
|
setState((prev) => ({ ...prev, projects }));
|
|
23710
23853
|
}
|
|
23711
|
-
} catch (
|
|
23712
|
-
console.error("
|
|
23854
|
+
} catch (err) {
|
|
23855
|
+
console.error("Fetch projects fallito:", err);
|
|
23713
23856
|
}
|
|
23714
23857
|
};
|
|
23858
|
+
const connect = () => {
|
|
23859
|
+
if (!mountedRef.current) return;
|
|
23860
|
+
eventSource = new EventSource("/events");
|
|
23861
|
+
eventSource.onopen = () => {
|
|
23862
|
+
if (!mountedRef.current) return;
|
|
23863
|
+
retryCount = 0;
|
|
23864
|
+
setState((prev) => ({ ...prev, isConnected: true }));
|
|
23865
|
+
};
|
|
23866
|
+
eventSource.onerror = () => {
|
|
23867
|
+
if (!mountedRef.current) return;
|
|
23868
|
+
setState((prev) => ({ ...prev, isConnected: false }));
|
|
23869
|
+
eventSource?.close();
|
|
23870
|
+
eventSource = null;
|
|
23871
|
+
const delay = Math.min(1e3 * Math.pow(2, retryCount), MAX_RETRY_DELAY);
|
|
23872
|
+
retryCount++;
|
|
23873
|
+
retryTimeout = setTimeout(connect, delay);
|
|
23874
|
+
};
|
|
23875
|
+
eventSource.addEventListener("observation-created", () => {
|
|
23876
|
+
fetchObservations();
|
|
23877
|
+
fetchProjects();
|
|
23878
|
+
});
|
|
23879
|
+
eventSource.addEventListener("summary-created", () => {
|
|
23880
|
+
fetchSummaries();
|
|
23881
|
+
});
|
|
23882
|
+
eventSource.addEventListener("prompt-created", () => {
|
|
23883
|
+
fetchPrompts();
|
|
23884
|
+
});
|
|
23885
|
+
};
|
|
23715
23886
|
fetchObservations();
|
|
23716
23887
|
fetchSummaries();
|
|
23888
|
+
fetchPrompts();
|
|
23717
23889
|
fetchProjects();
|
|
23890
|
+
connect();
|
|
23718
23891
|
return () => {
|
|
23719
|
-
|
|
23892
|
+
mountedRef.current = false;
|
|
23893
|
+
eventSource?.close();
|
|
23894
|
+
if (retryTimeout) clearTimeout(retryTimeout);
|
|
23720
23895
|
};
|
|
23721
23896
|
}, []);
|
|
23722
23897
|
return state;
|
|
23723
23898
|
}
|
|
23724
23899
|
|
|
23725
|
-
// src/ui/viewer/hooks/useSettings.ts
|
|
23726
|
-
var import_react4 = __toESM(require_react(), 1);
|
|
23727
|
-
function useSettings() {
|
|
23728
|
-
const [settings, setSettings] = (0, import_react4.useState)({
|
|
23729
|
-
sidebarOpen: true,
|
|
23730
|
-
selectedProject: null,
|
|
23731
|
-
theme: "system"
|
|
23732
|
-
});
|
|
23733
|
-
const [isSaving, setIsSaving] = (0, import_react4.useState)(false);
|
|
23734
|
-
const [saveStatus, setSaveStatus] = (0, import_react4.useState)("idle");
|
|
23735
|
-
(0, import_react4.useEffect)(() => {
|
|
23736
|
-
const saved = localStorage.getItem("contextkit-settings");
|
|
23737
|
-
if (saved) {
|
|
23738
|
-
try {
|
|
23739
|
-
setSettings(JSON.parse(saved));
|
|
23740
|
-
} catch (error) {
|
|
23741
|
-
console.error("Failed to parse settings:", error);
|
|
23742
|
-
}
|
|
23743
|
-
}
|
|
23744
|
-
}, []);
|
|
23745
|
-
const saveSettings = async (newSettings) => {
|
|
23746
|
-
setIsSaving(true);
|
|
23747
|
-
try {
|
|
23748
|
-
localStorage.setItem("contextkit-settings", JSON.stringify(newSettings));
|
|
23749
|
-
setSettings(newSettings);
|
|
23750
|
-
setSaveStatus("success");
|
|
23751
|
-
setTimeout(() => setSaveStatus("idle"), 2e3);
|
|
23752
|
-
} catch (error) {
|
|
23753
|
-
console.error("Failed to save settings:", error);
|
|
23754
|
-
setSaveStatus("error");
|
|
23755
|
-
} finally {
|
|
23756
|
-
setIsSaving(false);
|
|
23757
|
-
}
|
|
23758
|
-
};
|
|
23759
|
-
return { settings, saveSettings, isSaving, saveStatus };
|
|
23760
|
-
}
|
|
23761
|
-
|
|
23762
23900
|
// src/ui/viewer/hooks/useTheme.ts
|
|
23763
|
-
var
|
|
23901
|
+
var import_react6 = __toESM(require_react(), 1);
|
|
23764
23902
|
function useTheme() {
|
|
23765
|
-
const [preference, setPreference] = (0,
|
|
23766
|
-
const [resolvedTheme, setResolvedTheme] = (0,
|
|
23767
|
-
(0,
|
|
23768
|
-
const saved = localStorage.getItem("
|
|
23903
|
+
const [preference, setPreference] = (0, import_react6.useState)("system");
|
|
23904
|
+
const [resolvedTheme, setResolvedTheme] = (0, import_react6.useState)("light");
|
|
23905
|
+
(0, import_react6.useEffect)(() => {
|
|
23906
|
+
const saved = localStorage.getItem("kiro-memory-theme");
|
|
23769
23907
|
if (saved) {
|
|
23770
23908
|
setPreference(saved);
|
|
23771
23909
|
}
|
|
23772
23910
|
}, []);
|
|
23773
|
-
(0,
|
|
23911
|
+
(0, import_react6.useEffect)(() => {
|
|
23774
23912
|
const resolveTheme = () => {
|
|
23775
23913
|
if (preference === "system") {
|
|
23776
23914
|
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
@@ -23791,7 +23929,7 @@ function useTheme() {
|
|
|
23791
23929
|
}, [preference]);
|
|
23792
23930
|
const setThemePreference = (theme) => {
|
|
23793
23931
|
setPreference(theme);
|
|
23794
|
-
localStorage.setItem("
|
|
23932
|
+
localStorage.setItem("kiro-memory-theme", theme);
|
|
23795
23933
|
};
|
|
23796
23934
|
return { preference, resolvedTheme, setThemePreference };
|
|
23797
23935
|
}
|
|
@@ -23820,34 +23958,47 @@ function mergeAndDeduplicateByProject(liveData, paginatedData) {
|
|
|
23820
23958
|
}
|
|
23821
23959
|
|
|
23822
23960
|
// src/ui/viewer/App.tsx
|
|
23961
|
+
var TYPE_FILTERS = ["file-write", "command", "research", "delegation", "tool-use"];
|
|
23823
23962
|
function App() {
|
|
23824
|
-
const [currentFilter, setCurrentFilter] = (0,
|
|
23825
|
-
const [
|
|
23826
|
-
const [
|
|
23827
|
-
const [
|
|
23828
|
-
const [
|
|
23963
|
+
const [currentFilter, setCurrentFilter] = (0, import_react7.useState)("");
|
|
23964
|
+
const [activeTypes, setActiveTypes] = (0, import_react7.useState)(new Set(TYPE_FILTERS));
|
|
23965
|
+
const [paginatedObservations, setPaginatedObservations] = (0, import_react7.useState)([]);
|
|
23966
|
+
const [paginatedSummaries, setPaginatedSummaries] = (0, import_react7.useState)([]);
|
|
23967
|
+
const [paginatedPrompts, setPaginatedPrompts] = (0, import_react7.useState)([]);
|
|
23968
|
+
const [isLoadingMore, setIsLoadingMore] = (0, import_react7.useState)(false);
|
|
23969
|
+
const [hasMore, setHasMore] = (0, import_react7.useState)(true);
|
|
23829
23970
|
const { observations, summaries, prompts, projects, isConnected } = useSSE();
|
|
23830
|
-
const {
|
|
23831
|
-
const
|
|
23832
|
-
|
|
23833
|
-
if (currentFilter) {
|
|
23834
|
-
return paginatedObservations;
|
|
23835
|
-
}
|
|
23971
|
+
const { resolvedTheme, setThemePreference } = useTheme();
|
|
23972
|
+
const allObservations = (0, import_react7.useMemo)(() => {
|
|
23973
|
+
if (currentFilter) return paginatedObservations;
|
|
23836
23974
|
return mergeAndDeduplicateByProject(observations, paginatedObservations);
|
|
23837
23975
|
}, [observations, paginatedObservations, currentFilter]);
|
|
23838
|
-
const allSummaries = (0,
|
|
23839
|
-
if (currentFilter)
|
|
23840
|
-
return paginatedSummaries;
|
|
23841
|
-
}
|
|
23976
|
+
const allSummaries = (0, import_react7.useMemo)(() => {
|
|
23977
|
+
if (currentFilter) return paginatedSummaries;
|
|
23842
23978
|
return mergeAndDeduplicateByProject(summaries, paginatedSummaries);
|
|
23843
23979
|
}, [summaries, paginatedSummaries, currentFilter]);
|
|
23844
|
-
const allPrompts = (0,
|
|
23845
|
-
if (currentFilter)
|
|
23846
|
-
return paginatedPrompts;
|
|
23847
|
-
}
|
|
23980
|
+
const allPrompts = (0, import_react7.useMemo)(() => {
|
|
23981
|
+
if (currentFilter) return paginatedPrompts;
|
|
23848
23982
|
return mergeAndDeduplicateByProject(prompts, paginatedPrompts);
|
|
23849
23983
|
}, [prompts, paginatedPrompts, currentFilter]);
|
|
23850
|
-
const
|
|
23984
|
+
const filteredObservations = (0, import_react7.useMemo)(
|
|
23985
|
+
() => allObservations.filter((o) => activeTypes.has(o.type)),
|
|
23986
|
+
[allObservations, activeTypes]
|
|
23987
|
+
);
|
|
23988
|
+
const stats = (0, import_react7.useMemo)(() => ({
|
|
23989
|
+
observations: allObservations.length,
|
|
23990
|
+
summaries: allSummaries.length,
|
|
23991
|
+
prompts: allPrompts.length
|
|
23992
|
+
}), [allObservations, allSummaries, allPrompts]);
|
|
23993
|
+
const toggleType = (0, import_react7.useCallback)((type) => {
|
|
23994
|
+
setActiveTypes((prev) => {
|
|
23995
|
+
const next = new Set(prev);
|
|
23996
|
+
if (next.has(type)) next.delete(type);
|
|
23997
|
+
else next.add(type);
|
|
23998
|
+
return next;
|
|
23999
|
+
});
|
|
24000
|
+
}, []);
|
|
24001
|
+
const handleLoadMore = (0, import_react7.useCallback)(async () => {
|
|
23851
24002
|
if (isLoadingMore) return;
|
|
23852
24003
|
setIsLoadingMore(true);
|
|
23853
24004
|
try {
|
|
@@ -23863,57 +24014,69 @@ function App() {
|
|
|
23863
24014
|
fetch(`/api/summaries?${params}`),
|
|
23864
24015
|
fetch(`/api/prompts?${params}`)
|
|
23865
24016
|
]);
|
|
24017
|
+
let newItems = 0;
|
|
23866
24018
|
if (obsRes.ok) {
|
|
23867
24019
|
const newObs = await obsRes.json();
|
|
24020
|
+
newItems += newObs.length;
|
|
23868
24021
|
setPaginatedObservations((prev) => [...prev, ...newObs]);
|
|
23869
24022
|
}
|
|
23870
24023
|
if (sumRes.ok) {
|
|
23871
24024
|
const newSum = await sumRes.json();
|
|
24025
|
+
newItems += newSum.length;
|
|
23872
24026
|
setPaginatedSummaries((prev) => [...prev, ...newSum]);
|
|
23873
24027
|
}
|
|
23874
24028
|
if (promptRes.ok) {
|
|
23875
24029
|
const newPrompts = await promptRes.json();
|
|
24030
|
+
newItems += newPrompts.length;
|
|
23876
24031
|
setPaginatedPrompts((prev) => [...prev, ...newPrompts]);
|
|
23877
24032
|
}
|
|
24033
|
+
if (newItems === 0) setHasMore(false);
|
|
23878
24034
|
} catch (error) {
|
|
23879
|
-
console.error("
|
|
24035
|
+
console.error("Errore caricamento dati:", error);
|
|
23880
24036
|
} finally {
|
|
23881
24037
|
setIsLoadingMore(false);
|
|
23882
24038
|
}
|
|
23883
24039
|
}, [currentFilter, paginatedObservations.length, isLoadingMore]);
|
|
23884
|
-
(0,
|
|
24040
|
+
(0, import_react7.useEffect)(() => {
|
|
23885
24041
|
setPaginatedObservations([]);
|
|
23886
24042
|
setPaginatedSummaries([]);
|
|
23887
24043
|
setPaginatedPrompts([]);
|
|
23888
|
-
|
|
24044
|
+
setHasMore(true);
|
|
23889
24045
|
}, [currentFilter]);
|
|
23890
|
-
return /* @__PURE__ */
|
|
24046
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { className: "app", "data-theme": resolvedTheme }, /* @__PURE__ */ import_react7.default.createElement(
|
|
23891
24047
|
Header,
|
|
23892
24048
|
{
|
|
23893
24049
|
isConnected,
|
|
24050
|
+
resolvedTheme,
|
|
24051
|
+
onThemeToggle: () => setThemePreference(resolvedTheme === "dark" ? "light" : "dark")
|
|
24052
|
+
}
|
|
24053
|
+
), /* @__PURE__ */ import_react7.default.createElement(
|
|
24054
|
+
Sidebar,
|
|
24055
|
+
{
|
|
23894
24056
|
projects,
|
|
23895
24057
|
currentFilter,
|
|
23896
24058
|
onFilterChange: setCurrentFilter,
|
|
23897
|
-
|
|
23898
|
-
|
|
24059
|
+
activeTypes,
|
|
24060
|
+
onToggleType: toggleType,
|
|
24061
|
+
stats
|
|
23899
24062
|
}
|
|
23900
|
-
), /* @__PURE__ */
|
|
24063
|
+
), /* @__PURE__ */ import_react7.default.createElement("div", { className: "main" }, /* @__PURE__ */ import_react7.default.createElement(
|
|
23901
24064
|
Feed,
|
|
23902
24065
|
{
|
|
23903
|
-
observations:
|
|
24066
|
+
observations: filteredObservations,
|
|
23904
24067
|
summaries: allSummaries,
|
|
23905
24068
|
prompts: allPrompts,
|
|
23906
24069
|
onLoadMore: handleLoadMore,
|
|
23907
24070
|
isLoading: isLoadingMore,
|
|
23908
|
-
hasMore
|
|
24071
|
+
hasMore
|
|
23909
24072
|
}
|
|
23910
|
-
));
|
|
24073
|
+
)));
|
|
23911
24074
|
}
|
|
23912
24075
|
|
|
23913
24076
|
// src/ui/viewer/index.tsx
|
|
23914
24077
|
var root = import_client.default.createRoot(document.getElementById("root"));
|
|
23915
24078
|
root.render(
|
|
23916
|
-
/* @__PURE__ */
|
|
24079
|
+
/* @__PURE__ */ import_react8.default.createElement(import_react8.default.StrictMode, null, /* @__PURE__ */ import_react8.default.createElement(App, null))
|
|
23917
24080
|
);
|
|
23918
24081
|
/*! Bundled license information:
|
|
23919
24082
|
|