mindcache 3.6.0 → 3.7.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/dist/cloud/index.js.map +1 -1
- package/dist/cloud/index.mjs.map +1 -1
- package/dist/index.d.mts +366 -1
- package/dist/index.d.ts +366 -1
- package/dist/index.js +1021 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1012 -3
- package/dist/index.mjs.map +1 -1
- package/dist/server.js.map +1 -1
- package/dist/server.mjs.map +1 -1
- package/package.json +4 -8
package/dist/index.mjs
CHANGED
|
@@ -4,9 +4,11 @@ import * as decoding from 'lib0/decoding';
|
|
|
4
4
|
import * as Y from 'yjs';
|
|
5
5
|
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
6
6
|
import diff from 'fast-diff';
|
|
7
|
-
import { tool } from 'ai';
|
|
7
|
+
import { tool, streamText, stepCountIs } from 'ai';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { useState, useRef, useEffect } from 'react';
|
|
9
|
+
import React2, { createContext, useState, useRef, useEffect, useContext, useCallback } from 'react';
|
|
10
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
11
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
10
12
|
|
|
11
13
|
var __defProp = Object.defineProperty;
|
|
12
14
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -3405,10 +3407,1017 @@ function useMindCache(options) {
|
|
|
3405
3407
|
error
|
|
3406
3408
|
};
|
|
3407
3409
|
}
|
|
3410
|
+
function createModel(provider, model, apiKey) {
|
|
3411
|
+
switch (provider) {
|
|
3412
|
+
case "openai": {
|
|
3413
|
+
const openai = createOpenAI({ apiKey });
|
|
3414
|
+
return openai(model);
|
|
3415
|
+
}
|
|
3416
|
+
case "anthropic":
|
|
3417
|
+
throw new Error("Anthropic provider not yet implemented. Use modelProvider for custom providers.");
|
|
3418
|
+
default:
|
|
3419
|
+
throw new Error(`Unknown provider: ${provider}. Use modelProvider for custom providers.`);
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
var MindCacheContext = createContext(null);
|
|
3423
|
+
function useMindCacheContext() {
|
|
3424
|
+
const context = useContext(MindCacheContext);
|
|
3425
|
+
if (!context) {
|
|
3426
|
+
throw new Error("useMindCacheContext must be used within a MindCacheProvider");
|
|
3427
|
+
}
|
|
3428
|
+
return context;
|
|
3429
|
+
}
|
|
3430
|
+
function MindCacheProvider({
|
|
3431
|
+
mindcache: mcOptions,
|
|
3432
|
+
sync: syncConfig,
|
|
3433
|
+
ai: aiConfig = {},
|
|
3434
|
+
children
|
|
3435
|
+
}) {
|
|
3436
|
+
const [mindcache2, setMindcache] = useState(null);
|
|
3437
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
3438
|
+
const [error, setError] = useState(null);
|
|
3439
|
+
const [hasApiKey, setHasApiKey] = useState(false);
|
|
3440
|
+
const [lastSyncAt, setLastSyncAt] = useState(null);
|
|
3441
|
+
const [isSyncing, setIsSyncing] = useState(false);
|
|
3442
|
+
const initRef = useRef(false);
|
|
3443
|
+
const resolvedAiConfig = {
|
|
3444
|
+
provider: "openai",
|
|
3445
|
+
model: "gpt-4o",
|
|
3446
|
+
keyStorage: "localStorage",
|
|
3447
|
+
storageKey: "ai_api_key",
|
|
3448
|
+
...aiConfig
|
|
3449
|
+
};
|
|
3450
|
+
useEffect(() => {
|
|
3451
|
+
if (initRef.current) {
|
|
3452
|
+
return;
|
|
3453
|
+
}
|
|
3454
|
+
initRef.current = true;
|
|
3455
|
+
const init = async () => {
|
|
3456
|
+
try {
|
|
3457
|
+
const options = mcOptions || {
|
|
3458
|
+
indexedDB: {
|
|
3459
|
+
dbName: "mindcache_local_first",
|
|
3460
|
+
storeName: "mindcache_store",
|
|
3461
|
+
debounceMs: 1e3
|
|
3462
|
+
}
|
|
3463
|
+
};
|
|
3464
|
+
const mc = new MindCache(options);
|
|
3465
|
+
await mc.waitForSync();
|
|
3466
|
+
setMindcache(mc);
|
|
3467
|
+
setIsLoaded(true);
|
|
3468
|
+
if (resolvedAiConfig.keyStorage === "localStorage" && typeof window !== "undefined") {
|
|
3469
|
+
const stored = localStorage.getItem(resolvedAiConfig.storageKey || "openai_api_key");
|
|
3470
|
+
setHasApiKey(!!stored);
|
|
3471
|
+
} else if (resolvedAiConfig.apiKey) {
|
|
3472
|
+
setHasApiKey(true);
|
|
3473
|
+
}
|
|
3474
|
+
} catch (err) {
|
|
3475
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3476
|
+
setIsLoaded(true);
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
init();
|
|
3480
|
+
return () => {
|
|
3481
|
+
if (mindcache2) {
|
|
3482
|
+
mindcache2.disconnect();
|
|
3483
|
+
}
|
|
3484
|
+
};
|
|
3485
|
+
}, []);
|
|
3486
|
+
const getApiKey = () => {
|
|
3487
|
+
if (resolvedAiConfig.apiKey) {
|
|
3488
|
+
return resolvedAiConfig.apiKey;
|
|
3489
|
+
}
|
|
3490
|
+
if (resolvedAiConfig.keyStorage === "localStorage" && typeof window !== "undefined") {
|
|
3491
|
+
return localStorage.getItem(resolvedAiConfig.storageKey || "openai_api_key");
|
|
3492
|
+
}
|
|
3493
|
+
return null;
|
|
3494
|
+
};
|
|
3495
|
+
const setApiKey = (key) => {
|
|
3496
|
+
if (resolvedAiConfig.keyStorage === "localStorage" && typeof window !== "undefined") {
|
|
3497
|
+
localStorage.setItem(resolvedAiConfig.storageKey || "openai_api_key", key);
|
|
3498
|
+
setHasApiKey(true);
|
|
3499
|
+
}
|
|
3500
|
+
};
|
|
3501
|
+
const getModel = () => {
|
|
3502
|
+
const apiKey = getApiKey();
|
|
3503
|
+
if (!apiKey) {
|
|
3504
|
+
throw new Error("API key not configured. Call setApiKey() first or configure ai.apiKey.");
|
|
3505
|
+
}
|
|
3506
|
+
if (resolvedAiConfig.modelProvider) {
|
|
3507
|
+
return resolvedAiConfig.modelProvider(apiKey);
|
|
3508
|
+
}
|
|
3509
|
+
const provider = resolvedAiConfig.provider || "openai";
|
|
3510
|
+
const model = resolvedAiConfig.model || "gpt-4o";
|
|
3511
|
+
return createModel(provider, model, apiKey);
|
|
3512
|
+
};
|
|
3513
|
+
const syncToGitStore = async () => {
|
|
3514
|
+
if (!mindcache2 || !syncConfig?.gitstore) {
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
setIsSyncing(true);
|
|
3518
|
+
try {
|
|
3519
|
+
let gitStoreModule;
|
|
3520
|
+
try {
|
|
3521
|
+
gitStoreModule = await Function('return import("@mindcache/gitstore")')();
|
|
3522
|
+
} catch {
|
|
3523
|
+
throw new Error("@mindcache/gitstore is not installed. Run: npm install @mindcache/gitstore");
|
|
3524
|
+
}
|
|
3525
|
+
const { GitStore, MindCacheSync } = gitStoreModule;
|
|
3526
|
+
const token = typeof syncConfig.gitstore.token === "function" ? await syncConfig.gitstore.token() : syncConfig.gitstore.token;
|
|
3527
|
+
const gitStore = new GitStore({
|
|
3528
|
+
owner: syncConfig.gitstore.owner,
|
|
3529
|
+
repo: syncConfig.gitstore.repo,
|
|
3530
|
+
tokenProvider: async () => token
|
|
3531
|
+
});
|
|
3532
|
+
const sync = new MindCacheSync(gitStore, mindcache2, {
|
|
3533
|
+
filePath: syncConfig.gitstore.path || "mindcache.md"
|
|
3534
|
+
});
|
|
3535
|
+
await sync.save({ message: "Auto-sync from MindCache" });
|
|
3536
|
+
setLastSyncAt(/* @__PURE__ */ new Date());
|
|
3537
|
+
} catch (err) {
|
|
3538
|
+
console.error("[MindCacheProvider] Sync error:", err);
|
|
3539
|
+
throw err;
|
|
3540
|
+
} finally {
|
|
3541
|
+
setIsSyncing(false);
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
const value = {
|
|
3545
|
+
mindcache: mindcache2,
|
|
3546
|
+
isLoaded,
|
|
3547
|
+
error,
|
|
3548
|
+
aiConfig: resolvedAiConfig,
|
|
3549
|
+
syncConfig,
|
|
3550
|
+
getApiKey,
|
|
3551
|
+
setApiKey,
|
|
3552
|
+
hasApiKey,
|
|
3553
|
+
getModel,
|
|
3554
|
+
syncToGitStore,
|
|
3555
|
+
lastSyncAt,
|
|
3556
|
+
isSyncing
|
|
3557
|
+
};
|
|
3558
|
+
return /* @__PURE__ */ jsx(MindCacheContext.Provider, { value, children });
|
|
3559
|
+
}
|
|
3560
|
+
function generateId() {
|
|
3561
|
+
return Math.random().toString(36).substring(2, 15) + Date.now().toString(36);
|
|
3562
|
+
}
|
|
3563
|
+
function useClientChat(options = {}) {
|
|
3564
|
+
const context = useMindCacheContext();
|
|
3565
|
+
const mc = options.mindcache || context.mindcache;
|
|
3566
|
+
const [messages, setMessages] = useState(options.initialMessages || []);
|
|
3567
|
+
const [status, setStatus] = useState("idle");
|
|
3568
|
+
const [error, setError] = useState(null);
|
|
3569
|
+
const [streamingContent, setStreamingContent] = useState("");
|
|
3570
|
+
const abortControllerRef = useRef(null);
|
|
3571
|
+
const {
|
|
3572
|
+
systemPrompt,
|
|
3573
|
+
onMindCacheChange,
|
|
3574
|
+
onFinish,
|
|
3575
|
+
onError,
|
|
3576
|
+
maxToolCalls = 5
|
|
3577
|
+
} = options;
|
|
3578
|
+
const apiKey = context.getApiKey();
|
|
3579
|
+
const addMessage = useCallback((msg) => {
|
|
3580
|
+
const newMessage = {
|
|
3581
|
+
...msg,
|
|
3582
|
+
id: generateId(),
|
|
3583
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3584
|
+
};
|
|
3585
|
+
setMessages((prev) => [...prev, newMessage]);
|
|
3586
|
+
return newMessage;
|
|
3587
|
+
}, []);
|
|
3588
|
+
const clearMessages = useCallback(() => {
|
|
3589
|
+
setMessages([]);
|
|
3590
|
+
setError(null);
|
|
3591
|
+
setStreamingContent("");
|
|
3592
|
+
}, []);
|
|
3593
|
+
const stop = useCallback(() => {
|
|
3594
|
+
abortControllerRef.current?.abort();
|
|
3595
|
+
setStatus("idle");
|
|
3596
|
+
}, []);
|
|
3597
|
+
const sendMessage = useCallback(async (content) => {
|
|
3598
|
+
if (!mc) {
|
|
3599
|
+
const err = new Error("MindCache not initialized");
|
|
3600
|
+
setError(err);
|
|
3601
|
+
onError?.(err);
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
if (!apiKey) {
|
|
3605
|
+
const err = new Error("API key not configured. Please set your API key.");
|
|
3606
|
+
setError(err);
|
|
3607
|
+
onError?.(err);
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
abortControllerRef.current?.abort();
|
|
3611
|
+
abortControllerRef.current = new AbortController();
|
|
3612
|
+
const userMessage = addMessage({ role: "user", content });
|
|
3613
|
+
setStatus("loading");
|
|
3614
|
+
setError(null);
|
|
3615
|
+
setStreamingContent("");
|
|
3616
|
+
try {
|
|
3617
|
+
const model = context.getModel();
|
|
3618
|
+
const finalSystemPrompt = systemPrompt || mc.get_system_prompt();
|
|
3619
|
+
const tools = mc.create_vercel_ai_tools();
|
|
3620
|
+
const apiMessages = messages.concat(userMessage).map((m) => ({
|
|
3621
|
+
role: m.role,
|
|
3622
|
+
content: m.content
|
|
3623
|
+
}));
|
|
3624
|
+
setStatus("streaming");
|
|
3625
|
+
const parts = [];
|
|
3626
|
+
let accumulatedText = "";
|
|
3627
|
+
const result = await streamText({
|
|
3628
|
+
model,
|
|
3629
|
+
system: finalSystemPrompt,
|
|
3630
|
+
messages: apiMessages,
|
|
3631
|
+
tools,
|
|
3632
|
+
stopWhen: stepCountIs(maxToolCalls),
|
|
3633
|
+
abortSignal: abortControllerRef.current.signal,
|
|
3634
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
3635
|
+
onStepFinish: async (step) => {
|
|
3636
|
+
if (step.toolCalls && step.toolCalls.length > 0) {
|
|
3637
|
+
for (const toolCall of step.toolCalls) {
|
|
3638
|
+
const toolName = toolCall.toolName;
|
|
3639
|
+
const args = toolCall.args || toolCall.input || {};
|
|
3640
|
+
parts.push({
|
|
3641
|
+
type: "tool-call",
|
|
3642
|
+
toolCallId: toolCall.toolCallId,
|
|
3643
|
+
toolName,
|
|
3644
|
+
args
|
|
3645
|
+
});
|
|
3646
|
+
if (typeof toolName === "string" && (toolName.startsWith("write_") || toolName === "create_key")) {
|
|
3647
|
+
const value = args.value;
|
|
3648
|
+
const result2 = mc.executeToolCall(toolName, value);
|
|
3649
|
+
parts.push({
|
|
3650
|
+
type: "tool-result",
|
|
3651
|
+
toolCallId: toolCall.toolCallId,
|
|
3652
|
+
toolName,
|
|
3653
|
+
result: result2
|
|
3654
|
+
});
|
|
3655
|
+
onMindCacheChange?.();
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
if (step.text) {
|
|
3660
|
+
accumulatedText += step.text;
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
});
|
|
3664
|
+
for await (const chunk of result.textStream) {
|
|
3665
|
+
accumulatedText += chunk;
|
|
3666
|
+
setStreamingContent(accumulatedText);
|
|
3667
|
+
}
|
|
3668
|
+
if (accumulatedText) {
|
|
3669
|
+
parts.unshift({ type: "text", text: accumulatedText });
|
|
3670
|
+
}
|
|
3671
|
+
const assistantMessage = {
|
|
3672
|
+
id: generateId(),
|
|
3673
|
+
role: "assistant",
|
|
3674
|
+
content: accumulatedText,
|
|
3675
|
+
parts: parts.length > 0 ? parts : void 0,
|
|
3676
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3677
|
+
};
|
|
3678
|
+
setMessages((prev) => [...prev, assistantMessage]);
|
|
3679
|
+
setStreamingContent("");
|
|
3680
|
+
setStatus("idle");
|
|
3681
|
+
onFinish?.(assistantMessage);
|
|
3682
|
+
} catch (err) {
|
|
3683
|
+
if (err.name === "AbortError") {
|
|
3684
|
+
if (streamingContent) {
|
|
3685
|
+
const partialMessage = {
|
|
3686
|
+
id: generateId(),
|
|
3687
|
+
role: "assistant",
|
|
3688
|
+
content: streamingContent + " [stopped]",
|
|
3689
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3690
|
+
};
|
|
3691
|
+
setMessages((prev) => [...prev, partialMessage]);
|
|
3692
|
+
}
|
|
3693
|
+
setStreamingContent("");
|
|
3694
|
+
setStatus("idle");
|
|
3695
|
+
return;
|
|
3696
|
+
}
|
|
3697
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
3698
|
+
setError(error2);
|
|
3699
|
+
setStatus("error");
|
|
3700
|
+
setStreamingContent("");
|
|
3701
|
+
onError?.(error2);
|
|
3702
|
+
}
|
|
3703
|
+
}, [
|
|
3704
|
+
mc,
|
|
3705
|
+
apiKey,
|
|
3706
|
+
context,
|
|
3707
|
+
messages,
|
|
3708
|
+
systemPrompt,
|
|
3709
|
+
maxToolCalls,
|
|
3710
|
+
addMessage,
|
|
3711
|
+
onMindCacheChange,
|
|
3712
|
+
onFinish,
|
|
3713
|
+
onError,
|
|
3714
|
+
streamingContent
|
|
3715
|
+
]);
|
|
3716
|
+
useEffect(() => {
|
|
3717
|
+
return () => {
|
|
3718
|
+
abortControllerRef.current?.abort();
|
|
3719
|
+
};
|
|
3720
|
+
}, []);
|
|
3721
|
+
return {
|
|
3722
|
+
messages,
|
|
3723
|
+
status,
|
|
3724
|
+
error,
|
|
3725
|
+
sendMessage,
|
|
3726
|
+
clearMessages,
|
|
3727
|
+
isLoading: status === "loading" || status === "streaming",
|
|
3728
|
+
addMessage,
|
|
3729
|
+
stop,
|
|
3730
|
+
streamingContent
|
|
3731
|
+
};
|
|
3732
|
+
}
|
|
3733
|
+
var defaultTheme = {
|
|
3734
|
+
background: "#000",
|
|
3735
|
+
userBubble: "#1a1a2e",
|
|
3736
|
+
assistantBubble: "#0d0d0d",
|
|
3737
|
+
textColor: "#22c55e",
|
|
3738
|
+
secondaryTextColor: "#6b7280",
|
|
3739
|
+
borderColor: "#333",
|
|
3740
|
+
primaryColor: "#22c55e",
|
|
3741
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'
|
|
3742
|
+
};
|
|
3743
|
+
function DefaultMessage({
|
|
3744
|
+
message,
|
|
3745
|
+
theme
|
|
3746
|
+
}) {
|
|
3747
|
+
const isUser = message.role === "user";
|
|
3748
|
+
return /* @__PURE__ */ jsx(
|
|
3749
|
+
"div",
|
|
3750
|
+
{
|
|
3751
|
+
style: {
|
|
3752
|
+
display: "flex",
|
|
3753
|
+
justifyContent: isUser ? "flex-end" : "flex-start",
|
|
3754
|
+
marginBottom: "12px"
|
|
3755
|
+
},
|
|
3756
|
+
children: /* @__PURE__ */ jsxs(
|
|
3757
|
+
"div",
|
|
3758
|
+
{
|
|
3759
|
+
style: {
|
|
3760
|
+
maxWidth: "80%",
|
|
3761
|
+
padding: "12px 16px",
|
|
3762
|
+
borderRadius: "12px",
|
|
3763
|
+
backgroundColor: isUser ? theme.userBubble : theme.assistantBubble,
|
|
3764
|
+
border: `1px solid ${theme.borderColor}`
|
|
3765
|
+
},
|
|
3766
|
+
children: [
|
|
3767
|
+
/* @__PURE__ */ jsx(
|
|
3768
|
+
"div",
|
|
3769
|
+
{
|
|
3770
|
+
style: {
|
|
3771
|
+
fontSize: "10px",
|
|
3772
|
+
color: theme.secondaryTextColor,
|
|
3773
|
+
marginBottom: "4px",
|
|
3774
|
+
textTransform: "uppercase"
|
|
3775
|
+
},
|
|
3776
|
+
children: isUser ? "You" : "Assistant"
|
|
3777
|
+
}
|
|
3778
|
+
),
|
|
3779
|
+
/* @__PURE__ */ jsx(
|
|
3780
|
+
"div",
|
|
3781
|
+
{
|
|
3782
|
+
style: {
|
|
3783
|
+
color: theme.textColor,
|
|
3784
|
+
whiteSpace: "pre-wrap",
|
|
3785
|
+
wordBreak: "break-word",
|
|
3786
|
+
lineHeight: 1.5
|
|
3787
|
+
},
|
|
3788
|
+
children: message.content
|
|
3789
|
+
}
|
|
3790
|
+
)
|
|
3791
|
+
]
|
|
3792
|
+
}
|
|
3793
|
+
)
|
|
3794
|
+
}
|
|
3795
|
+
);
|
|
3796
|
+
}
|
|
3797
|
+
function ApiKeyInput({
|
|
3798
|
+
theme,
|
|
3799
|
+
onSubmit
|
|
3800
|
+
}) {
|
|
3801
|
+
const [key, setKey] = useState("");
|
|
3802
|
+
const handleSubmit = (e) => {
|
|
3803
|
+
e.preventDefault();
|
|
3804
|
+
if (key.trim()) {
|
|
3805
|
+
onSubmit(key.trim());
|
|
3806
|
+
}
|
|
3807
|
+
};
|
|
3808
|
+
return /* @__PURE__ */ jsxs(
|
|
3809
|
+
"div",
|
|
3810
|
+
{
|
|
3811
|
+
style: {
|
|
3812
|
+
display: "flex",
|
|
3813
|
+
flexDirection: "column",
|
|
3814
|
+
alignItems: "center",
|
|
3815
|
+
justifyContent: "center",
|
|
3816
|
+
height: "100%",
|
|
3817
|
+
padding: "20px"
|
|
3818
|
+
},
|
|
3819
|
+
children: [
|
|
3820
|
+
/* @__PURE__ */ jsx(
|
|
3821
|
+
"div",
|
|
3822
|
+
{
|
|
3823
|
+
style: {
|
|
3824
|
+
fontSize: "14px",
|
|
3825
|
+
color: theme.textColor,
|
|
3826
|
+
marginBottom: "16px",
|
|
3827
|
+
textAlign: "center"
|
|
3828
|
+
},
|
|
3829
|
+
children: "Enter your API key to start chatting"
|
|
3830
|
+
}
|
|
3831
|
+
),
|
|
3832
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { width: "100%", maxWidth: "400px" }, children: [
|
|
3833
|
+
/* @__PURE__ */ jsx(
|
|
3834
|
+
"input",
|
|
3835
|
+
{
|
|
3836
|
+
type: "password",
|
|
3837
|
+
value: key,
|
|
3838
|
+
onChange: (e) => setKey(e.target.value),
|
|
3839
|
+
placeholder: "sk-...",
|
|
3840
|
+
style: {
|
|
3841
|
+
width: "100%",
|
|
3842
|
+
padding: "12px",
|
|
3843
|
+
backgroundColor: theme.assistantBubble,
|
|
3844
|
+
border: `1px solid ${theme.borderColor}`,
|
|
3845
|
+
borderRadius: "8px",
|
|
3846
|
+
color: theme.textColor,
|
|
3847
|
+
fontFamily: theme.fontFamily,
|
|
3848
|
+
fontSize: "14px",
|
|
3849
|
+
marginBottom: "12px"
|
|
3850
|
+
}
|
|
3851
|
+
}
|
|
3852
|
+
),
|
|
3853
|
+
/* @__PURE__ */ jsx(
|
|
3854
|
+
"button",
|
|
3855
|
+
{
|
|
3856
|
+
type: "submit",
|
|
3857
|
+
disabled: !key.trim(),
|
|
3858
|
+
style: {
|
|
3859
|
+
width: "100%",
|
|
3860
|
+
padding: "12px",
|
|
3861
|
+
backgroundColor: theme.primaryColor,
|
|
3862
|
+
border: "none",
|
|
3863
|
+
borderRadius: "8px",
|
|
3864
|
+
color: "#000",
|
|
3865
|
+
fontFamily: theme.fontFamily,
|
|
3866
|
+
fontSize: "14px",
|
|
3867
|
+
fontWeight: "bold",
|
|
3868
|
+
cursor: key.trim() ? "pointer" : "not-allowed",
|
|
3869
|
+
opacity: key.trim() ? 1 : 0.5
|
|
3870
|
+
},
|
|
3871
|
+
children: "Save & Start"
|
|
3872
|
+
}
|
|
3873
|
+
)
|
|
3874
|
+
] }),
|
|
3875
|
+
/* @__PURE__ */ jsx(
|
|
3876
|
+
"div",
|
|
3877
|
+
{
|
|
3878
|
+
style: {
|
|
3879
|
+
fontSize: "11px",
|
|
3880
|
+
color: theme.secondaryTextColor,
|
|
3881
|
+
marginTop: "16px",
|
|
3882
|
+
textAlign: "center"
|
|
3883
|
+
},
|
|
3884
|
+
children: "Your key is stored locally and never sent to our servers."
|
|
3885
|
+
}
|
|
3886
|
+
)
|
|
3887
|
+
]
|
|
3888
|
+
}
|
|
3889
|
+
);
|
|
3890
|
+
}
|
|
3891
|
+
function MindCacheChat({
|
|
3892
|
+
theme: customTheme,
|
|
3893
|
+
placeholder = "Type a message...",
|
|
3894
|
+
welcomeMessage = "Hello! I'm ready to help you.",
|
|
3895
|
+
showApiKeyInput = true,
|
|
3896
|
+
className,
|
|
3897
|
+
style,
|
|
3898
|
+
renderMessage,
|
|
3899
|
+
header,
|
|
3900
|
+
footer,
|
|
3901
|
+
initialMessages,
|
|
3902
|
+
...chatOptions
|
|
3903
|
+
}) {
|
|
3904
|
+
const context = useMindCacheContext();
|
|
3905
|
+
const theme = { ...defaultTheme, ...customTheme };
|
|
3906
|
+
const messagesEndRef = useRef(null);
|
|
3907
|
+
const inputRef = useRef(null);
|
|
3908
|
+
const [inputValue, setInputValue] = useState("");
|
|
3909
|
+
const defaultInitialMessages = welcomeMessage ? [
|
|
3910
|
+
{
|
|
3911
|
+
id: "welcome",
|
|
3912
|
+
role: "assistant",
|
|
3913
|
+
content: welcomeMessage,
|
|
3914
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3915
|
+
}
|
|
3916
|
+
] : [];
|
|
3917
|
+
const {
|
|
3918
|
+
messages,
|
|
3919
|
+
sendMessage,
|
|
3920
|
+
isLoading,
|
|
3921
|
+
error,
|
|
3922
|
+
streamingContent,
|
|
3923
|
+
stop
|
|
3924
|
+
} = useClientChat({
|
|
3925
|
+
...chatOptions,
|
|
3926
|
+
initialMessages: initialMessages || defaultInitialMessages,
|
|
3927
|
+
mindcache: context.mindcache || void 0
|
|
3928
|
+
});
|
|
3929
|
+
useEffect(() => {
|
|
3930
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
3931
|
+
}, [messages]);
|
|
3932
|
+
const handleSubmit = async (e) => {
|
|
3933
|
+
e?.preventDefault();
|
|
3934
|
+
if (!inputValue.trim() || isLoading) {
|
|
3935
|
+
return;
|
|
3936
|
+
}
|
|
3937
|
+
const message = inputValue.trim();
|
|
3938
|
+
setInputValue("");
|
|
3939
|
+
await sendMessage(message);
|
|
3940
|
+
};
|
|
3941
|
+
const handleKeyDown = (e) => {
|
|
3942
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
3943
|
+
e.preventDefault();
|
|
3944
|
+
handleSubmit();
|
|
3945
|
+
}
|
|
3946
|
+
};
|
|
3947
|
+
if (showApiKeyInput && !context.hasApiKey && context.aiConfig.keyStorage !== "memory") {
|
|
3948
|
+
return /* @__PURE__ */ jsxs(
|
|
3949
|
+
"div",
|
|
3950
|
+
{
|
|
3951
|
+
className,
|
|
3952
|
+
style: {
|
|
3953
|
+
display: "flex",
|
|
3954
|
+
flexDirection: "column",
|
|
3955
|
+
height: "100%",
|
|
3956
|
+
backgroundColor: theme.background,
|
|
3957
|
+
fontFamily: theme.fontFamily,
|
|
3958
|
+
...style
|
|
3959
|
+
},
|
|
3960
|
+
children: [
|
|
3961
|
+
header,
|
|
3962
|
+
/* @__PURE__ */ jsx(
|
|
3963
|
+
ApiKeyInput,
|
|
3964
|
+
{
|
|
3965
|
+
theme,
|
|
3966
|
+
onSubmit: (key) => context.setApiKey(key)
|
|
3967
|
+
}
|
|
3968
|
+
),
|
|
3969
|
+
footer
|
|
3970
|
+
]
|
|
3971
|
+
}
|
|
3972
|
+
);
|
|
3973
|
+
}
|
|
3974
|
+
if (!context.isLoaded) {
|
|
3975
|
+
return /* @__PURE__ */ jsx(
|
|
3976
|
+
"div",
|
|
3977
|
+
{
|
|
3978
|
+
className,
|
|
3979
|
+
style: {
|
|
3980
|
+
display: "flex",
|
|
3981
|
+
alignItems: "center",
|
|
3982
|
+
justifyContent: "center",
|
|
3983
|
+
height: "100%",
|
|
3984
|
+
backgroundColor: theme.background,
|
|
3985
|
+
color: theme.textColor,
|
|
3986
|
+
fontFamily: theme.fontFamily,
|
|
3987
|
+
...style
|
|
3988
|
+
},
|
|
3989
|
+
children: "Loading..."
|
|
3990
|
+
}
|
|
3991
|
+
);
|
|
3992
|
+
}
|
|
3993
|
+
return /* @__PURE__ */ jsxs(
|
|
3994
|
+
"div",
|
|
3995
|
+
{
|
|
3996
|
+
className,
|
|
3997
|
+
style: {
|
|
3998
|
+
display: "flex",
|
|
3999
|
+
flexDirection: "column",
|
|
4000
|
+
height: "100%",
|
|
4001
|
+
backgroundColor: theme.background,
|
|
4002
|
+
fontFamily: theme.fontFamily,
|
|
4003
|
+
...style
|
|
4004
|
+
},
|
|
4005
|
+
children: [
|
|
4006
|
+
header,
|
|
4007
|
+
/* @__PURE__ */ jsxs(
|
|
4008
|
+
"div",
|
|
4009
|
+
{
|
|
4010
|
+
style: {
|
|
4011
|
+
flex: 1,
|
|
4012
|
+
overflowY: "auto",
|
|
4013
|
+
padding: "16px"
|
|
4014
|
+
},
|
|
4015
|
+
children: [
|
|
4016
|
+
messages.map((message) => renderMessage ? /* @__PURE__ */ jsx(React2.Fragment, { children: renderMessage(message) }, message.id) : /* @__PURE__ */ jsx(DefaultMessage, { message, theme }, message.id)),
|
|
4017
|
+
streamingContent && /* @__PURE__ */ jsx(
|
|
4018
|
+
"div",
|
|
4019
|
+
{
|
|
4020
|
+
style: {
|
|
4021
|
+
display: "flex",
|
|
4022
|
+
justifyContent: "flex-start",
|
|
4023
|
+
marginBottom: "12px"
|
|
4024
|
+
},
|
|
4025
|
+
children: /* @__PURE__ */ jsxs(
|
|
4026
|
+
"div",
|
|
4027
|
+
{
|
|
4028
|
+
style: {
|
|
4029
|
+
maxWidth: "80%",
|
|
4030
|
+
padding: "12px 16px",
|
|
4031
|
+
borderRadius: "12px",
|
|
4032
|
+
backgroundColor: theme.assistantBubble,
|
|
4033
|
+
border: `1px solid ${theme.borderColor}`
|
|
4034
|
+
},
|
|
4035
|
+
children: [
|
|
4036
|
+
/* @__PURE__ */ jsx(
|
|
4037
|
+
"div",
|
|
4038
|
+
{
|
|
4039
|
+
style: {
|
|
4040
|
+
fontSize: "10px",
|
|
4041
|
+
color: theme.secondaryTextColor,
|
|
4042
|
+
marginBottom: "4px",
|
|
4043
|
+
textTransform: "uppercase"
|
|
4044
|
+
},
|
|
4045
|
+
children: "Assistant"
|
|
4046
|
+
}
|
|
4047
|
+
),
|
|
4048
|
+
/* @__PURE__ */ jsxs(
|
|
4049
|
+
"div",
|
|
4050
|
+
{
|
|
4051
|
+
style: {
|
|
4052
|
+
color: theme.textColor,
|
|
4053
|
+
whiteSpace: "pre-wrap",
|
|
4054
|
+
wordBreak: "break-word",
|
|
4055
|
+
lineHeight: 1.5
|
|
4056
|
+
},
|
|
4057
|
+
children: [
|
|
4058
|
+
streamingContent,
|
|
4059
|
+
/* @__PURE__ */ jsx("span", { style: { opacity: 0.5, animation: "blink 1s infinite" }, children: "\u258A" })
|
|
4060
|
+
]
|
|
4061
|
+
}
|
|
4062
|
+
)
|
|
4063
|
+
]
|
|
4064
|
+
}
|
|
4065
|
+
)
|
|
4066
|
+
}
|
|
4067
|
+
),
|
|
4068
|
+
isLoading && !streamingContent && /* @__PURE__ */ jsx(
|
|
4069
|
+
"div",
|
|
4070
|
+
{
|
|
4071
|
+
style: {
|
|
4072
|
+
display: "flex",
|
|
4073
|
+
justifyContent: "flex-start",
|
|
4074
|
+
marginBottom: "12px"
|
|
4075
|
+
},
|
|
4076
|
+
children: /* @__PURE__ */ jsx(
|
|
4077
|
+
"div",
|
|
4078
|
+
{
|
|
4079
|
+
style: {
|
|
4080
|
+
padding: "12px 16px",
|
|
4081
|
+
borderRadius: "12px",
|
|
4082
|
+
backgroundColor: theme.assistantBubble,
|
|
4083
|
+
border: `1px solid ${theme.borderColor}`,
|
|
4084
|
+
color: theme.secondaryTextColor
|
|
4085
|
+
},
|
|
4086
|
+
children: "Thinking..."
|
|
4087
|
+
}
|
|
4088
|
+
)
|
|
4089
|
+
}
|
|
4090
|
+
),
|
|
4091
|
+
error && /* @__PURE__ */ jsxs(
|
|
4092
|
+
"div",
|
|
4093
|
+
{
|
|
4094
|
+
style: {
|
|
4095
|
+
padding: "12px",
|
|
4096
|
+
marginBottom: "12px",
|
|
4097
|
+
borderRadius: "8px",
|
|
4098
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
4099
|
+
border: "1px solid rgba(239, 68, 68, 0.3)",
|
|
4100
|
+
color: "#ef4444",
|
|
4101
|
+
fontSize: "13px"
|
|
4102
|
+
},
|
|
4103
|
+
children: [
|
|
4104
|
+
"Error: ",
|
|
4105
|
+
error.message
|
|
4106
|
+
]
|
|
4107
|
+
}
|
|
4108
|
+
),
|
|
4109
|
+
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
4110
|
+
]
|
|
4111
|
+
}
|
|
4112
|
+
),
|
|
4113
|
+
/* @__PURE__ */ jsx(
|
|
4114
|
+
"form",
|
|
4115
|
+
{
|
|
4116
|
+
onSubmit: handleSubmit,
|
|
4117
|
+
style: {
|
|
4118
|
+
padding: "12px 16px",
|
|
4119
|
+
borderTop: `1px solid ${theme.borderColor}`
|
|
4120
|
+
},
|
|
4121
|
+
children: /* @__PURE__ */ jsxs(
|
|
4122
|
+
"div",
|
|
4123
|
+
{
|
|
4124
|
+
style: {
|
|
4125
|
+
display: "flex",
|
|
4126
|
+
gap: "8px",
|
|
4127
|
+
alignItems: "flex-end"
|
|
4128
|
+
},
|
|
4129
|
+
children: [
|
|
4130
|
+
/* @__PURE__ */ jsx(
|
|
4131
|
+
"textarea",
|
|
4132
|
+
{
|
|
4133
|
+
ref: inputRef,
|
|
4134
|
+
value: inputValue,
|
|
4135
|
+
onChange: (e) => {
|
|
4136
|
+
setInputValue(e.target.value);
|
|
4137
|
+
e.target.style.height = "auto";
|
|
4138
|
+
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
4139
|
+
},
|
|
4140
|
+
onKeyDown: handleKeyDown,
|
|
4141
|
+
placeholder: isLoading ? "Waiting for response..." : placeholder,
|
|
4142
|
+
disabled: isLoading,
|
|
4143
|
+
rows: 1,
|
|
4144
|
+
style: {
|
|
4145
|
+
flex: 1,
|
|
4146
|
+
padding: "12px",
|
|
4147
|
+
backgroundColor: theme.assistantBubble,
|
|
4148
|
+
border: `1px solid ${theme.borderColor}`,
|
|
4149
|
+
borderRadius: "8px",
|
|
4150
|
+
color: theme.textColor,
|
|
4151
|
+
fontFamily: theme.fontFamily,
|
|
4152
|
+
fontSize: "16px",
|
|
4153
|
+
// Prevents iOS zoom on focus
|
|
4154
|
+
resize: "none",
|
|
4155
|
+
minHeight: "44px",
|
|
4156
|
+
// Apple touch target minimum
|
|
4157
|
+
maxHeight: "120px",
|
|
4158
|
+
outline: "none",
|
|
4159
|
+
WebkitAppearance: "none"
|
|
4160
|
+
// Remove iOS styling
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
),
|
|
4164
|
+
isLoading ? /* @__PURE__ */ jsx(
|
|
4165
|
+
"button",
|
|
4166
|
+
{
|
|
4167
|
+
type: "button",
|
|
4168
|
+
onClick: stop,
|
|
4169
|
+
style: {
|
|
4170
|
+
padding: "12px 20px",
|
|
4171
|
+
minWidth: "44px",
|
|
4172
|
+
// Touch target
|
|
4173
|
+
minHeight: "44px",
|
|
4174
|
+
// Touch target
|
|
4175
|
+
backgroundColor: "#ef4444",
|
|
4176
|
+
border: "none",
|
|
4177
|
+
borderRadius: "8px",
|
|
4178
|
+
color: "#fff",
|
|
4179
|
+
fontFamily: theme.fontFamily,
|
|
4180
|
+
fontSize: "16px",
|
|
4181
|
+
fontWeight: "bold",
|
|
4182
|
+
cursor: "pointer",
|
|
4183
|
+
transition: "opacity 0.2s",
|
|
4184
|
+
WebkitTapHighlightColor: "transparent",
|
|
4185
|
+
touchAction: "manipulation"
|
|
4186
|
+
// Faster touch response
|
|
4187
|
+
},
|
|
4188
|
+
children: "Stop"
|
|
4189
|
+
}
|
|
4190
|
+
) : /* @__PURE__ */ jsx(
|
|
4191
|
+
"button",
|
|
4192
|
+
{
|
|
4193
|
+
type: "submit",
|
|
4194
|
+
disabled: !inputValue.trim(),
|
|
4195
|
+
style: {
|
|
4196
|
+
padding: "12px 20px",
|
|
4197
|
+
minWidth: "44px",
|
|
4198
|
+
// Touch target
|
|
4199
|
+
minHeight: "44px",
|
|
4200
|
+
// Touch target
|
|
4201
|
+
backgroundColor: theme.primaryColor,
|
|
4202
|
+
border: "none",
|
|
4203
|
+
borderRadius: "8px",
|
|
4204
|
+
color: "#000",
|
|
4205
|
+
fontFamily: theme.fontFamily,
|
|
4206
|
+
fontSize: "16px",
|
|
4207
|
+
fontWeight: "bold",
|
|
4208
|
+
cursor: !inputValue.trim() ? "not-allowed" : "pointer",
|
|
4209
|
+
opacity: !inputValue.trim() ? 0.5 : 1,
|
|
4210
|
+
transition: "opacity 0.2s",
|
|
4211
|
+
WebkitTapHighlightColor: "transparent",
|
|
4212
|
+
touchAction: "manipulation"
|
|
4213
|
+
// Faster touch response
|
|
4214
|
+
},
|
|
4215
|
+
children: "Send"
|
|
4216
|
+
}
|
|
4217
|
+
)
|
|
4218
|
+
]
|
|
4219
|
+
}
|
|
4220
|
+
)
|
|
4221
|
+
}
|
|
4222
|
+
),
|
|
4223
|
+
footer
|
|
4224
|
+
]
|
|
4225
|
+
}
|
|
4226
|
+
);
|
|
4227
|
+
}
|
|
4228
|
+
function useLocalFirstSync(options) {
|
|
4229
|
+
const {
|
|
4230
|
+
mindcache: mindcache2,
|
|
4231
|
+
gitstore,
|
|
4232
|
+
server,
|
|
4233
|
+
autoSyncInterval = 0,
|
|
4234
|
+
saveDebounceMs = 5e3,
|
|
4235
|
+
loadOnMount = true,
|
|
4236
|
+
mergeOnLoad = true
|
|
4237
|
+
} = options;
|
|
4238
|
+
const [status, setStatus] = useState("idle");
|
|
4239
|
+
const [error, setError] = useState(null);
|
|
4240
|
+
const [lastSyncAt, setLastSyncAt] = useState(null);
|
|
4241
|
+
const [hasLocalChanges, setHasLocalChanges] = useState(false);
|
|
4242
|
+
const saveTimeoutRef = useRef(null);
|
|
4243
|
+
const syncIntervalRef = useRef(null);
|
|
4244
|
+
const mountedRef = useRef(true);
|
|
4245
|
+
const getToken = useCallback(async () => {
|
|
4246
|
+
if (!gitstore) {
|
|
4247
|
+
throw new Error("GitStore not configured");
|
|
4248
|
+
}
|
|
4249
|
+
return typeof gitstore.token === "function" ? await gitstore.token() : gitstore.token;
|
|
4250
|
+
}, [gitstore]);
|
|
4251
|
+
const load = useCallback(async () => {
|
|
4252
|
+
if (!mindcache2) {
|
|
4253
|
+
return;
|
|
4254
|
+
}
|
|
4255
|
+
setStatus("loading");
|
|
4256
|
+
setError(null);
|
|
4257
|
+
try {
|
|
4258
|
+
if (gitstore) {
|
|
4259
|
+
let gitStoreModule;
|
|
4260
|
+
try {
|
|
4261
|
+
gitStoreModule = await Function('return import("@mindcache/gitstore")')();
|
|
4262
|
+
} catch {
|
|
4263
|
+
throw new Error("@mindcache/gitstore is not installed. Run: npm install @mindcache/gitstore");
|
|
4264
|
+
}
|
|
4265
|
+
const { GitStore, MindCacheSync } = gitStoreModule;
|
|
4266
|
+
const token = await getToken();
|
|
4267
|
+
const store = new GitStore({
|
|
4268
|
+
owner: gitstore.owner,
|
|
4269
|
+
repo: gitstore.repo,
|
|
4270
|
+
branch: gitstore.branch,
|
|
4271
|
+
tokenProvider: async () => token
|
|
4272
|
+
});
|
|
4273
|
+
const sync2 = new MindCacheSync(store, mindcache2, {
|
|
4274
|
+
filePath: gitstore.path || "mindcache.md"
|
|
4275
|
+
});
|
|
4276
|
+
await sync2.load({ merge: mergeOnLoad });
|
|
4277
|
+
} else if (server) {
|
|
4278
|
+
const response = await fetch(server.url, {
|
|
4279
|
+
headers: server.authToken ? { Authorization: `Bearer ${server.authToken}` } : {}
|
|
4280
|
+
});
|
|
4281
|
+
if (response.ok) {
|
|
4282
|
+
const markdown = await response.text();
|
|
4283
|
+
mindcache2.fromMarkdown(markdown, mergeOnLoad);
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
if (mountedRef.current) {
|
|
4287
|
+
setLastSyncAt(/* @__PURE__ */ new Date());
|
|
4288
|
+
setStatus("idle");
|
|
4289
|
+
}
|
|
4290
|
+
} catch (err) {
|
|
4291
|
+
if (mountedRef.current) {
|
|
4292
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
4293
|
+
setError(error2);
|
|
4294
|
+
setStatus("error");
|
|
4295
|
+
}
|
|
4296
|
+
throw err;
|
|
4297
|
+
}
|
|
4298
|
+
}, [mindcache2, gitstore, server, getToken, mergeOnLoad]);
|
|
4299
|
+
const save = useCallback(async (message) => {
|
|
4300
|
+
if (!mindcache2) {
|
|
4301
|
+
return;
|
|
4302
|
+
}
|
|
4303
|
+
setStatus("saving");
|
|
4304
|
+
setError(null);
|
|
4305
|
+
try {
|
|
4306
|
+
if (gitstore) {
|
|
4307
|
+
let gitStoreModule;
|
|
4308
|
+
try {
|
|
4309
|
+
gitStoreModule = await Function('return import("@mindcache/gitstore")')();
|
|
4310
|
+
} catch {
|
|
4311
|
+
throw new Error("@mindcache/gitstore is not installed. Run: npm install @mindcache/gitstore");
|
|
4312
|
+
}
|
|
4313
|
+
const { GitStore, MindCacheSync } = gitStoreModule;
|
|
4314
|
+
const token = await getToken();
|
|
4315
|
+
const store = new GitStore({
|
|
4316
|
+
owner: gitstore.owner,
|
|
4317
|
+
repo: gitstore.repo,
|
|
4318
|
+
branch: gitstore.branch,
|
|
4319
|
+
tokenProvider: async () => token
|
|
4320
|
+
});
|
|
4321
|
+
const sync2 = new MindCacheSync(store, mindcache2, {
|
|
4322
|
+
filePath: gitstore.path || "mindcache.md"
|
|
4323
|
+
});
|
|
4324
|
+
await sync2.save({ message: message || "MindCache sync" });
|
|
4325
|
+
} else if (server) {
|
|
4326
|
+
await fetch(server.url, {
|
|
4327
|
+
method: "POST",
|
|
4328
|
+
headers: {
|
|
4329
|
+
"Content-Type": "text/plain",
|
|
4330
|
+
...server.authToken ? { Authorization: `Bearer ${server.authToken}` } : {}
|
|
4331
|
+
},
|
|
4332
|
+
body: mindcache2.toMarkdown()
|
|
4333
|
+
});
|
|
4334
|
+
}
|
|
4335
|
+
if (mountedRef.current) {
|
|
4336
|
+
setLastSyncAt(/* @__PURE__ */ new Date());
|
|
4337
|
+
setHasLocalChanges(false);
|
|
4338
|
+
setStatus("idle");
|
|
4339
|
+
}
|
|
4340
|
+
} catch (err) {
|
|
4341
|
+
if (mountedRef.current) {
|
|
4342
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
4343
|
+
setError(error2);
|
|
4344
|
+
setStatus("error");
|
|
4345
|
+
}
|
|
4346
|
+
throw err;
|
|
4347
|
+
}
|
|
4348
|
+
}, [mindcache2, gitstore, server, getToken]);
|
|
4349
|
+
const sync = useCallback(async () => {
|
|
4350
|
+
setStatus("syncing");
|
|
4351
|
+
try {
|
|
4352
|
+
await load();
|
|
4353
|
+
if (hasLocalChanges) {
|
|
4354
|
+
await save();
|
|
4355
|
+
}
|
|
4356
|
+
} catch (err) {
|
|
4357
|
+
}
|
|
4358
|
+
}, [load, save, hasLocalChanges]);
|
|
4359
|
+
const markSaved = useCallback(() => {
|
|
4360
|
+
setHasLocalChanges(false);
|
|
4361
|
+
}, []);
|
|
4362
|
+
useEffect(() => {
|
|
4363
|
+
if (!mindcache2 || !gitstore || saveDebounceMs <= 0) {
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4366
|
+
const unsubscribe = mindcache2.subscribeToAll(() => {
|
|
4367
|
+
setHasLocalChanges(true);
|
|
4368
|
+
if (saveTimeoutRef.current) {
|
|
4369
|
+
clearTimeout(saveTimeoutRef.current);
|
|
4370
|
+
}
|
|
4371
|
+
saveTimeoutRef.current = setTimeout(() => {
|
|
4372
|
+
save("Auto-save").catch(console.error);
|
|
4373
|
+
}, saveDebounceMs);
|
|
4374
|
+
});
|
|
4375
|
+
return () => {
|
|
4376
|
+
unsubscribe();
|
|
4377
|
+
if (saveTimeoutRef.current) {
|
|
4378
|
+
clearTimeout(saveTimeoutRef.current);
|
|
4379
|
+
}
|
|
4380
|
+
};
|
|
4381
|
+
}, [mindcache2, gitstore, saveDebounceMs, save]);
|
|
4382
|
+
useEffect(() => {
|
|
4383
|
+
if (!mindcache2 || autoSyncInterval <= 0) {
|
|
4384
|
+
return;
|
|
4385
|
+
}
|
|
4386
|
+
syncIntervalRef.current = setInterval(() => {
|
|
4387
|
+
sync().catch(console.error);
|
|
4388
|
+
}, autoSyncInterval);
|
|
4389
|
+
return () => {
|
|
4390
|
+
if (syncIntervalRef.current) {
|
|
4391
|
+
clearInterval(syncIntervalRef.current);
|
|
4392
|
+
}
|
|
4393
|
+
};
|
|
4394
|
+
}, [mindcache2, autoSyncInterval, sync]);
|
|
4395
|
+
useEffect(() => {
|
|
4396
|
+
if (loadOnMount && mindcache2 && (gitstore || server)) {
|
|
4397
|
+
load().catch(console.error);
|
|
4398
|
+
}
|
|
4399
|
+
}, [mindcache2, gitstore, server, loadOnMount]);
|
|
4400
|
+
useEffect(() => {
|
|
4401
|
+
mountedRef.current = true;
|
|
4402
|
+
return () => {
|
|
4403
|
+
mountedRef.current = false;
|
|
4404
|
+
};
|
|
4405
|
+
}, []);
|
|
4406
|
+
return {
|
|
4407
|
+
status,
|
|
4408
|
+
error,
|
|
4409
|
+
lastSyncAt,
|
|
4410
|
+
hasLocalChanges,
|
|
4411
|
+
load,
|
|
4412
|
+
save,
|
|
4413
|
+
sync,
|
|
4414
|
+
markSaved
|
|
4415
|
+
};
|
|
4416
|
+
}
|
|
3408
4417
|
|
|
3409
4418
|
// src/index.ts
|
|
3410
4419
|
var mindcache = new MindCache();
|
|
3411
4420
|
|
|
3412
|
-
export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, OAuthClient, SchemaParser, SystemTagHelpers, createOAuthClient, mindcache, useMindCache };
|
|
4421
|
+
export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, MindCacheChat, MindCacheProvider, OAuthClient, SchemaParser, SystemTagHelpers, createOAuthClient, mindcache, useClientChat, useLocalFirstSync, useMindCache, useMindCacheContext };
|
|
3413
4422
|
//# sourceMappingURL=index.mjs.map
|
|
3414
4423
|
//# sourceMappingURL=index.mjs.map
|