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