mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-03 21:02:40 +02:00
feat(filesystem): implement filesystem tree watch functionality using chokidar for real-time updates on local folder changes
This commit is contained in:
parent
3fa8c790f5
commit
f330d1431c
8 changed files with 583 additions and 23 deletions
|
|
@ -47,6 +47,42 @@ interface EditorContent {
|
|||
const EDITABLE_DOCUMENT_TYPES = new Set(["FILE", "NOTE"]);
|
||||
type EditorRenderMode = "rich_markdown" | "source_code";
|
||||
|
||||
type AgentFilesystemMount = {
|
||||
mount: string;
|
||||
rootPath: string;
|
||||
};
|
||||
|
||||
function normalizeLocalVirtualPathForEditor(
|
||||
candidatePath: string,
|
||||
mounts: AgentFilesystemMount[]
|
||||
): string {
|
||||
const normalizedCandidate = candidatePath.trim().replace(/\\/g, "/").replace(/\/+/g, "/");
|
||||
if (!normalizedCandidate) return candidatePath;
|
||||
const defaultMount = mounts[0]?.mount;
|
||||
if (!defaultMount) {
|
||||
return normalizedCandidate.startsWith("/")
|
||||
? normalizedCandidate
|
||||
: `/${normalizedCandidate.replace(/^\/+/, "")}`;
|
||||
}
|
||||
|
||||
const mountNames = new Set(mounts.map((entry) => entry.mount));
|
||||
if (normalizedCandidate.startsWith("/")) {
|
||||
const relative = normalizedCandidate.replace(/^\/+/, "");
|
||||
const [firstSegment] = relative.split("/", 1);
|
||||
if (mountNames.has(firstSegment)) {
|
||||
return `/${relative}`;
|
||||
}
|
||||
return `/${defaultMount}/${relative}`;
|
||||
}
|
||||
|
||||
const relative = normalizedCandidate.replace(/^\/+/, "");
|
||||
const [firstSegment] = relative.split("/", 1);
|
||||
if (mountNames.has(firstSegment)) {
|
||||
return `/${relative}`;
|
||||
}
|
||||
return `/${defaultMount}/${relative}`;
|
||||
}
|
||||
|
||||
function EditorPanelSkeleton() {
|
||||
return (
|
||||
<div className="space-y-6 p-6">
|
||||
|
|
@ -100,6 +136,22 @@ export function EditorPanelContent({
|
|||
const [displayTitle, setDisplayTitle] = useState(title || "Untitled");
|
||||
const isLocalFileMode = kind === "local_file";
|
||||
const editorRenderMode: EditorRenderMode = isLocalFileMode ? "source_code" : "rich_markdown";
|
||||
const resolveLocalVirtualPath = useCallback(
|
||||
async (candidatePath: string): Promise<string> => {
|
||||
if (!electronAPI?.getAgentFilesystemMounts) {
|
||||
return candidatePath;
|
||||
}
|
||||
try {
|
||||
const mounts = (await electronAPI.getAgentFilesystemMounts(
|
||||
searchSpaceId
|
||||
)) as AgentFilesystemMount[];
|
||||
return normalizeLocalVirtualPathForEditor(candidatePath, mounts);
|
||||
} catch {
|
||||
return candidatePath;
|
||||
}
|
||||
},
|
||||
[electronAPI, searchSpaceId]
|
||||
);
|
||||
|
||||
const isLargeDocument = (editorDoc?.content_size_bytes ?? 0) > LARGE_DOCUMENT_THRESHOLD;
|
||||
|
||||
|
|
@ -124,14 +176,15 @@ export function EditorPanelContent({
|
|||
if (!electronAPI?.readAgentLocalFileText) {
|
||||
throw new Error("Local file editor is available only in desktop mode.");
|
||||
}
|
||||
const resolvedLocalPath = await resolveLocalVirtualPath(localFilePath);
|
||||
const readResult = await electronAPI.readAgentLocalFileText(
|
||||
localFilePath,
|
||||
resolvedLocalPath,
|
||||
searchSpaceId
|
||||
);
|
||||
if (!readResult.ok) {
|
||||
throw new Error(readResult.error || "Failed to read local file");
|
||||
}
|
||||
const inferredTitle = localFilePath.split("/").pop() || localFilePath;
|
||||
const inferredTitle = resolvedLocalPath.split("/").pop() || resolvedLocalPath;
|
||||
const content: EditorContent = {
|
||||
document_id: -1,
|
||||
title: inferredTitle,
|
||||
|
|
@ -195,7 +248,7 @@ export function EditorPanelContent({
|
|||
|
||||
doFetch().catch(() => {});
|
||||
return () => controller.abort();
|
||||
}, [documentId, electronAPI, isLocalFileMode, localFilePath, searchSpaceId, title]);
|
||||
}, [documentId, electronAPI, isLocalFileMode, localFilePath, resolveLocalVirtualPath, searchSpaceId, title]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -239,9 +292,10 @@ export function EditorPanelContent({
|
|||
if (!electronAPI?.writeAgentLocalFileText) {
|
||||
throw new Error("Local file editor is available only in desktop mode.");
|
||||
}
|
||||
const resolvedLocalPath = await resolveLocalVirtualPath(localFilePath);
|
||||
const contentToSave = markdownRef.current;
|
||||
const writeResult = await electronAPI.writeAgentLocalFileText(
|
||||
localFilePath,
|
||||
resolvedLocalPath,
|
||||
contentToSave,
|
||||
searchSpaceId
|
||||
);
|
||||
|
|
@ -290,7 +344,7 @@ export function EditorPanelContent({
|
|||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}, [documentId, electronAPI, isLocalFileMode, localFilePath, searchSpaceId]);
|
||||
}, [documentId, electronAPI, isLocalFileMode, localFilePath, resolveLocalVirtualPath, searchSpaceId]);
|
||||
|
||||
const isEditableType = editorDoc
|
||||
? (editorRenderMode === "source_code" ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue