@powerhousedao/knowledge-note 1.0.5 → 1.0.7
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/dist/editors/knowledge-note-editor/components/links-section.d.ts.map +1 -1
- package/dist/editors/knowledge-note-editor/components/links-section.js +18 -2
- package/dist/editors/knowledge-vault/components/ActivityView.d.ts +2 -0
- package/dist/editors/knowledge-vault/components/ActivityView.d.ts.map +1 -0
- package/dist/editors/knowledge-vault/components/ActivityView.js +188 -0
- package/dist/editors/knowledge-vault/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/DriveExplorer.js +8 -1
- package/dist/editors/knowledge-vault/components/GraphView.d.ts +1 -0
- package/dist/editors/knowledge-vault/components/GraphView.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/GraphView.js +27 -9
- package/dist/editors/knowledge-vault/components/SearchView.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/components/SearchView.js +18 -11
- package/dist/editors/knowledge-vault/hooks/use-graph-search.d.ts +2 -1
- package/dist/editors/knowledge-vault/hooks/use-graph-search.d.ts.map +1 -1
- package/dist/editors/knowledge-vault/hooks/use-graph-search.js +33 -2
- package/dist/editors/moc-editor/editor.d.ts.map +1 -1
- package/dist/editors/moc-editor/editor.js +1 -1
- package/dist/package.json +1 -1
- package/dist/processors/graph-indexer/index.d.ts.map +1 -1
- package/dist/processors/graph-indexer/index.js +80 -0
- package/dist/processors/graph-indexer/migrations.d.ts.map +1 -1
- package/dist/processors/graph-indexer/migrations.js +46 -0
- package/dist/processors/graph-indexer/query.d.ts +29 -0
- package/dist/processors/graph-indexer/query.d.ts.map +1 -1
- package/dist/processors/graph-indexer/query.js +104 -0
- package/dist/processors/graph-indexer/schema.d.ts +13 -0
- package/dist/processors/graph-indexer/schema.d.ts.map +1 -1
- package/dist/style.css +4 -4
- package/dist/subgraphs/knowledge-graph/subgraph.d.ts +55 -0
- package/dist/subgraphs/knowledge-graph/subgraph.d.ts.map +1 -1
- package/dist/subgraphs/knowledge-graph/subgraph.js +72 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links-section.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-note-editor/components/links-section.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"links-section.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-note-editor/components/links-section.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACT,MAAM,gEAAgE,CAAC;AAExE,KAAK,iBAAiB,GAAG;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,CACT,EAAE,EAAE,MAAM,EACV,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,KACf,IAAI,CAAC;IACV,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5D,CAAC;AA0BF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,gBAAgB,GACjB,EAAE,iBAAiB,2CA8FnB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo, useRef, useEffect } from "react";
|
|
3
3
|
import { generateId } from "document-model/core";
|
|
4
|
+
import { setSelectedNode } from "@powerhousedao/reactor-browser";
|
|
4
5
|
import { useKnowledgeNoteDocumentsInSelectedDrive } from "@powerhousedao/knowledge-note/document-models/knowledge-note";
|
|
5
6
|
const LINK_TYPES = [
|
|
6
7
|
"RELATES_TO",
|
|
@@ -59,10 +60,25 @@ export function LinksSection({ links, currentDocId, onAddLink, onRemoveLink, onU
|
|
|
59
60
|
} }, link.id))), isAdding ? (_jsx(AddLinkForm, { docOptions: docOptions, onAdd: handleAdd, onCancel: () => setIsAdding(false) })) : (_jsx("button", { type: "button", onClick: () => setIsAdding(true), className: "w-full rounded-lg border border-dashed border-white/10 py-1.5 text-xs text-gray-500 hover:border-[#cba6f7]/30 hover:text-[#cba6f7]", children: "+ Add link" }))] }));
|
|
60
61
|
}
|
|
61
62
|
function LinkCard({ link, isEditing, allDocOptions, onStartEdit, onCancelEdit, onUpdateLinkType, onRemoveLink, onChangeTarget, }) {
|
|
63
|
+
const editRef = useRef(null);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (!isEditing)
|
|
66
|
+
return;
|
|
67
|
+
function handleClickOutside(e) {
|
|
68
|
+
if (editRef.current && !editRef.current.contains(e.target)) {
|
|
69
|
+
onCancelEdit();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
73
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
74
|
+
}, [isEditing, onCancelEdit]);
|
|
62
75
|
if (isEditing) {
|
|
63
|
-
return (_jsxs("div", { className: "rounded-lg border border-[#cba6f7]/20 bg-[#cba6f7]/5 p-2", children: [_jsx("p", { className: "mb-1.5 text-[10px] font-medium uppercase text-gray-500", children: "Change target document" }), _jsx(DocumentSearch, { options: allDocOptions, onSelect: (doc) => onChangeTarget(doc.id, doc.title), onCancel: onCancelEdit, autoFocus: true })] }));
|
|
76
|
+
return (_jsxs("div", { ref: editRef, className: "rounded-lg border border-[#cba6f7]/20 bg-[#cba6f7]/5 p-2", children: [_jsx("p", { className: "mb-1.5 text-[10px] font-medium uppercase text-gray-500", children: "Change target document" }), _jsx(DocumentSearch, { options: allDocOptions, onSelect: (doc) => onChangeTarget(doc.id, doc.title), onCancel: onCancelEdit, autoFocus: true })] }));
|
|
64
77
|
}
|
|
65
|
-
return (_jsxs("div", { className: "group flex items-center gap-2 rounded-lg border border-white/5 bg-[#1e1e2e] px-3 py-2", children: [_jsx("select", { value: link.linkType ?? "RELATES_TO", onChange: (e) => onUpdateLinkType(link.id, e.target.value), className: `rounded-md border-0 px-2 py-0.5 text-xs font-medium ${LINK_TYPE_COLORS[link.linkType ?? "RELATES_TO"]} bg-transparent`, children: LINK_TYPES.map((lt) => (_jsx("option", { value: lt, children: LINK_TYPE_LABELS[lt] }, lt))) }),
|
|
78
|
+
return (_jsxs("div", { className: "group flex items-center gap-2 rounded-lg border border-white/5 bg-[#1e1e2e] px-3 py-2", children: [_jsx("select", { value: link.linkType ?? "RELATES_TO", onChange: (e) => onUpdateLinkType(link.id, e.target.value), className: `rounded-md border-0 px-2 py-0.5 text-xs font-medium ${LINK_TYPE_COLORS[link.linkType ?? "RELATES_TO"]} bg-transparent`, children: LINK_TYPES.map((lt) => (_jsx("option", { value: lt, children: LINK_TYPE_LABELS[lt] }, lt))) }), _jsxs("button", { type: "button", onClick: () => {
|
|
79
|
+
if (link.targetDocumentId)
|
|
80
|
+
setSelectedNode(link.targetDocumentId);
|
|
81
|
+
}, className: "flex-1 truncate text-left text-sm text-gray-300 hover:text-[#cba6f7] hover:underline", title: `Open: ${link.targetTitle || link.targetDocumentId || "Untitled"}`, children: [link.targetTitle || link.targetDocumentId || "Untitled", _jsxs("svg", { className: "ml-1 inline-block h-3 w-3 opacity-0 group-hover:opacity-50", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }), _jsx("polyline", { points: "15 3 21 3 21 9" }), _jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] })] }), _jsx("button", { type: "button", onClick: onStartEdit, className: "text-gray-600 opacity-0 transition-opacity hover:text-[#cba6f7] group-hover:opacity-100", "aria-label": "Change target", title: "Change target document", children: _jsxs("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }) }), _jsx("button", { type: "button", onClick: () => onRemoveLink(link.id), className: "text-gray-600 opacity-0 transition-opacity hover:text-red-400 group-hover:opacity-100", "aria-label": "Remove link", children: "\u00D7" })] }));
|
|
66
82
|
}
|
|
67
83
|
function AddLinkForm({ docOptions, onAdd, onCancel, }) {
|
|
68
84
|
const [selectedDoc, setSelectedDoc] = useState(null);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActivityView.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/ActivityView.tsx"],"names":[],"mappings":"AAuHA,wBAAgB,YAAY,4CAkJ3B"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
3
|
+
import { setSelectedNode, useSelectedDriveId, } from "@powerhousedao/reactor-browser";
|
|
4
|
+
const FILTER_TYPES = {
|
|
5
|
+
all: { label: "All", ops: [] },
|
|
6
|
+
content: {
|
|
7
|
+
label: "Content",
|
|
8
|
+
ops: ["SET_TITLE", "SET_DESCRIPTION", "SET_CONTENT", "SET_NOTE_TYPE"],
|
|
9
|
+
},
|
|
10
|
+
links: {
|
|
11
|
+
label: "Links",
|
|
12
|
+
ops: ["ADD_LINK", "REMOVE_LINK", "UPDATE_LINK_TYPE"],
|
|
13
|
+
},
|
|
14
|
+
lifecycle: {
|
|
15
|
+
label: "Lifecycle",
|
|
16
|
+
ops: [
|
|
17
|
+
"SET_STATUS",
|
|
18
|
+
"SUBMIT_FOR_REVIEW",
|
|
19
|
+
"APPROVE_NOTE",
|
|
20
|
+
"REJECT_NOTE",
|
|
21
|
+
"ARCHIVE_NOTE",
|
|
22
|
+
"RESTORE_NOTE",
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
topics: { label: "Topics", ops: ["ADD_TOPIC", "REMOVE_TOPIC"] },
|
|
26
|
+
};
|
|
27
|
+
const OP_ICONS = {
|
|
28
|
+
SET_TITLE: "T",
|
|
29
|
+
SET_DESCRIPTION: "D",
|
|
30
|
+
SET_CONTENT: "C",
|
|
31
|
+
SET_NOTE_TYPE: "N",
|
|
32
|
+
ADD_LINK: "+L",
|
|
33
|
+
REMOVE_LINK: "-L",
|
|
34
|
+
ADD_TOPIC: "+#",
|
|
35
|
+
REMOVE_TOPIC: "-#",
|
|
36
|
+
SET_STATUS: "S",
|
|
37
|
+
SUBMIT_FOR_REVIEW: "R",
|
|
38
|
+
APPROVE_NOTE: "A",
|
|
39
|
+
REJECT_NOTE: "X",
|
|
40
|
+
ARCHIVE_NOTE: "Z",
|
|
41
|
+
RESTORE_NOTE: "U",
|
|
42
|
+
SET_PROVENANCE: "P",
|
|
43
|
+
SET_METADATA_FIELD: "M",
|
|
44
|
+
};
|
|
45
|
+
/* ------------------------------------------------------------------ */
|
|
46
|
+
/* GraphQL */
|
|
47
|
+
/* ------------------------------------------------------------------ */
|
|
48
|
+
const SUBGRAPH_PATH = "/graphql/knowledgeGraph";
|
|
49
|
+
function getEndpoint() {
|
|
50
|
+
const envUrl = typeof import.meta !== "undefined" &&
|
|
51
|
+
import.meta.env?.VITE_SUBGRAPH_URL;
|
|
52
|
+
if (envUrl)
|
|
53
|
+
return envUrl;
|
|
54
|
+
const port = globalThis.window?.location?.port;
|
|
55
|
+
if (port === "3000" || port === "3001") {
|
|
56
|
+
return `http://localhost:4001${SUBGRAPH_PATH}`;
|
|
57
|
+
}
|
|
58
|
+
return SUBGRAPH_PATH;
|
|
59
|
+
}
|
|
60
|
+
const ACTIVITY_QUERY = `
|
|
61
|
+
query Activity($driveId: ID!, $limit: Int) {
|
|
62
|
+
knowledgeGraphActivity(driveId: $driveId, limit: $limit) {
|
|
63
|
+
id documentId operationType timestamp index summary signerAddress signerApp
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
async function fetchActivity(driveId, limit) {
|
|
68
|
+
try {
|
|
69
|
+
const res = await fetch(getEndpoint(), {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "Content-Type": "application/json" },
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
query: ACTIVITY_QUERY,
|
|
74
|
+
variables: { driveId, limit },
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok)
|
|
78
|
+
return [];
|
|
79
|
+
const json = (await res.json());
|
|
80
|
+
return json.data?.knowledgeGraphActivity ?? [];
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/* ------------------------------------------------------------------ */
|
|
87
|
+
/* Component */
|
|
88
|
+
/* ------------------------------------------------------------------ */
|
|
89
|
+
export function ActivityView() {
|
|
90
|
+
const driveId = useSelectedDriveId();
|
|
91
|
+
const [operations, setOperations] = useState([]);
|
|
92
|
+
const [loading, setLoading] = useState(true);
|
|
93
|
+
const [filter, setFilter] = useState("all");
|
|
94
|
+
const endpoint = useMemo(() => getEndpoint(), []);
|
|
95
|
+
const loadActivity = useCallback(async () => {
|
|
96
|
+
if (!driveId)
|
|
97
|
+
return;
|
|
98
|
+
setLoading(true);
|
|
99
|
+
const data = await fetchActivity(driveId, 200);
|
|
100
|
+
setOperations(data);
|
|
101
|
+
setLoading(false);
|
|
102
|
+
}, [driveId]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
void loadActivity();
|
|
105
|
+
}, [loadActivity]);
|
|
106
|
+
const filtered = useMemo(() => {
|
|
107
|
+
if (filter === "all")
|
|
108
|
+
return operations;
|
|
109
|
+
const allowedOps = FILTER_TYPES[filter].ops;
|
|
110
|
+
return operations.filter((op) => allowedOps.includes(op.operationType));
|
|
111
|
+
}, [operations, filter]);
|
|
112
|
+
// Group by date
|
|
113
|
+
const grouped = useMemo(() => {
|
|
114
|
+
const groups = new Map();
|
|
115
|
+
for (const op of filtered) {
|
|
116
|
+
const date = op.timestamp.slice(0, 10);
|
|
117
|
+
const existing = groups.get(date) ?? [];
|
|
118
|
+
existing.push(op);
|
|
119
|
+
groups.set(date, existing);
|
|
120
|
+
}
|
|
121
|
+
return groups;
|
|
122
|
+
}, [filtered]);
|
|
123
|
+
if (loading) {
|
|
124
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center text-sm", style: { color: "var(--bai-text-muted)" }, children: "Loading activity..." }));
|
|
125
|
+
}
|
|
126
|
+
if (operations.length === 0) {
|
|
127
|
+
return (_jsxs("div", { className: "flex h-full flex-col items-center justify-center", children: [_jsxs("svg", { className: "mb-4 h-12 w-12", style: { color: "var(--bai-text-faint)", opacity: 0.5 }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 6v6l4 2" })] }), _jsx("p", { className: "text-sm", style: { color: "var(--bai-text-muted)" }, children: "No activity recorded yet" }), _jsx("p", { className: "mt-1 text-xs", style: { color: "var(--bai-text-faint)" }, children: "Edit notes to start tracking changes" })] }));
|
|
128
|
+
}
|
|
129
|
+
return (_jsxs("div", { className: "flex h-full flex-col p-4", children: [_jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", style: { color: "var(--bai-text)" }, children: "Vault Activity" }), _jsxs("p", { className: "text-xs", style: { color: "var(--bai-text-muted)" }, children: [filtered.length, " operation", filtered.length !== 1 ? "s" : "", filter !== "all" ? ` (${FILTER_TYPES[filter].label})` : ""] })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsx("button", { type: "button", onClick: () => void loadActivity(), className: "rounded-md border px-3 py-1.5 text-xs transition-colors", style: {
|
|
130
|
+
borderColor: "var(--bai-border)",
|
|
131
|
+
color: "var(--bai-text-muted)",
|
|
132
|
+
backgroundColor: "var(--bai-surface)",
|
|
133
|
+
}, children: "Refresh" }) })] }), _jsx("div", { className: "mb-4 flex flex-wrap gap-1.5", children: Object.keys(FILTER_TYPES).map((key) => (_jsx("button", { type: "button", onClick: () => setFilter(key), className: "rounded-full px-3 py-1 text-xs transition-colors", style: {
|
|
134
|
+
backgroundColor: filter === key ? "var(--bai-accent)" : "var(--bai-hover)",
|
|
135
|
+
color: filter === key ? "#fff" : "var(--bai-text-muted)",
|
|
136
|
+
}, children: FILTER_TYPES[key].label }, key))) }), _jsx("div", { className: "flex-1 overflow-auto", children: [...grouped.entries()].map(([date, ops]) => (_jsxs("div", { className: "mb-6", children: [_jsx("h3", { className: "sticky top-0 z-10 mb-2 py-1 text-xs font-semibold uppercase tracking-wider", style: {
|
|
137
|
+
color: "var(--bai-text-muted)",
|
|
138
|
+
backgroundColor: "var(--bai-bg)",
|
|
139
|
+
}, children: formatDate(date) }), _jsx("div", { className: "space-y-1", children: ops.map((op) => (_jsx(OperationRow, { op: op }, op.id))) })] }, date))) })] }));
|
|
140
|
+
}
|
|
141
|
+
/* ------------------------------------------------------------------ */
|
|
142
|
+
/* Operation row */
|
|
143
|
+
/* ------------------------------------------------------------------ */
|
|
144
|
+
function OperationRow({ op }) {
|
|
145
|
+
const icon = OP_ICONS[op.operationType] ?? "?";
|
|
146
|
+
const time = op.timestamp.slice(11, 16);
|
|
147
|
+
return (_jsxs("button", { type: "button", onClick: () => setSelectedNode(op.documentId), className: "group flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-[var(--bai-hover)]", children: [_jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-[10px] font-bold", style: {
|
|
148
|
+
backgroundColor: opColor(op.operationType) + "20",
|
|
149
|
+
color: opColor(op.operationType),
|
|
150
|
+
}, children: icon }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-xs", style: { color: "var(--bai-text)" }, children: op.summary ?? op.operationType }), _jsxs("p", { className: "truncate text-[10px]", style: { color: "var(--bai-text-faint)" }, children: [op.documentId.slice(0, 8), "...", op.signerAddress || op.signerApp ? (_jsxs("span", { title: op.signerAddress ?? op.signerApp ?? "", className: "cursor-pointer", style: { color: "var(--bai-accent)", opacity: 0.7 }, onClick: (e) => {
|
|
151
|
+
e.stopPropagation();
|
|
152
|
+
const text = op.signerAddress ?? op.signerApp ?? "";
|
|
153
|
+
void navigator.clipboard.writeText(text);
|
|
154
|
+
}, children: [" by ", op.signerAddress
|
|
155
|
+
? `${op.signerAddress.slice(0, 6)}...${op.signerAddress.slice(-4)}`
|
|
156
|
+
: op.signerApp, " ", _jsxs("svg", { className: "inline-block h-2.5 w-2.5 opacity-0 group-hover:opacity-50", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }), _jsx("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })] })] })) : null] })] }), _jsx("span", { className: "shrink-0 text-[10px] font-mono", style: { color: "var(--bai-text-faint)" }, children: time }), _jsx("svg", { className: "h-3 w-3 shrink-0 opacity-0 transition-opacity group-hover:opacity-50", style: { color: "var(--bai-text-muted)" }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M9 18l6-6-6-6" }) })] }));
|
|
157
|
+
}
|
|
158
|
+
/* ------------------------------------------------------------------ */
|
|
159
|
+
/* Helpers */
|
|
160
|
+
/* ------------------------------------------------------------------ */
|
|
161
|
+
function opColor(type) {
|
|
162
|
+
if (type.startsWith("SET_TITLE") || type.startsWith("SET_CONTENT"))
|
|
163
|
+
return "#f59e0b";
|
|
164
|
+
if (type.startsWith("ADD_LINK") || type.startsWith("REMOVE_LINK"))
|
|
165
|
+
return "#3b82f6";
|
|
166
|
+
if (type.startsWith("ADD_TOPIC") || type.startsWith("REMOVE_TOPIC"))
|
|
167
|
+
return "#10b981";
|
|
168
|
+
if (type === "SUBMIT_FOR_REVIEW" ||
|
|
169
|
+
type === "APPROVE_NOTE" ||
|
|
170
|
+
type === "REJECT_NOTE")
|
|
171
|
+
return "#a855f7";
|
|
172
|
+
if (type === "ARCHIVE_NOTE" || type === "RESTORE_NOTE")
|
|
173
|
+
return "#6b7280";
|
|
174
|
+
return "#64748b";
|
|
175
|
+
}
|
|
176
|
+
function formatDate(dateStr) {
|
|
177
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
178
|
+
const yesterday = new Date(Date.now() - 86400000).toISOString().slice(0, 10);
|
|
179
|
+
if (dateStr === today)
|
|
180
|
+
return "Today";
|
|
181
|
+
if (dateStr === yesterday)
|
|
182
|
+
return "Yesterday";
|
|
183
|
+
return new Date(dateStr + "T00:00:00").toLocaleDateString("en-US", {
|
|
184
|
+
weekday: "short",
|
|
185
|
+
month: "short",
|
|
186
|
+
day: "numeric",
|
|
187
|
+
});
|
|
188
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/DriveExplorer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/DriveExplorer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAmClD,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAoXtD"}
|
|
@@ -8,6 +8,7 @@ import { NoteList } from "./NoteList.js";
|
|
|
8
8
|
import { SourceList } from "./SourceList.js";
|
|
9
9
|
import { HealthDashboard } from "./HealthDashboard.js";
|
|
10
10
|
import { SearchView } from "./SearchView.js";
|
|
11
|
+
import { ActivityView } from "./ActivityView.js";
|
|
11
12
|
import { GettingStartedButton } from "./GettingStarted.js";
|
|
12
13
|
import { useKnowledgeNotes } from "../hooks/use-knowledge-notes.js";
|
|
13
14
|
import { useKnowledgeGraph, buildSyncPayload, } from "../hooks/use-knowledge-graph.js";
|
|
@@ -36,6 +37,7 @@ export function DriveExplorer({ children }) {
|
|
|
36
37
|
noteRef: ci.noteRef,
|
|
37
38
|
contextPhrase: ci.contextPhrase,
|
|
38
39
|
})),
|
|
40
|
+
childRefs: state.childRefs ?? [],
|
|
39
41
|
};
|
|
40
42
|
});
|
|
41
43
|
}, [allDocuments]);
|
|
@@ -129,6 +131,11 @@ export function DriveExplorer({ children }) {
|
|
|
129
131
|
badge: sourceCount > 0 ? sourceCount : undefined,
|
|
130
132
|
icon: (_jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M4 19.5A2.5 2.5 0 016.5 17H20" }), _jsx("path", { d: "M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" })] })),
|
|
131
133
|
},
|
|
134
|
+
{
|
|
135
|
+
key: "activity",
|
|
136
|
+
label: "Activity",
|
|
137
|
+
icon: (_jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("path", { d: "M12 6v6l4 2" })] })),
|
|
138
|
+
},
|
|
132
139
|
{
|
|
133
140
|
key: "pipeline",
|
|
134
141
|
label: "Pipeline",
|
|
@@ -161,7 +168,7 @@ export function DriveExplorer({ children }) {
|
|
|
161
168
|
}, children: tab.badge }))] }, tab.key))), showDocumentEditor && (_jsxs("span", { className: "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", style: {
|
|
162
169
|
backgroundColor: "var(--bai-hover)",
|
|
163
170
|
color: "var(--bai-accent)",
|
|
164
|
-
}, children: [_jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }), "Editing"] }))] }), _jsxs("div", { className: "flex items-center gap-3", children: [hasGraphDoc && graphState && (_jsxs("span", { className: "text-[10px]", style: { color: "var(--bai-text-faint)" }, children: [graphState.nodes.length, "n / ", graphState.edges.length, "e"] })), _jsx(ThemeToggle, {}), _jsx(GettingStartedButton, {}), _jsx(CreateMenu, {})] })] }), _jsx("div", { className: "flex-1 overflow-auto", children: showDocumentEditor ? (_jsx("div", { className: "h-full", children: children })) : viewMode === "graph" ? (_jsx(GraphView, { notes: notes, graphState: graphState, mocs: mocs, tensions: tensions })) : viewMode === "search" ? (_jsx(SearchView, {})) : viewMode === "sources" ? (_jsx(SourceList, {})) : viewMode === "health" ? (_jsx(HealthDashboard, {})) : (_jsx(NoteList, { notes: notes })) })] })] }));
|
|
171
|
+
}, children: [_jsxs("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }), "Editing"] }))] }), _jsxs("div", { className: "flex items-center gap-3", children: [hasGraphDoc && graphState && (_jsxs("span", { className: "text-[10px]", style: { color: "var(--bai-text-faint)" }, children: [graphState.nodes.length, "n / ", graphState.edges.length, "e"] })), _jsx(ThemeToggle, {}), _jsx(GettingStartedButton, {}), _jsx(CreateMenu, {})] })] }), _jsx("div", { className: "flex-1 overflow-auto", children: showDocumentEditor ? (_jsx("div", { className: "h-full", children: children })) : viewMode === "graph" ? (_jsx(GraphView, { notes: notes, graphState: graphState, mocs: mocs, tensions: tensions })) : viewMode === "search" ? (_jsx(SearchView, {})) : viewMode === "activity" ? (_jsx(ActivityView, {})) : viewMode === "sources" ? (_jsx(SourceList, {})) : viewMode === "health" ? (_jsx(HealthDashboard, {})) : (_jsx(NoteList, { notes: notes })) })] })] }));
|
|
165
172
|
}
|
|
166
173
|
const CREATE_ITEMS = [
|
|
167
174
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/GraphView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAUzE,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,EAAE,CAAC;IACJ,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,EAAE,CAAC;IACJ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,IAAI,CAAC;AAET,KAAK,OAAO,GAAG;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"GraphView.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/GraphView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAUzE,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,EAAE,CAAC;IACJ,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,EAAE,CAAC;IACJ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,IAAI,CAAC;AAET,KAAK,OAAO,GAAG;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;CAC1B,CAAC;AAghBF,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,GACT,EAAE,cAAc,2CAotBhB"}
|
|
@@ -184,8 +184,12 @@ function buildElements(notes, graphState, mocs, tensions) {
|
|
|
184
184
|
}
|
|
185
185
|
// Track existing node IDs for MOC + tension edge targets
|
|
186
186
|
const existingNodeIds = new Set(elements.filter((e) => !e.data.source).map((e) => e.data.id));
|
|
187
|
-
// Add MOC nodes
|
|
187
|
+
// Add MOC nodes + edges (coreIdeas → notes, childRefs → child MOCs)
|
|
188
188
|
if (mocs?.length) {
|
|
189
|
+
// Pre-register MOC IDs so childRef edges between MOCs can resolve
|
|
190
|
+
for (const moc of mocs) {
|
|
191
|
+
existingNodeIds.add(moc.id);
|
|
192
|
+
}
|
|
189
193
|
for (const moc of mocs) {
|
|
190
194
|
elements.push({
|
|
191
195
|
data: {
|
|
@@ -195,7 +199,7 @@ function buildElements(notes, graphState, mocs, tensions) {
|
|
|
195
199
|
noteType: `MOC (${moc.tier ?? "TOPIC"})`,
|
|
196
200
|
description: null,
|
|
197
201
|
topics: [],
|
|
198
|
-
linkCount: moc.coreIdeas.length,
|
|
202
|
+
linkCount: moc.coreIdeas.length + moc.childRefs.length,
|
|
199
203
|
color: MOC_NODE_COLOR,
|
|
200
204
|
isMoc: true,
|
|
201
205
|
},
|
|
@@ -213,6 +217,19 @@ function buildElements(notes, graphState, mocs, tensions) {
|
|
|
213
217
|
});
|
|
214
218
|
}
|
|
215
219
|
}
|
|
220
|
+
for (const childRef of moc.childRefs) {
|
|
221
|
+
if (existingNodeIds.has(childRef)) {
|
|
222
|
+
elements.push({
|
|
223
|
+
data: {
|
|
224
|
+
id: `moc-child-${moc.id}-${childRef}`,
|
|
225
|
+
source: moc.id,
|
|
226
|
+
target: childRef,
|
|
227
|
+
linkType: "CORE_IDEA",
|
|
228
|
+
color: MOC_EDGE_COLOR,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
216
233
|
}
|
|
217
234
|
}
|
|
218
235
|
// Add tension nodes and edges to involved notes
|
|
@@ -572,16 +589,17 @@ export function GraphView({ notes, graphState, mocs, tensions, }) {
|
|
|
572
589
|
const dx = curr.x - prev.x;
|
|
573
590
|
const dy = curr.y - prev.y;
|
|
574
591
|
mocDragState.set(moc.id(), { x: curr.x, y: curr.y });
|
|
575
|
-
// Move
|
|
592
|
+
// Move CORE_IDEA-connected notes along with the MOC,
|
|
593
|
+
// but skip MOC-to-MOC connections (parent ↔ child MOCs move independently)
|
|
576
594
|
moc.connectedEdges().forEach((edge) => {
|
|
577
595
|
if (edge.data("linkType") !== "CORE_IDEA")
|
|
578
596
|
return;
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (
|
|
583
|
-
return; // don't
|
|
584
|
-
|
|
597
|
+
const other = edge.source().id() === moc.id() ? edge.target() : edge.source();
|
|
598
|
+
if (other.grabbed())
|
|
599
|
+
return;
|
|
600
|
+
if (other.data("isMoc"))
|
|
601
|
+
return; // don't drag other MOCs
|
|
602
|
+
other.shift({ x: dx, y: dy });
|
|
585
603
|
});
|
|
586
604
|
});
|
|
587
605
|
// Persist position after manual drag
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchView.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/SearchView.tsx"],"names":[],"mappings":"AA+CA,wBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"SearchView.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/components/SearchView.tsx"],"names":[],"mappings":"AA+CA,wBAAgB,UAAU,4CAsGzB"}
|
|
@@ -43,19 +43,19 @@ export function SearchView() {
|
|
|
43
43
|
backgroundColor: "var(--bai-surface)",
|
|
44
44
|
borderColor: "var(--bai-border)",
|
|
45
45
|
color: "var(--bai-text)",
|
|
46
|
-
} }), query && (_jsx("button", { type: "button", onClick: () => setQuery(""), className: "absolute right-3 top-1/2 -translate-y-1/2 rounded p-0.5 transition-colors hover:opacity-80", style: { color: "var(--bai-text-muted)" }, children: _jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }))] }), _jsx(ModeToggle, { mode: searchMode, onChange: setSearchMode })] }), query.trim() && (_jsxs("div", { className: "mb-3 flex items-center gap-2 text-xs", style: { color: "var(--bai-text-muted)" }, children: [loading ? (_jsx("span", { children: "Searching..." })) : (_jsxs(_Fragment, { children: [_jsxs("span", { children: [results.length, " result", results.length !== 1 ? "s" : ""] }), searchMode === "semantic"
|
|
46
|
+
} }), query && (_jsx("button", { type: "button", onClick: () => setQuery(""), className: "absolute right-3 top-1/2 -translate-y-1/2 rounded p-0.5 transition-colors hover:opacity-80", style: { color: "var(--bai-text-muted)" }, children: _jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }))] }), _jsx(ModeToggle, { mode: searchMode, onChange: setSearchMode })] }), query.trim() && (_jsxs("div", { className: "mb-3 flex items-center gap-2 text-xs", style: { color: "var(--bai-text-muted)" }, children: [loading ? (_jsx("span", { children: "Searching..." })) : (_jsxs(_Fragment, { children: [_jsxs("span", { children: [results.length, " result", results.length !== 1 ? "s" : ""] }), (searchMode === "semantic" || searchMode === "hybrid") &&
|
|
47
|
+
results.length > 0 && (_jsxs("span", { style: { opacity: 0.6 }, children: ["\u2014 score shows relevance", searchMode === "hybrid"
|
|
48
|
+
? " combining keyword + semantic matching"
|
|
49
|
+
: " by meaning"] }))] })), error && _jsx("span", { style: { color: "#ef4444" }, children: error })] })), _jsx("div", { className: "flex-1 overflow-auto", children: !query.trim() ? (_jsx(EmptyState, { topics: topics, onTopicClick: setQuery })) : (_jsx(ResultList, { results: results, searchMode: searchMode })) })] }));
|
|
47
50
|
}
|
|
48
51
|
/* ------------------------------------------------------------------ */
|
|
49
52
|
/* Mode toggle */
|
|
50
53
|
/* ------------------------------------------------------------------ */
|
|
51
54
|
function ModeToggle({ mode, onChange, }) {
|
|
52
|
-
return (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
backgroundColor: mode === "keyword" ? "var(--bai-accent)" : "var(--bai-surface)",
|
|
57
|
-
color: mode === "keyword" ? "#fff" : "var(--bai-text-muted)",
|
|
58
|
-
}, children: "Keyword" })] }));
|
|
55
|
+
return (_jsx("div", { className: "flex shrink-0 overflow-hidden rounded-lg border text-xs", style: { borderColor: "var(--bai-border)" }, children: ["hybrid", "semantic", "keyword"].map((m) => (_jsx("button", { type: "button", onClick: () => onChange(m), className: "px-3 py-2 transition-colors capitalize", style: {
|
|
56
|
+
backgroundColor: mode === m ? "var(--bai-accent)" : "var(--bai-surface)",
|
|
57
|
+
color: mode === m ? "#fff" : "var(--bai-text-muted)",
|
|
58
|
+
}, children: m }, m))) }));
|
|
59
59
|
}
|
|
60
60
|
/* ------------------------------------------------------------------ */
|
|
61
61
|
/* Empty state */
|
|
@@ -78,7 +78,7 @@ function ResultList({ results, searchMode, }) {
|
|
|
78
78
|
if (results.length === 0) {
|
|
79
79
|
return (_jsx("div", { className: "py-12 text-center text-sm", style: { color: "var(--bai-text-muted)" }, children: "No results found" }));
|
|
80
80
|
}
|
|
81
|
-
return (_jsx("div", { className: "space-y-2", children: results.map((result) => (_jsx(ResultCard, { result: result, showSimilarity: searchMode
|
|
81
|
+
return (_jsx("div", { className: "space-y-2", children: results.map((result) => (_jsx(ResultCard, { result: result, showSimilarity: searchMode !== "keyword" }, result.documentId))) }));
|
|
82
82
|
}
|
|
83
83
|
/* ------------------------------------------------------------------ */
|
|
84
84
|
/* Result card */
|
|
@@ -86,11 +86,18 @@ function ResultList({ results, searchMode, }) {
|
|
|
86
86
|
function ResultCard({ result, showSimilarity, }) {
|
|
87
87
|
const status = result.status ?? "DRAFT";
|
|
88
88
|
const badgeStyle = STATUS_COLORS[status] ?? STATUS_COLORS.DRAFT;
|
|
89
|
-
return (_jsxs("button", { type: "button", onClick: () => setSelectedNode(result.documentId), className: "group flex w-full items-start gap-3 rounded-xl border p-4 text-left transition-all border-[var(--bai-border)] bg-[var(--bai-surface)] hover:border-[var(--bai-accent)] hover:bg-[var(--bai-hover)]", children: [showSimilarity && result.similarity != null && (_jsxs("div", { className: "shrink-0 rounded-md px-2 py-1 text-center font-mono text-xs font-bold", title: "
|
|
89
|
+
return (_jsxs("button", { type: "button", onClick: () => setSelectedNode(result.documentId), className: "group flex w-full items-start gap-3 rounded-xl border p-4 text-left transition-all border-[var(--bai-border)] bg-[var(--bai-surface)] hover:border-[var(--bai-accent)] hover:bg-[var(--bai-hover)]", children: [showSimilarity && result.similarity != null && (_jsxs("div", { className: "shrink-0 rounded-md px-2 py-1 text-center font-mono text-xs font-bold", title: "Relevance score \u2014 how closely this note matches your query (higher is better)", style: {
|
|
90
90
|
color: similarityColor(result.similarity),
|
|
91
91
|
backgroundColor: `${similarityColor(result.similarity)}15`,
|
|
92
92
|
}, children: [(result.similarity * 100).toFixed(0), "%"] })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-1 flex items-start justify-between gap-2", children: [_jsx("h4", { className: "truncate text-sm font-semibold text-[var(--bai-text)] group-hover:text-[var(--bai-accent)]", children: result.title ?? "Untitled" }), _jsx("span", { className: "shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium", style: badgeStyle, children: status.replace("_", " ") })] }), result.description && (_jsx("p", { className: "mb-2 line-clamp-2 text-xs leading-relaxed", style: { color: "var(--bai-text-muted)" }, children: result.description })), _jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [result.noteType && (_jsx("span", { className: "rounded px-1.5 py-0.5 text-[10px] font-medium", style: {
|
|
93
93
|
background: "var(--bai-hover)",
|
|
94
94
|
color: "var(--bai-text-muted)",
|
|
95
|
-
}, children: result.noteType })), result.topics?.slice(0, 4).map((topic) => (_jsxs("span", { className: "text-[10px]", style: { color: "var(--bai-accent)", opacity: 0.6 }, children: ["#", topic] }, topic)))
|
|
95
|
+
}, children: result.noteType })), result.topics?.slice(0, 4).map((topic) => (_jsxs("span", { className: "text-[10px]", style: { color: "var(--bai-accent)", opacity: 0.6 }, children: ["#", topic] }, topic))), result.matchedBy && result.matchedBy.length > 0 && (_jsx("span", { className: "ml-auto flex gap-1", children: result.matchedBy.map((m) => (_jsx("span", { className: "rounded px-1.5 py-0.5 text-[9px] font-medium", style: {
|
|
96
|
+
background: m === "semantic"
|
|
97
|
+
? "rgba(139, 92, 246, 0.15)"
|
|
98
|
+
: "rgba(59, 130, 246, 0.15)",
|
|
99
|
+
color: m === "semantic"
|
|
100
|
+
? "rgba(167, 139, 250, 1)"
|
|
101
|
+
: "rgba(147, 197, 253, 1)",
|
|
102
|
+
}, children: m }, m))) }))] })] }), _jsx("svg", { className: "mt-1 h-4 w-4 shrink-0 opacity-0 transition-opacity group-hover:opacity-60", style: { color: "var(--bai-text-muted)" }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M9 18l6-6-6-6" }) })] }));
|
|
96
103
|
}
|
|
@@ -6,12 +6,13 @@ export type SearchResult = {
|
|
|
6
6
|
status: string | null;
|
|
7
7
|
topics: string[];
|
|
8
8
|
similarity?: number;
|
|
9
|
+
matchedBy?: string[];
|
|
9
10
|
};
|
|
10
11
|
export type TopicInfo = {
|
|
11
12
|
name: string;
|
|
12
13
|
noteCount: number;
|
|
13
14
|
};
|
|
14
|
-
export type SearchMode = "semantic" | "keyword";
|
|
15
|
+
export type SearchMode = "hybrid" | "semantic" | "keyword";
|
|
15
16
|
export declare function useGraphSearch(): {
|
|
16
17
|
query: string;
|
|
17
18
|
setQuery: (q: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-graph-search.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/hooks/use-graph-search.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"use-graph-search.d.ts","sourceRoot":"","sources":["../../../../editors/knowledge-vault/hooks/use-graph-search.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAkJ3D,wBAAgB,cAAc;;kBAgBtB,MAAM;;;;;;uBAQN,UAAU;EA4HjB"}
|
|
@@ -79,6 +79,15 @@ const KEYWORD_SEARCH_QUERY = `
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
`;
|
|
82
|
+
const HYBRID_SEARCH_QUERY = `
|
|
83
|
+
query HybridSearch($driveId: ID!, $query: String!, $limit: Int) {
|
|
84
|
+
knowledgeGraphHybridSearch(driveId: $driveId, query: $query, limit: $limit) {
|
|
85
|
+
node { documentId title description noteType status topics }
|
|
86
|
+
score
|
|
87
|
+
matchedBy
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
82
91
|
const TOPICS_QUERY = `
|
|
83
92
|
query Topics($driveId: ID!) {
|
|
84
93
|
knowledgeGraphTopics(driveId: $driveId) { name noteCount }
|
|
@@ -93,9 +102,14 @@ function loadSearchState() {
|
|
|
93
102
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
94
103
|
if (raw) {
|
|
95
104
|
const parsed = JSON.parse(raw);
|
|
105
|
+
const mode = parsed.mode;
|
|
96
106
|
return {
|
|
97
107
|
query: parsed.query ?? "",
|
|
98
|
-
mode:
|
|
108
|
+
mode: mode === "keyword"
|
|
109
|
+
? "keyword"
|
|
110
|
+
: mode === "semantic"
|
|
111
|
+
? "semantic"
|
|
112
|
+
: "hybrid",
|
|
99
113
|
};
|
|
100
114
|
}
|
|
101
115
|
}
|
|
@@ -151,7 +165,24 @@ export function useGraphSearch() {
|
|
|
151
165
|
}
|
|
152
166
|
setLoading(true);
|
|
153
167
|
setError(null);
|
|
154
|
-
if (mode === "
|
|
168
|
+
if (mode === "hybrid") {
|
|
169
|
+
const data = await graphqlFetch(endpoint, HYBRID_SEARCH_QUERY, { driveId, query: q, limit: 20 });
|
|
170
|
+
if (data?.knowledgeGraphHybridSearch) {
|
|
171
|
+
const raw = data.knowledgeGraphHybridSearch;
|
|
172
|
+
// Normalize RRF scores to 0-1 range (top result = 1.0)
|
|
173
|
+
const maxScore = raw.length > 0 ? raw[0].score : 1;
|
|
174
|
+
setResults(raw.map((r) => ({
|
|
175
|
+
...r.node,
|
|
176
|
+
similarity: maxScore > 0 ? r.score / maxScore : 0,
|
|
177
|
+
matchedBy: r.matchedBy,
|
|
178
|
+
})));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
setResults([]);
|
|
182
|
+
setError("Hybrid search unavailable. Try keyword mode.");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (mode === "semantic") {
|
|
155
186
|
const data = await graphqlFetch(endpoint, SEMANTIC_SEARCH_QUERY, { driveId, query: q, limit: 20 });
|
|
156
187
|
if (data?.knowledgeGraphSemanticSearch) {
|
|
157
188
|
setResults(data.knowledgeGraphSemanticSearch.map((r) => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/moc-editor/editor.tsx"],"names":[],"mappings":"AAuBA,MAAM,CAAC,OAAO,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/moc-editor/editor.tsx"],"names":[],"mappings":"AAuBA,MAAM,CAAC,OAAO,UAAU,MAAM,4CAgY7B"}
|
|
@@ -58,7 +58,7 @@ export default function Editor() {
|
|
|
58
58
|
backgroundColor: "var(--bai-bg)",
|
|
59
59
|
boxShadow: "0 0 0 1px var(--bai-ring)",
|
|
60
60
|
}, children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-xs", style: { color: "var(--bai-text-secondary)" }, children: idea.contextPhrase }), idea.noteRef &&
|
|
61
|
-
(noteTitle ? (_jsxs("button", { type: "button", onClick: () => setSelectedNode(idea.noteRef), className: "mt-0.5 text-[10px] text-left truncate max-w-full transition-colors hover:underline", style: { color: "var(--bai-accent)" }, title: `Open note: ${noteTitle}`, children: [noteTitle, _jsxs("svg", { className: "ml-1 inline h-2.5 w-2.5", style: { color: "var(--bai-text-faint)" }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }), _jsx("path", { d: "M15 3h6v6" }), _jsx("path", { d: "M10 14L21 3" })] })] })) : (
|
|
61
|
+
(noteTitle ? (_jsxs("button", { type: "button", onClick: () => setSelectedNode(idea.noteRef), className: "mt-0.5 text-[10px] text-left truncate max-w-full transition-colors hover:underline", style: { color: "var(--bai-accent)" }, title: `Open note: ${noteTitle}`, children: [noteTitle, _jsxs("svg", { className: "ml-1 inline h-2.5 w-2.5", style: { color: "var(--bai-text-faint)" }, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [_jsx("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }), _jsx("path", { d: "M15 3h6v6" }), _jsx("path", { d: "M10 14L21 3" })] })] })) : (_jsxs("button", { type: "button", onClick: () => setSelectedNode(idea.noteRef), className: "mt-0.5 text-[10px] font-mono text-left truncate max-w-full transition-colors hover:underline", style: { color: "var(--bai-text-faint)" }, title: `Open document: ${idea.noteRef}`, children: [idea.noteRef.slice(0, 12), "..."] })))] }), _jsx("button", { type: "button", onClick: () => dispatch(actions.removeCoreIdea({ id: idea.id })), className: "opacity-0 hover:text-red-400 group-hover:opacity-100", style: { color: "var(--bai-text-faint)" }, children: "\u00D7" })] }, idea.id));
|
|
62
62
|
}), _jsxs("form", { className: "flex gap-2", onSubmit: (e) => {
|
|
63
63
|
e.preventDefault();
|
|
64
64
|
if (!newIdeaRef.trim() || !newIdeaPhrase.trim())
|
package/dist/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAEjF,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AA+DtC,qBAAa,qBAAsB,SAAQ,qBAAqB,CAAC,EAAE,CAAC;WAClD,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAItC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,YAAY,CACzB,UAAU,EAAE,oBAAoB,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC;IAgMV,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;YAQrB,UAAU;CA8BzB"}
|
|
@@ -2,6 +2,62 @@ import { RelationalDbProcessor } from "@powerhousedao/shared/processors";
|
|
|
2
2
|
import { up } from "./migrations.js";
|
|
3
3
|
import { generateEmbedding } from "./embedder.js";
|
|
4
4
|
import { upsertEmbedding, deleteEmbedding } from "./embedding-store.js";
|
|
5
|
+
function summarizeOperation(type, input) {
|
|
6
|
+
switch (type) {
|
|
7
|
+
case "SET_TITLE":
|
|
8
|
+
return `Title changed to "${truncate(input.title)}"`;
|
|
9
|
+
case "SET_DESCRIPTION":
|
|
10
|
+
return `Description updated`;
|
|
11
|
+
case "SET_CONTENT": {
|
|
12
|
+
const len = typeof input.content === "string" ? input.content.length : 0;
|
|
13
|
+
return `Content updated (${len} chars)`;
|
|
14
|
+
}
|
|
15
|
+
case "SET_NOTE_TYPE":
|
|
16
|
+
return `Type set to ${String(input.noteType)}`;
|
|
17
|
+
case "SET_STATUS":
|
|
18
|
+
return `Status changed to ${String(input.status)}`;
|
|
19
|
+
case "ADD_LINK":
|
|
20
|
+
return `Linked to "${truncate(input.targetTitle)}" (${s(input.linkType, "RELATES_TO")})`;
|
|
21
|
+
case "REMOVE_LINK":
|
|
22
|
+
return `Removed link ${s(input.id)}`;
|
|
23
|
+
case "UPDATE_LINK_TYPE":
|
|
24
|
+
return `Link type changed to ${s(input.linkType)}`;
|
|
25
|
+
case "ADD_TOPIC":
|
|
26
|
+
return `Added topic #${s(input.name)}`;
|
|
27
|
+
case "REMOVE_TOPIC":
|
|
28
|
+
return `Removed topic`;
|
|
29
|
+
case "SET_PROVENANCE":
|
|
30
|
+
return `Provenance set: ${s(input.author, "unknown")}, ${s(input.sourceOrigin)}`;
|
|
31
|
+
case "SUBMIT_FOR_REVIEW":
|
|
32
|
+
return `Submitted for review`;
|
|
33
|
+
case "APPROVE_NOTE":
|
|
34
|
+
return `Approved by ${s(input.actor, "unknown")}`;
|
|
35
|
+
case "REJECT_NOTE":
|
|
36
|
+
return `Rejected: ${truncate(input.comment)}`;
|
|
37
|
+
case "ARCHIVE_NOTE":
|
|
38
|
+
return `Archived`;
|
|
39
|
+
case "RESTORE_NOTE":
|
|
40
|
+
return `Restored from archive`;
|
|
41
|
+
case "SET_METADATA_FIELD":
|
|
42
|
+
return `Metadata: ${String(input.field)} = ${truncate(input.value)}`;
|
|
43
|
+
default:
|
|
44
|
+
return type;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Safely stringify an unknown value with optional fallback */
|
|
48
|
+
function s(val, fallback = "") {
|
|
49
|
+
if (val == null)
|
|
50
|
+
return fallback;
|
|
51
|
+
if (typeof val === "string")
|
|
52
|
+
return val;
|
|
53
|
+
if (typeof val === "number" || typeof val === "boolean")
|
|
54
|
+
return String(val);
|
|
55
|
+
return fallback;
|
|
56
|
+
}
|
|
57
|
+
function truncate(val, max = 60) {
|
|
58
|
+
const str = s(val);
|
|
59
|
+
return str.length > max ? str.slice(0, max) + "..." : str;
|
|
60
|
+
}
|
|
5
61
|
export class GraphIndexerProcessor extends RelationalDbProcessor {
|
|
6
62
|
static getNamespace(driveId) {
|
|
7
63
|
return super.getNamespace(driveId);
|
|
@@ -28,6 +84,30 @@ export class GraphIndexerProcessor extends RelationalDbProcessor {
|
|
|
28
84
|
// Only process knowledge-note documents
|
|
29
85
|
if (context.documentType !== "bai/knowledge-note")
|
|
30
86
|
continue;
|
|
87
|
+
// Index operation for history tracking
|
|
88
|
+
try {
|
|
89
|
+
const input = operation.action.input;
|
|
90
|
+
const signer = operation.action.context?.signer;
|
|
91
|
+
await this.relationalDb
|
|
92
|
+
.insertInto("graph_operations")
|
|
93
|
+
.values({
|
|
94
|
+
id: `${documentId}-${operation.index}`,
|
|
95
|
+
document_id: documentId,
|
|
96
|
+
operation_type: operation.action.type,
|
|
97
|
+
timestamp: operation.timestampUtcMs ?? new Date().toISOString(),
|
|
98
|
+
index: operation.index,
|
|
99
|
+
scope: context.scope ?? "global",
|
|
100
|
+
summary: summarizeOperation(operation.action.type, input),
|
|
101
|
+
input_json: JSON.stringify(input),
|
|
102
|
+
signer_address: signer?.user?.address || null,
|
|
103
|
+
signer_app: signer?.app?.name || null,
|
|
104
|
+
})
|
|
105
|
+
.onConflict((oc) => oc.column("id").doNothing())
|
|
106
|
+
.execute();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// non-critical — don't block state reconciliation
|
|
110
|
+
}
|
|
31
111
|
// Collect last state per document
|
|
32
112
|
if (context.resultingState) {
|
|
33
113
|
lastByDocument.set(documentId, entry);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,wBAAsB,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,wBAAsB,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqI9D;AAED,wBAAsB,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhE"}
|
|
@@ -73,8 +73,54 @@ export async function up(db) {
|
|
|
73
73
|
.column("name")
|
|
74
74
|
.ifNotExists()
|
|
75
75
|
.execute();
|
|
76
|
+
// --- Operation history ---
|
|
77
|
+
await db.schema
|
|
78
|
+
.createTable("graph_operations")
|
|
79
|
+
.addColumn("id", "varchar(255)", (col) => col.primaryKey())
|
|
80
|
+
.addColumn("document_id", "varchar(255)", (col) => col.notNull())
|
|
81
|
+
.addColumn("operation_type", "varchar(100)", (col) => col.notNull())
|
|
82
|
+
.addColumn("timestamp", "varchar(50)", (col) => col.notNull())
|
|
83
|
+
.addColumn("index", "integer", (col) => col.notNull())
|
|
84
|
+
.addColumn("scope", "varchar(20)", (col) => col.notNull())
|
|
85
|
+
.addColumn("summary", "text")
|
|
86
|
+
.addColumn("input_json", "text")
|
|
87
|
+
.addColumn("signer_address", "varchar(255)")
|
|
88
|
+
.addColumn("signer_app", "varchar(255)")
|
|
89
|
+
.ifNotExists()
|
|
90
|
+
.execute();
|
|
91
|
+
await db.schema
|
|
92
|
+
.createIndex("idx_graph_ops_doc")
|
|
93
|
+
.on("graph_operations")
|
|
94
|
+
.column("document_id")
|
|
95
|
+
.ifNotExists()
|
|
96
|
+
.execute();
|
|
97
|
+
await db.schema
|
|
98
|
+
.createIndex("idx_graph_ops_timestamp")
|
|
99
|
+
.on("graph_operations")
|
|
100
|
+
.column("timestamp")
|
|
101
|
+
.ifNotExists()
|
|
102
|
+
.execute();
|
|
103
|
+
await db.schema
|
|
104
|
+
.createIndex("idx_graph_ops_type")
|
|
105
|
+
.on("graph_operations")
|
|
106
|
+
.column("operation_type")
|
|
107
|
+
.ifNotExists()
|
|
108
|
+
.execute();
|
|
109
|
+
// Add signer columns to graph_operations (idempotent)
|
|
110
|
+
for (const col of ["signer_address", "signer_app"]) {
|
|
111
|
+
try {
|
|
112
|
+
await db.schema
|
|
113
|
+
.alterTable("graph_operations")
|
|
114
|
+
.addColumn(col, "varchar(255)")
|
|
115
|
+
.execute();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// column likely already exists — ignore
|
|
119
|
+
}
|
|
120
|
+
}
|
|
76
121
|
}
|
|
77
122
|
export async function down(db) {
|
|
123
|
+
await db.schema.dropTable("graph_operations").ifExists().execute();
|
|
78
124
|
await db.schema.dropTable("graph_topics").ifExists().execute();
|
|
79
125
|
await db.schema.dropTable("graph_edges").ifExists().execute();
|
|
80
126
|
await db.schema.dropTable("graph_nodes").ifExists().execute();
|
|
@@ -40,6 +40,22 @@ export interface RelatedByTopicResult {
|
|
|
40
40
|
sharedTopics: string[];
|
|
41
41
|
sharedTopicCount: number;
|
|
42
42
|
}
|
|
43
|
+
export interface HybridSearchResult {
|
|
44
|
+
node: GraphNodeResult;
|
|
45
|
+
score: number;
|
|
46
|
+
matchedBy: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface OperationRecord {
|
|
49
|
+
id: string;
|
|
50
|
+
documentId: string;
|
|
51
|
+
operationType: string;
|
|
52
|
+
timestamp: string;
|
|
53
|
+
index: number;
|
|
54
|
+
scope: string;
|
|
55
|
+
summary: string | null;
|
|
56
|
+
signerAddress: string | null;
|
|
57
|
+
signerApp: string | null;
|
|
58
|
+
}
|
|
43
59
|
export declare function createGraphQuery(db: Kysely<DB>): {
|
|
44
60
|
allNodes(): Promise<GraphNodeResult[]>;
|
|
45
61
|
allEdges(): Promise<GraphEdgeResult[]>;
|
|
@@ -66,5 +82,18 @@ export declare function createGraphQuery(db: Kysely<DB>): {
|
|
|
66
82
|
nodesByAuthor(author: string): Promise<GraphNodeResult[]>;
|
|
67
83
|
nodesByOrigin(origin: string): Promise<GraphNodeResult[]>;
|
|
68
84
|
recentNodes(limit?: number, since?: string): Promise<GraphNodeResult[]>;
|
|
85
|
+
/**
|
|
86
|
+
* Hybrid search: run keyword + semantic in parallel, merge via
|
|
87
|
+
* Reciprocal Rank Fusion (RRF). semanticResults must be pre-fetched
|
|
88
|
+
* from the embedding store by the caller.
|
|
89
|
+
*/
|
|
90
|
+
hybridSearch(keywordQuery: string, semanticResults: Array<{
|
|
91
|
+
documentId: string;
|
|
92
|
+
similarity: number;
|
|
93
|
+
}>, limit?: number): Promise<HybridSearchResult[]>;
|
|
94
|
+
history(documentId: string, limit?: number): Promise<OperationRecord[]>;
|
|
95
|
+
activity(limit?: number, since?: string): Promise<OperationRecord[]>;
|
|
96
|
+
activityByType(operationType: string, limit?: number): Promise<OperationRecord[]>;
|
|
97
|
+
staleNodes(since: string, limit?: number): Promise<GraphNodeResult[]>;
|
|
69
98
|
};
|
|
70
99
|
//# sourceMappingURL=query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,EAAE,EAAwB,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,eAAe,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,19 @@ function rowToEdge(row) {
|
|
|
24
24
|
updatedAt: row.updated_at,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
function rowToOperation(row) {
|
|
28
|
+
return {
|
|
29
|
+
id: row.id,
|
|
30
|
+
documentId: row.document_id,
|
|
31
|
+
operationType: row.operation_type,
|
|
32
|
+
timestamp: row.timestamp,
|
|
33
|
+
index: row.index,
|
|
34
|
+
scope: row.scope,
|
|
35
|
+
summary: row.summary,
|
|
36
|
+
signerAddress: row.signer_address,
|
|
37
|
+
signerApp: row.signer_app,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
27
40
|
export function createGraphQuery(db) {
|
|
28
41
|
return {
|
|
29
42
|
async allNodes() {
|
|
@@ -372,5 +385,96 @@ export function createGraphQuery(db) {
|
|
|
372
385
|
const rows = await query.execute();
|
|
373
386
|
return rows.map(rowToNode);
|
|
374
387
|
},
|
|
388
|
+
/**
|
|
389
|
+
* Hybrid search: run keyword + semantic in parallel, merge via
|
|
390
|
+
* Reciprocal Rank Fusion (RRF). semanticResults must be pre-fetched
|
|
391
|
+
* from the embedding store by the caller.
|
|
392
|
+
*/
|
|
393
|
+
async hybridSearch(keywordQuery, semanticResults, limit = 20) {
|
|
394
|
+
const K = 60;
|
|
395
|
+
const scores = new Map();
|
|
396
|
+
// Keyword leg
|
|
397
|
+
const keywordResults = await this.fullSearch(keywordQuery, limit * 2);
|
|
398
|
+
keywordResults.forEach((node, rank) => {
|
|
399
|
+
const existing = scores.get(node.documentId) ?? {
|
|
400
|
+
score: 0,
|
|
401
|
+
matchedBy: [],
|
|
402
|
+
};
|
|
403
|
+
existing.score += 1 / (K + rank);
|
|
404
|
+
existing.matchedBy.push("keyword");
|
|
405
|
+
existing.node = node;
|
|
406
|
+
scores.set(node.documentId, existing);
|
|
407
|
+
});
|
|
408
|
+
// Semantic leg
|
|
409
|
+
for (let rank = 0; rank < semanticResults.length; rank++) {
|
|
410
|
+
const sr = semanticResults[rank];
|
|
411
|
+
const existing = scores.get(sr.documentId) ?? {
|
|
412
|
+
score: 0,
|
|
413
|
+
matchedBy: [],
|
|
414
|
+
};
|
|
415
|
+
existing.score += 1 / (K + rank);
|
|
416
|
+
if (!existing.matchedBy.includes("semantic")) {
|
|
417
|
+
existing.matchedBy.push("semantic");
|
|
418
|
+
}
|
|
419
|
+
// Fetch node data if we don't have it from keyword results
|
|
420
|
+
if (!existing.node) {
|
|
421
|
+
existing.node = await this.nodeByDocumentId(sr.documentId);
|
|
422
|
+
}
|
|
423
|
+
scores.set(sr.documentId, existing);
|
|
424
|
+
}
|
|
425
|
+
return [...scores.values()]
|
|
426
|
+
.filter((e) => !!e.node)
|
|
427
|
+
.sort((a, b) => b.score - a.score)
|
|
428
|
+
.slice(0, limit)
|
|
429
|
+
.map(({ score, matchedBy, node }) => ({ node, score, matchedBy }));
|
|
430
|
+
},
|
|
431
|
+
// ---- Operation history queries ----
|
|
432
|
+
async history(documentId, limit = 50) {
|
|
433
|
+
const rows = await db
|
|
434
|
+
.selectFrom("graph_operations")
|
|
435
|
+
.where("document_id", "=", documentId)
|
|
436
|
+
.orderBy("index", "desc")
|
|
437
|
+
.selectAll()
|
|
438
|
+
.limit(limit)
|
|
439
|
+
.execute();
|
|
440
|
+
return rows.map(rowToOperation);
|
|
441
|
+
},
|
|
442
|
+
async activity(limit = 50, since) {
|
|
443
|
+
let query = db
|
|
444
|
+
.selectFrom("graph_operations")
|
|
445
|
+
.orderBy("timestamp", "desc")
|
|
446
|
+
.selectAll()
|
|
447
|
+
.limit(limit);
|
|
448
|
+
if (since) {
|
|
449
|
+
query = query.where("timestamp", ">", since);
|
|
450
|
+
}
|
|
451
|
+
const rows = await query.execute();
|
|
452
|
+
return rows.map(rowToOperation);
|
|
453
|
+
},
|
|
454
|
+
async activityByType(operationType, limit = 50) {
|
|
455
|
+
const rows = await db
|
|
456
|
+
.selectFrom("graph_operations")
|
|
457
|
+
.where("operation_type", "=", operationType)
|
|
458
|
+
.orderBy("timestamp", "desc")
|
|
459
|
+
.selectAll()
|
|
460
|
+
.limit(limit)
|
|
461
|
+
.execute();
|
|
462
|
+
return rows.map(rowToOperation);
|
|
463
|
+
},
|
|
464
|
+
async staleNodes(since, limit = 50) {
|
|
465
|
+
// Nodes with no operations after `since` but that have neighbors
|
|
466
|
+
// who DO have operations after `since`
|
|
467
|
+
const staleRows = await db
|
|
468
|
+
.selectFrom("graph_nodes")
|
|
469
|
+
.where("document_id", "not in", db
|
|
470
|
+
.selectFrom("graph_operations")
|
|
471
|
+
.where("timestamp", ">", since)
|
|
472
|
+
.select("document_id"))
|
|
473
|
+
.where("updated_at", "<", since)
|
|
474
|
+
.selectAll()
|
|
475
|
+
.limit(limit)
|
|
476
|
+
.execute();
|
|
477
|
+
return staleRows.map(rowToNode);
|
|
478
|
+
},
|
|
375
479
|
};
|
|
376
480
|
}
|
|
@@ -25,9 +25,22 @@ export interface GraphEdge {
|
|
|
25
25
|
target_title: string | null;
|
|
26
26
|
updated_at: string;
|
|
27
27
|
}
|
|
28
|
+
export interface GraphOperation {
|
|
29
|
+
id: string;
|
|
30
|
+
document_id: string;
|
|
31
|
+
operation_type: string;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
index: number;
|
|
34
|
+
scope: string;
|
|
35
|
+
summary: string | null;
|
|
36
|
+
input_json: string | null;
|
|
37
|
+
signer_address: string | null;
|
|
38
|
+
signer_app: string | null;
|
|
39
|
+
}
|
|
28
40
|
export interface DB {
|
|
29
41
|
graph_nodes: GraphNode;
|
|
30
42
|
graph_edges: GraphEdge;
|
|
31
43
|
graph_topics: GraphTopic;
|
|
44
|
+
graph_operations: GraphOperation;
|
|
32
45
|
}
|
|
33
46
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/schema.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,EAAE;IACjB,WAAW,EAAE,SAAS,CAAC;IACvB,WAAW,EAAE,SAAS,CAAC;IACvB,YAAY,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../processors/graph-indexer/schema.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,EAAE;IACjB,WAAW,EAAE,SAAS,CAAC;IACvB,WAAW,EAAE,SAAS,CAAC;IACvB,YAAY,EAAE,UAAU,CAAC;IACzB,gBAAgB,EAAE,cAAc,CAAC;CAClC"}
|
package/dist/style.css
CHANGED
|
@@ -1495,17 +1495,17 @@
|
|
|
1495
1495
|
--tw-outline-style: none;
|
|
1496
1496
|
outline-style: none;
|
|
1497
1497
|
}
|
|
1498
|
-
.group-hover\:
|
|
1498
|
+
.group-hover\:text-\[var\(--bai-accent\)\] {
|
|
1499
1499
|
&:is(:where(.group):hover *) {
|
|
1500
1500
|
@media (hover: hover) {
|
|
1501
|
-
|
|
1501
|
+
color: var(--bai-accent);
|
|
1502
1502
|
}
|
|
1503
1503
|
}
|
|
1504
1504
|
}
|
|
1505
|
-
.group-hover\:
|
|
1505
|
+
.group-hover\:opacity-50 {
|
|
1506
1506
|
&:is(:where(.group):hover *) {
|
|
1507
1507
|
@media (hover: hover) {
|
|
1508
|
-
|
|
1508
|
+
opacity: 50%;
|
|
1509
1509
|
}
|
|
1510
1510
|
}
|
|
1511
1511
|
}
|
|
@@ -360,6 +360,61 @@ export declare class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
360
360
|
};
|
|
361
361
|
similarity: number;
|
|
362
362
|
}[]>;
|
|
363
|
+
knowledgeGraphHybridSearch: (_: unknown, args: {
|
|
364
|
+
driveId: string;
|
|
365
|
+
query: string;
|
|
366
|
+
limit?: number;
|
|
367
|
+
}) => Promise<{
|
|
368
|
+
node: {
|
|
369
|
+
_driveId: string;
|
|
370
|
+
id: string;
|
|
371
|
+
documentId: string;
|
|
372
|
+
title: string | null;
|
|
373
|
+
description: string | null;
|
|
374
|
+
noteType: string | null;
|
|
375
|
+
status: string | null;
|
|
376
|
+
content: string | null;
|
|
377
|
+
author: string | null;
|
|
378
|
+
sourceOrigin: string | null;
|
|
379
|
+
createdAt: string | null;
|
|
380
|
+
updatedAt: string;
|
|
381
|
+
};
|
|
382
|
+
score: number;
|
|
383
|
+
matchedBy: string[];
|
|
384
|
+
}[]>;
|
|
385
|
+
knowledgeGraphHistory: (_: unknown, args: {
|
|
386
|
+
driveId: string;
|
|
387
|
+
documentId: string;
|
|
388
|
+
limit?: number;
|
|
389
|
+
}) => Promise<import("../../processors/graph-indexer/query.js").OperationRecord[]>;
|
|
390
|
+
knowledgeGraphActivity: (_: unknown, args: {
|
|
391
|
+
driveId: string;
|
|
392
|
+
limit?: number;
|
|
393
|
+
since?: string;
|
|
394
|
+
}) => Promise<import("../../processors/graph-indexer/query.js").OperationRecord[]>;
|
|
395
|
+
knowledgeGraphActivityByType: (_: unknown, args: {
|
|
396
|
+
driveId: string;
|
|
397
|
+
operationType: string;
|
|
398
|
+
limit?: number;
|
|
399
|
+
}) => Promise<import("../../processors/graph-indexer/query.js").OperationRecord[]>;
|
|
400
|
+
knowledgeGraphStale: (_: unknown, args: {
|
|
401
|
+
driveId: string;
|
|
402
|
+
since: string;
|
|
403
|
+
limit?: number;
|
|
404
|
+
}) => Promise<{
|
|
405
|
+
_driveId: string;
|
|
406
|
+
id: string;
|
|
407
|
+
documentId: string;
|
|
408
|
+
title: string | null;
|
|
409
|
+
description: string | null;
|
|
410
|
+
noteType: string | null;
|
|
411
|
+
status: string | null;
|
|
412
|
+
content: string | null;
|
|
413
|
+
author: string | null;
|
|
414
|
+
sourceOrigin: string | null;
|
|
415
|
+
createdAt: string | null;
|
|
416
|
+
updatedAt: string;
|
|
417
|
+
}[]>;
|
|
363
418
|
knowledgeGraphDebug: (_: unknown, args: {
|
|
364
419
|
driveId: string;
|
|
365
420
|
}) => Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subgraph.d.ts","sourceRoot":"","sources":["../../../subgraphs/knowledge-graph/subgraph.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAa7E,qBAAa,sBAAuB,SAAQ,YAAY;IAC7C,IAAI,SAAoB;IAExB,QAAQ,
|
|
1
|
+
{"version":3,"file":"subgraph.d.ts","sourceRoot":"","sources":["../../../subgraphs/knowledge-graph/subgraph.ts"],"names":[],"mappings":"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"}
|
|
@@ -129,6 +129,32 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
129
129
|
documentId: String!
|
|
130
130
|
limit: Int
|
|
131
131
|
): [SemanticResult!]!
|
|
132
|
+
knowledgeGraphHybridSearch(
|
|
133
|
+
driveId: ID!
|
|
134
|
+
query: String!
|
|
135
|
+
limit: Int
|
|
136
|
+
): [HybridResult!]!
|
|
137
|
+
|
|
138
|
+
knowledgeGraphHistory(
|
|
139
|
+
driveId: ID!
|
|
140
|
+
documentId: String!
|
|
141
|
+
limit: Int
|
|
142
|
+
): [OperationRecord!]!
|
|
143
|
+
knowledgeGraphActivity(
|
|
144
|
+
driveId: ID!
|
|
145
|
+
limit: Int
|
|
146
|
+
since: String
|
|
147
|
+
): [OperationRecord!]!
|
|
148
|
+
knowledgeGraphActivityByType(
|
|
149
|
+
driveId: ID!
|
|
150
|
+
operationType: String!
|
|
151
|
+
limit: Int
|
|
152
|
+
): [OperationRecord!]!
|
|
153
|
+
knowledgeGraphStale(
|
|
154
|
+
driveId: ID!
|
|
155
|
+
since: String!
|
|
156
|
+
limit: Int
|
|
157
|
+
): [KnowledgeGraphNode!]!
|
|
132
158
|
|
|
133
159
|
"""
|
|
134
160
|
Debug: raw processor DB tables
|
|
@@ -147,6 +173,24 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
147
173
|
similarity: Float!
|
|
148
174
|
}
|
|
149
175
|
|
|
176
|
+
type HybridResult {
|
|
177
|
+
node: KnowledgeGraphNode!
|
|
178
|
+
score: Float!
|
|
179
|
+
matchedBy: [String!]!
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
type OperationRecord {
|
|
183
|
+
id: String!
|
|
184
|
+
documentId: String!
|
|
185
|
+
operationType: String!
|
|
186
|
+
timestamp: String!
|
|
187
|
+
index: Int!
|
|
188
|
+
scope: String!
|
|
189
|
+
summary: String
|
|
190
|
+
signerAddress: String
|
|
191
|
+
signerApp: String
|
|
192
|
+
}
|
|
193
|
+
|
|
150
194
|
type GraphDebugInfo {
|
|
151
195
|
rawNodeCount: Int!
|
|
152
196
|
rawEdgeCount: Int!
|
|
@@ -331,6 +375,34 @@ export class KnowledgeGraphSubgraph extends BaseSubgraph {
|
|
|
331
375
|
}
|
|
332
376
|
return semanticResults.slice(0, args.limit ?? 10);
|
|
333
377
|
},
|
|
378
|
+
knowledgeGraphHybridSearch: async (_, args) => {
|
|
379
|
+
const queryEmbedding = await generateEmbedding(args.query);
|
|
380
|
+
const semanticResults = await searchSimilar(queryEmbedding, (args.limit ?? 20) * 2);
|
|
381
|
+
const graphQuery = this.getQuery(args.driveId);
|
|
382
|
+
const hybridResults = await graphQuery.hybridSearch(args.query, semanticResults, args.limit ?? 20);
|
|
383
|
+
return hybridResults.map((r) => ({
|
|
384
|
+
node: { ...r.node, _driveId: args.driveId },
|
|
385
|
+
score: r.score,
|
|
386
|
+
matchedBy: r.matchedBy,
|
|
387
|
+
}));
|
|
388
|
+
},
|
|
389
|
+
knowledgeGraphHistory: async (_, args) => {
|
|
390
|
+
const query = this.getQuery(args.driveId);
|
|
391
|
+
return query.history(args.documentId, args.limit ?? 50);
|
|
392
|
+
},
|
|
393
|
+
knowledgeGraphActivity: async (_, args) => {
|
|
394
|
+
const query = this.getQuery(args.driveId);
|
|
395
|
+
return query.activity(args.limit ?? 50, args.since ?? undefined);
|
|
396
|
+
},
|
|
397
|
+
knowledgeGraphActivityByType: async (_, args) => {
|
|
398
|
+
const query = this.getQuery(args.driveId);
|
|
399
|
+
return query.activityByType(args.operationType, args.limit ?? 50);
|
|
400
|
+
},
|
|
401
|
+
knowledgeGraphStale: async (_, args) => {
|
|
402
|
+
const query = this.getQuery(args.driveId);
|
|
403
|
+
const nodes = await query.staleNodes(args.since, args.limit ?? 50);
|
|
404
|
+
return nodes.map((n) => ({ ...n, _driveId: args.driveId }));
|
|
405
|
+
},
|
|
334
406
|
knowledgeGraphDebug: async (_, args) => {
|
|
335
407
|
const namespace = GraphIndexerProcessor.getNamespace(args.driveId);
|
|
336
408
|
try {
|